[Legacy syntax] Getting error in Lambda Function

I am getting an error in the following contract.

import smartpy as sp

##########################################################
# Upgradable Contract that uses lambdas
# https://tezos.gitlab.io/michelson-reference/#type-lambda
##########################################################

class Upgradable(sp.Contract):
    def __init__(self, **kargs):
        self.init(**kargs)

    @sp.entrypoint
    def calc(self, data):
        self.data.value = self.data.logic(data)

    # @sp.entrypoint
    # def calc2(self):
    #     self.data.value = self.data.logic()

    @sp.entrypoint
    def updateLogic(self, logic):
        self.data.logic = logic

# Logic Version 1 (x, y)
def logic1(data):
    t = sp.TRecord(x = sp.TNat, y = sp.TNat)
    unpacked = sp.unpack(data, t).open_some(message = "Cannot UNPACK")

    sp.result(unpacked.x + unpacked.y)

# Logic Version 2 (x, y, z)
def logic2(data):
    t = sp.TRecord(x = sp.TNat, y = sp.TNat, z = sp.TNat)
    unpacked = sp.unpack(data, t).open_some(message = "Cannot UNPACK")

    sp.result(unpacked.x + unpacked.y + unpacked.z)

def logic3(self, params):
    t = sp.TRecord(data = sp.TUnit)
    unpacked = sp.unpack(params, t).open_some(message = "Cannot UNPACK")
    data = self.data.value * self.data.value
    sp.result(abs(data))

@sp.add_test(name = "Upgradable")
def test():
    scenario = sp.test_scenario()
    scenario.h1("Upgradable")

    c1 = Upgradable(value = 0, logic = sp.build_lambda(logic1))
    scenario += c1

    # Use logic version 1
    c1.calc(sp.pack(sp.record(x = 1, y = 2)))

    # Update logic to version 2
    c1.updateLogic(sp.build_lambda(logic2))

    # Use logic version 2
    c1.calc(sp.pack(sp.record(x = 1, y = 2, z = 3)))

    # Update logic to version 3
    c1.updateLogic(sp.build_lambda(logic3, with_storage="read-write", with_operations=False))

    # Use logic version 3
    # c1.calc(sp.pack(sp.unit))

The error I am getting is:

Error: entrypoint expects parameter of type sp.TLambda(sp.TBytes, sp.TNat), but got sp.TLambda(sp.TUnknown(), sp.TNat, with_storage="read-write", tstorage=TRecord++(value = sp.TInt))
Lambdas have different effects: sp.TLambda(sp.TUnknown(), sp.TNat, with_storage="read-write", tstorage=TRecord++(value = sp.TInt)) and sp.TLambda(sp.TBytes, sp.TNat)
(__main__, line 62)

You cannot store a lambda that can modify the storage inside the storage otherwise the type of the storage is recursively infinite: storage that contains a lambda that takes as a parameter the storage.

A solution is to use lazy upgradable entrypoint.

import smartpy as sp

class C(sp.Contract):
    def __init__(self):
        self.set_initial_balance(sp.tez(100))
        self.init(x = 1, y = True)

    @sp.entry_point(lazify = True)
    def modify_x(self, n):
        self.data.x = n

    @sp.entry_point(lazify = True)
    def modify_x2(self, n):
        self.data.x = 2 * n

    @sp.entry_point(lazify = False)
    def modify_x3(self, n):
        self.data.x = 3 * n

    @sp.entry_point(lazify = False)
    def update_modify_x(self, ep):
        sp.set_entry_point("modify_x", ep)

    @sp.entry_point(lazify = True, lazy_no_code = True)
    def bounce(self, p):
        sp.set_type(p, sp.TAddress)

    @sp.entry_point(lazify = False)
    def update_bounce(self, ep):
        sp.set_entry_point("bounce", ep)
        sp.send(sp.sender, sp.tez(1))

    @sp.entry_point(lazify = False)
    def take_ticket(self, p):
        sp.set_type(p, sp.TTicket(sp.TInt))

    @sp.entry_point
    def check_bounce(self):
        sp.verify(sp.has_entry_point("bounce"))

    @sp.onchain_view()
    def get_entrypoint(self, ep_id):
        sp.result(sp.entrypoint_map()[ep_id])

    @sp.onchain_view()
    def modify_x_id(self):
        sp.result(sp.entrypoint_id("modify_x"))

def ep_incr(self, params):
    self.data.x += params

def ep_decr(self, params):
    self.data.x -= params

def ep_decr_transfers(self, params):
    sp.send(sp.test_account("me").address, sp.tez(1))
    sp.send(sp.test_account("me").address, sp.tez(2))
    self.data.x -= params

def ep_bounce(self, params):
    sp.send(params, sp.mutez(2))

@sp.add_test(name = "Upgrade")
def test():
    s = sp.test_scenario()

    s.table_of_contents()

    s.h1("Upgradable and lazy entrypoints")

    alice = sp.test_account("Alice")
    bob = sp.test_account("Bob")

    c = C()
    s += c

    s.h2("Use initial entrypoint")
    c.modify_x(1)
    c.modify_x(2)
    c.modify_x(3)
    s.verify(c.data.x == 3)

    s.h1("Updating an entrypoint")

    s.h2("Switch it to incrementing")
    c.update_modify_x(sp.utils.wrap_entry_point("modify_x", ep_incr))
    c.modify_x(1)
    c.modify_x(2)
    c.modify_x(3)
    s.verify(c.data.x == 9)

    s.h2("Switch it to decrementing")
    c.update_modify_x(sp.utils.wrap_entry_point("modify_x", ep_decr))
    c.modify_x(1)
    c.modify_x(2)
    c.modify_x(3)
    s.verify(c.data.x == 3)

    s.h2("Switch it to decrementing with additional transfers")
    c.update_modify_x(sp.utils.wrap_entry_point("modify_x", ep_decr_transfers))
    c.modify_x(1)
    c.modify_x(2)
    c.modify_x(3)
    s.verify(c.data.x == -3)

    s.h1("Testing the presence of an entrypoint")

    s.h2("entrypoint is still absent (lazy_no_code)")
    c.check_bounce().run(valid = False)
    c.bounce(alice.address).run(valid = False)

    s.h2("Add entrypoint and call it")
    c.update_bounce(sp.utils.wrap_entry_point("bounce", ep_bounce)).run(sender = bob)
    c.bounce(alice.address)
    c.check_bounce()


    s.h1("Use entrypoint from another contract")

    c2 = C()
    s += c2

    s.p("Original entry point:")
    c.update_modify_x(c2.get_entrypoint(c2.modify_x_id()))
    c.modify_x(42)
    s.verify(c.data.x == 42)

    s.p("Modified entry point (obtained via view, using entrypoint):")
    c2.update_modify_x(sp.utils.wrap_entry_point("modify_x", ep_decr))
    c.update_modify_x(c2.get_entrypoint(c2.modify_x_id()))
    c.modify_x(5)
    s.verify(c.data.x == 37)

    s.p("Modified entry point (obtained via sp.contract_entrypoint):")
    c2.update_modify_x(sp.utils.wrap_entry_point("modify_x", ep_incr))
    c.update_modify_x(sp.contract_entrypoint(c2, "modify_x"))
    c.modify_x(5)
    s.verify(c.data.x == 42)

    s.p("Entrypoint map and ids")
    s.verify(c2.modify_x_id() == 1)
    s.verify(sp.contract_entrypoint_id(c, "modify_x") == 1)
    s.verify(sp.contract_entrypoint_map(c).contains(1))