Exemplo n.º 1
0
def do_test_many(values):
    for i, v in enumerate(values):
        proof = [v]
        r = merkleroot(values, proof)
        assert check_proof(proof, r, v)
        proof = get_proof(values, v, r)
        assert check_proof(proof, r, v)
Exemplo n.º 2
0
def test_get_proof():
    values = [x * 32 for x in 'ab']
    proof_for = values[-1]
    proof = [proof_for]
    r = merkleroot(values, proof)
    # print pex(r)
    # print 'proof', proof
    assert check_proof(proof, r, proof_for)

    proof_for = values[-1]
    proof = get_proof(values, proof_for, r)
    assert check_proof(proof, r, proof_for)
Exemplo n.º 3
0
def test_get_proof():
    hash_0 = 'a' * 32
    hash_1 = 'b' * 32

    merkle_tree = [hash_0, hash_1]

    merkle_proof = get_proof(merkle_tree, hash_0)
    merkle_root = merkleroot(merkle_tree)
    assert check_proof(merkle_proof, merkle_root, hash_0)

    second_merkle_proof = get_proof(merkle_tree, hash_0, merkle_root)
    assert check_proof(second_merkle_proof, merkle_root, hash_0)
    assert merkle_proof == second_merkle_proof
Exemplo n.º 4
0
def test_basic3():
    values = [x * 32 for x in 'abc']
    proof_for = values[-1]
    proof = [proof_for]
    r = merkleroot(values, proof)
    # print pex(r)
    # print 'proof', pexl(proof)
    assert check_proof(proof, r, proof_for)
    proof_for = values[0]
    proof = [proof_for]
    r = merkleroot(values, proof)
    # print pex(r)
    # print 'proof', pexl(proof)
    assert check_proof(proof, r, proof_for)
Exemplo n.º 5
0
    def unlock(self, ctx, locked_encoded, merkleproof_encoded, secret):
        if self.settled is not None:
            raise RuntimeError('Contract is settled.')

        if self.closed is None:
            raise RuntimeError('Contract is open.')

        if ctx['msg.sender'] not in self.participants:
            raise ValueError('Unknow address.')

        partner = self.partner(ctx['msg.sender'])
        state = self.participants[partner]
        transfer = state.transfer

        # if partner haven't made a single transfer
        if transfer is None:
            return

        merkle_proof = tuple32(merkleproof_encoded)
        lock = Lock.from_bytes(locked_encoded)

        hashlock = lock.hashlock
        if hashlock != sha3(secret):
            raise ValueError('Invalid secret')

        is_valid_proof = check_proof(
            merkle_proof,
            transfer.locksroot,
            sha3(transfer.lock.as_bytes),
        )

        if not is_valid_proof:
            raise ValueError('Invalid merkle proof')

        transfer.append(lock)
Exemplo n.º 6
0
def test_many(tree_up_to=10):
    for number_of_leaves in range(tree_up_to):
        merkle_tree = [
            keccak(str(value))
            for value in range(number_of_leaves)
        ]

        for value in merkle_tree:
            merkle_proof = get_proof(merkle_tree, value)
            merkle_root = merkleroot(merkle_tree)
            second_proof = get_proof(merkle_tree, value, merkle_root)

            assert check_proof(merkle_proof, merkle_root, value) is True
            assert check_proof(second_proof, merkle_root, value) is True

        assert merkleroot(merkle_tree) == merkleroot(reversed(merkle_tree))
Exemplo n.º 7
0
def test_settlement(raiden_network, settle_timeout):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    setup_messages_cb()

    asset_manager0 = app0.raiden.managers_by_asset_address.values()[0]
    asset_manager1 = app1.raiden.managers_by_asset_address.values()[0]

    chain0 = app0.raiden.chain

    channel0 = asset_manager0.partneraddress_channel[app1.raiden.address]
    channel1 = asset_manager1.partneraddress_channel[app0.raiden.address]

    balance0 = channel0.balance
    balance1 = channel1.balance

    amount = 10
    expiration = 5
    secret = 'secret'
    hashlock = sha3(secret)

    assert app1.raiden.address in asset_manager0.partneraddress_channel
    assert asset_manager0.asset_address == asset_manager1.asset_address
    assert channel0.external_state.netting_channel.address == channel1.external_state.netting_channel.address

    transfermessage = channel0.create_lockedtransfer(amount, expiration, hashlock)
    app0.raiden.sign(transfermessage)
    channel0.register_transfer(transfermessage)
    channel1.register_transfer(transfermessage)

    assert_synched_channels(
        channel0, balance0, [transfermessage.lock],
        channel1, balance1, []
    )

    # Bob learns the secret, but Alice did not send a signed updated balance to
    # reflect this Bob wants to settle

    # get proof, that locked transfermessage was in merkle tree, with locked.root
    merkle_proof = channel1.our_state.locked.get_proof(transfermessage)
    root = channel1.our_state.locked.root
    assert check_proof(merkle_proof, root, sha3(transfermessage.lock.as_bytes))

    channel0.external_state.netting_channel.close(
        app0.raiden.address,
        transfermessage,
        None,
    )

    unlocked = [(merkle_proof, transfermessage.lock.as_bytes, secret)]

    channel0.external_state.netting_channel.unlock(
        app0.raiden.address,
        unlocked,
    )

    for _ in range(settle_timeout):
        chain0.next_block()

    channel0.external_state.netting_channel.settle()
Exemplo n.º 8
0
def test_multiple():
    "does not support repeated values"
    values = [x * 32 for x in 'abada']
    proof_for = values[-1]
    proof = [proof_for]
    with pytest.raises(AssertionError):
        r = merkleroot(values, proof)
        assert check_proof(proof, r, proof_for)
Exemplo n.º 9
0
def test_small():
    values = [x * 32 for x in 'a']
    proof_for = values[-1]
    proof = [proof_for]
    r = merkleroot(values, proof)
    assert check_proof(proof, r, proof_for)

    r = merkleroot('')
    assert r == ''
Exemplo n.º 10
0
def test_two():
    hash_0 = 'a' * 32
    hash_1 = 'b' * 32

    merkle_tree = [hash_0, hash_1]

    merkle_proof = get_proof(merkle_tree, hash_0)
    merkle_root = merkleroot(merkle_tree)

    assert merkle_proof == [hash_1]
    assert merkle_root == keccak(hash_0 + hash_1)
    assert check_proof(merkle_proof, merkle_root, hash_0)

    merkle_proof = get_proof(merkle_tree, hash_1)
    merkle_root = merkleroot(merkle_tree)

    assert merkle_proof == [hash_0]
    assert merkle_root == keccak(hash_0 + hash_1)
    assert check_proof(merkle_proof, merkle_root, hash_1)
Exemplo n.º 11
0
def test_one():
    hash_0 = 'a' * 32

    merkle_tree = [hash_0]
    merkle_proof = get_proof(merkle_tree, hash_0)
    merkle_root = merkleroot(merkle_tree)

    assert merkle_proof == []
    assert merkle_root == hash_0
    assert check_proof(merkle_proof, merkle_root, hash_0) is True
Exemplo n.º 12
0
def test_three():
    def sort_join(first, second):
        return ''.join(sorted([first, second]))

    hash_0 = 'a' * 32
    hash_1 = 'b' * 32
    hash_2 = 'c' * 32

    merkle_tree = [hash_0, hash_1, hash_2]

    hash_01 = (
        b'me\xef\x9c\xa9=5\x16\xa4\xd3\x8a\xb7\xd9\x89\xc2\xb5\x00'
        b'\xe2\xfc\x89\xcc\xdc\xf8x\xf9\xc4m\xaa\xf6\xad\r['
    )
    assert keccak(hash_0 + hash_1) == hash_01
    calculated_root = keccak(hash_2 + hash_01)

    merkle_proof = get_proof(merkle_tree, hash_0)
    merkle_root = merkleroot(merkle_tree)

    assert merkle_proof == [hash_1, hash_2]
    assert merkle_root == calculated_root
    assert check_proof(merkle_proof, merkle_root, hash_0)

    merkle_proof = get_proof(merkle_tree, hash_1)
    merkle_root = merkleroot(merkle_tree)

    assert merkle_proof == [hash_0, hash_2]
    assert merkle_root == calculated_root
    assert check_proof(merkle_proof, merkle_root, hash_1)

    merkle_proof = get_proof(merkle_tree, hash_2)
    merkle_root = merkleroot(merkle_tree)

    # with an odd number of values, the last value wont appear by itself in the
    # proof since it isn't hashed with another value
    assert merkle_proof == [keccak(hash_0 + hash_1)]
    assert merkle_root == calculated_root
    assert check_proof(merkle_proof, merkle_root, hash_2)
Exemplo n.º 13
0
def test_settlement():
    apps = create_network(num_nodes=2, num_assets=1, channels_per_node=1)
    a0, a1 = apps
    messages = setup_messages_cb(a0.transport)

    # channels
    am0 = a0.raiden.assetmanagers.values()[0]
    am1 = a1.raiden.assetmanagers.values()[0]

    assert am0.asset_address == am1.asset_address

    c0 = am0.channels[a1.raiden.address]
    c1 = am1.channels[a0.raiden.address]

    b0 = c0.balance
    b1 = c1.balance

    lr0 = c0.locked.root
    lr0p = c0.partner.locked.root
    lr1 = c1.locked.root
    lr1p = c1.partner.locked.root

    amount = 10
    secret = 'secret'
    hashlock = sha3(secret)
    target = a1.raiden.address
    expiration = 10
    assert target in am0.channels

    t = c0.create_lockedtransfer(amount, expiration, hashlock)
    c0.raiden.sign(t)
    c0.register_transfer(t)
    c1.register_transfer(t)

    # balances are unchanged, but locksroot changed

    assert b1 == c1.balance
    assert b0 == c0.balance

    assert c0.locked.root == lr0
    assert c0.partner.locked.root != lr0p

    assert c1.locked.root != lr1
    assert c1.partner.locked.root == lr1p

    assert c1.locked.root == c0.partner.locked.root

    # now Bob learns the secret, but alice did not send a signed updated balance to reflect this
    # Bob wants to settle

    sc = c0.contract
    assert sc == c1.contract

    last_sent_transfers = [t]

    # get proof, that locked transfer was in merkle tree, with locked.root
    assert c1.locked
    merkle_proof = c1.locked.get_proof(t)
    # assert merkle_proof
    # assert merkle_proof[0] == t.locked.asstring
    root = c1.locked.root
    assert check_proof(merkle_proof, root, sha3(t.lock.asstring))

    unlocked = [(merkle_proof, t.lock.asstring, secret)]

    chain = a0.raiden.chain
    chain.block_number = 1

    sc.close(a1.raiden.address, last_sent_transfers, *unlocked)
    chain.block_number += sc.locked_time

    r = sc.settle()
    assert r[c1.address] == b1 + amount
    assert r[c0.address] == b0 - amount
Exemplo n.º 14
0
def test_settlement():
    apps = create_network(num_nodes=2, num_assets=1, channels_per_node=1)
    app0, app1 = apps  # pylint: disable=unbalanced-tuple-unpacking

    setup_messages_cb()

    asset_manager0 = app0.raiden.assetmanagers.values()[0]
    asset_manager1 = app1.raiden.assetmanagers.values()[0]

    chain0 = app0.raiden.chain
    asset_address = asset_manager0.asset_address

    channel0 = asset_manager0.channels[app1.raiden.address]
    channel1 = asset_manager1.channels[app0.raiden.address]

    balance0 = channel0.balance
    balance1 = channel1.balance

    amount = 10
    expiration = 10
    secret = 'secret'
    hashlock = sha3(secret)

    assert app1.raiden.address in asset_manager0.channels
    assert asset_manager0.asset_address == asset_manager1.asset_address
    assert channel0.nettingcontract_address == channel1.nettingcontract_address

    transfermessage = channel0.create_lockedtransfer(amount, expiration, hashlock)
    app0.raiden.sign(transfermessage)
    channel0.register_transfer(transfermessage)
    channel1.register_transfer(transfermessage)

    assert_synched_channels(
        channel0, balance0, [transfermessage.lock],
        channel1, balance1, []
    )

    # Bob learns the secret, but Alice did not send a signed updated balance to
    # reflect this Bob wants to settle

    nettingcontract_address = channel0.nettingcontract_address
    last_sent_transfers = [transfermessage]

    # get proof, that locked transfermessage was in merkle tree, with locked.root
    merkle_proof = channel1.our_state.locked.get_proof(transfermessage)
    root = channel1.our_state.locked.root
    assert check_proof(merkle_proof, root, sha3(transfermessage.lock.as_bytes))

    unlocked = [(merkle_proof, transfermessage.lock, secret)]

    chain0.close(
        asset_address,
        nettingcontract_address,
        app0.raiden.address,
        last_sent_transfers,
        unlocked,
    )

    for _ in range(NettingChannelContract.locked_time):
        chain0.next_block()

    chain0.settle(asset_address, nettingcontract_address)
Exemplo n.º 15
0
def test_settlement(raiden_network, settle_timeout, reveal_timeout):
    alice_app, bob_app = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    setup_messages_cb()

    alice_graph = alice_app.raiden.token_to_channelgraph.values()[0]
    bob_graph = bob_app.raiden.token_to_channelgraph.values()[0]
    assert alice_graph.token_address == bob_graph.token_address

    alice_bob_channel = alice_graph.partneraddress_to_channel[
        bob_app.raiden.address]
    bob_alice_channel = bob_graph.partneraddress_to_channel[
        alice_app.raiden.address]

    alice_deposit = alice_bob_channel.balance
    bob_deposit = bob_alice_channel.balance

    token = alice_app.raiden.chain.token(alice_bob_channel.token_address)

    alice_balance = token.balance_of(alice_app.raiden.address)
    bob_balance = token.balance_of(bob_app.raiden.address)

    alice_chain = alice_app.raiden.chain

    alice_to_bob_amount = 10
    expiration = alice_app.raiden.chain.block_number() + reveal_timeout + 1
    secret = 'secretsecretsecretsecretsecretse'
    hashlock = sha3(secret)

    assert bob_app.raiden.address in alice_graph.partneraddress_to_channel

    nettingaddress0 = alice_bob_channel.external_state.netting_channel.address
    nettingaddress1 = bob_alice_channel.external_state.netting_channel.address
    assert nettingaddress0 == nettingaddress1

    identifier = 1
    fee = 0
    transfermessage = alice_bob_channel.create_mediatedtransfer(
        alice_app.raiden.address,
        bob_app.raiden.address,
        fee,
        alice_to_bob_amount,
        identifier,
        expiration,
        hashlock,
    )
    alice_app.raiden.sign(transfermessage)
    alice_bob_channel.register_transfer(
        alice_app.raiden.get_block_number(),
        transfermessage,
    )
    bob_alice_channel.register_transfer(
        bob_app.raiden.get_block_number(),
        transfermessage,
    )

    assert_synched_channels(
        alice_bob_channel,
        alice_deposit,
        [],
        bob_alice_channel,
        bob_deposit,
        [transfermessage.lock],
    )

    # At this point we are assuming the following:
    #
    #    A -> B MediatedTransfer
    #    B -> A SecretRequest
    #    A -> B RevealSecret
    #    - protocol didn't continue
    #
    # B knowns the secret but doesn't have an updated balance proof, B needs to
    # call settle.

    # get proof, that locked transfermessage was in merkle tree, with locked.root
    lock = bob_alice_channel.our_state.balance_proof.get_lock_by_hashlock(
        hashlock)
    assert sha3(secret) == hashlock
    unlock_proof = bob_alice_channel.our_state.balance_proof.compute_proof_for_lock(
        secret, lock)

    root = bob_alice_channel.our_state.balance_proof.merkleroot_for_unclaimed()

    assert check_proof(
        unlock_proof.merkle_proof,
        root,
        sha3(transfermessage.lock.as_bytes),
    )
    assert unlock_proof.lock_encoded == transfermessage.lock.as_bytes
    assert unlock_proof.secret == secret

    # a ChannelClose event will be generated, this will be polled by both apps
    # and each must start a task for calling settle
    balance_proof = transfermessage.to_balanceproof()
    bob_alice_channel.external_state.close(balance_proof)
    wait_until_block(alice_chain, alice_chain.block_number() + 1)

    assert alice_bob_channel.external_state.close_event.wait(timeout=15)
    assert bob_alice_channel.external_state.close_event.wait(timeout=15)

    assert alice_bob_channel.external_state.closed_block != 0
    assert bob_alice_channel.external_state.closed_block != 0
    assert alice_bob_channel.external_state.settled_block == 0
    assert bob_alice_channel.external_state.settled_block == 0

    # unlock will not be called by Channel.channel_closed because we did not
    # register the secret
    assert lock.expiration > alice_app.raiden.chain.block_number()
    assert lock.hashlock == sha3(secret)

    bob_alice_channel.external_state.netting_channel.withdraw([unlock_proof])

    settle_expiration = alice_chain.block_number() + settle_timeout + 2
    wait_until_block(alice_chain, settle_expiration)

    assert alice_bob_channel.external_state.settle_event.wait(timeout=15)
    assert bob_alice_channel.external_state.settle_event.wait(timeout=15)
    # settle must be called by the apps triggered by the ChannelClose event,
    # and the channels must update it's state based on the ChannelSettled event
    assert alice_bob_channel.external_state.settled_block != 0
    assert bob_alice_channel.external_state.settled_block != 0

    address0 = alice_app.raiden.address
    address1 = bob_app.raiden.address

    alice_netted_balance = alice_balance + alice_deposit - alice_to_bob_amount
    bob_netted_balance = bob_balance + bob_deposit + alice_to_bob_amount

    assert token.balance_of(address0) == alice_netted_balance
    assert token.balance_of(address1) == bob_netted_balance

    # Now let's query the WAL to see if the state changes were logged as expected
    state_changes = [
        change[1]
        for change in get_all_state_changes(alice_app.raiden.transaction_log)
        if not isinstance(change[1], Block)
    ]

    state_change1 = state_changes[0]
    state_change2 = state_changes[1]
    state_change3 = state_changes[2]
    state_change4 = state_changes[3]

    assert isinstance(state_change1, ContractReceiveClosed)
    assert state_change1.channel_address == nettingaddress0
    assert state_change1.closing_address == bob_app.raiden.address
    assert state_change1.block_number == alice_bob_channel.external_state.closed_block

    # Can't be sure of the order in which we encounter the SecretReveal and the withdraw
    assert_secretreveal_or_withdraw(state_change2, secret, nettingaddress0,
                                    bob_app.raiden.address)
    assert_secretreveal_or_withdraw(state_change3, secret, nettingaddress0,
                                    bob_app.raiden.address)

    assert isinstance(state_change4, ContractReceiveSettled)
    assert state_change4.channel_address == nettingaddress0
    assert state_change4.block_number == bob_alice_channel.external_state.settled_block
Exemplo n.º 16
0
def test_settlement(raiden_network, settle_timeout, reveal_timeout):
    app0, app1 = raiden_network  # pylint: disable=unbalanced-tuple-unpacking

    setup_messages_cb()

    asset_manager0 = app0.raiden.managers_by_asset_address.values()[0]
    asset_manager1 = app1.raiden.managers_by_asset_address.values()[0]

    chain0 = app0.raiden.chain

    channel0 = asset_manager0.partneraddress_channel[app1.raiden.address]
    channel1 = asset_manager1.partneraddress_channel[app0.raiden.address]

    balance0 = channel0.balance
    balance1 = channel1.balance

    amount = 10
    expiration = app0.raiden.chain.block_number() + reveal_timeout + 1
    secret = 'secret'
    hashlock = sha3(secret)

    assert app1.raiden.address in asset_manager0.partneraddress_channel
    assert asset_manager0.asset_address == asset_manager1.asset_address

    nettingaddress0 = channel0.external_state.netting_channel.address
    nettingaddress1 = channel1.external_state.netting_channel.address
    assert nettingaddress0 == nettingaddress1

    identifier = 1
    fee = 0
    transfermessage = channel0.create_mediatedtransfer(
        app0.raiden.address,
        app1.raiden.address,
        fee,
        amount,
        identifier,
        expiration,
        hashlock,
    )
    app0.raiden.sign(transfermessage)
    channel0.register_transfer(transfermessage)
    channel1.register_transfer(transfermessage)

    assert_synched_channels(
        channel0, balance0, [],
        channel1, balance1, [transfermessage.lock],
    )

    # At this point we are assuming the following:
    #
    #    A -> B MediatedTransfer
    #    B -> A SecretRequest
    #    A -> B RevealSecret
    #    - protocol didn't continue
    #
    # B knowns the secret but doesn't have an updated balance proof, B needs to
    # call settle.

    # get proof, that locked transfermessage was in merkle tree, with locked.root
    lock = channel1.our_state.balance_proof.get_lock_by_hashlock(hashlock)
    unlock_proof = channel1.our_state.balance_proof.compute_proof_for_lock(secret, lock)

    root = channel1.our_state.balance_proof.merkleroot_for_unclaimed()

    assert check_proof(
        unlock_proof.merkle_proof,
        root,
        sha3(transfermessage.lock.as_bytes),
    )
    assert unlock_proof.lock_encoded == transfermessage.lock.as_bytes
    assert unlock_proof.secret == secret

    # a ChannelClose event will be generated, this will be polled by both apps
    # and each must start a task for calling settle
    channel0.external_state.netting_channel.close(
        app0.raiden.address,
        transfermessage,
        None,
    )

    # unlock will not be called by Channel.channel_closed because we did not
    # register the secret
    channel0.external_state.netting_channel.unlock(
        app0.raiden.address,
        [unlock_proof],
    )

    settle_expiration = chain0.block_number() + settle_timeout
    wait_until_block(chain0, settle_expiration)

    # settle must be called by the apps triggered by the ChannelClose event,
    # and the channels must update it's state based on the ChannelSettled event
    assert channel0.external_state.settled_block != 0
    assert channel1.external_state.settled_block != 0
Exemplo n.º 17
0
    def close(self, ctx, sender, transfers_encoded, locked_encoded,  # noqa
              merkleproof_encoded, secret):
        """" Request the closing of the channel. Can be called multiple times.
        lock period starts with first valid call.

        Args:
            sender (address):
                The sender address.

            transfers_encoded (List[transfer]):
                A list of maximum length of 2 containing the transfer encoded
                using the fixed length format, may be empty.

            ctx:
                Block chain state used for mocking.

            locked_encoded (bin):
                The Lock to be unlocked.

            merkleproof_encoded (bin):
                A proof that the given lock is contained in the latest
                transfer. The binary data is composed of a single hash at every
                4bytes.

            secret (bin):
                The secret that unlocks the lock `hashlock = sha3(secret)`.

        Todo:
            if challenged, keep track of who provided the last valid answer,
            punish the wrongdoer here, check that participants only updates
            their own balance are counted, because they could sign something
            for the other party to blame it.
        """
        # pylint: disable=too-many-arguments,too-many-locals,too-many-branches
        # if len(transfers_encoded):
        #     raise ValueError('transfers_encoded needs at least 1 item.')

        if len(transfers_encoded) > 2:
            raise ValueError('transfers_encoded cannot have more than 2 items.')

        if self.settled:
            raise RuntimeError('contract is settled')

        # the merkleproof can be empty, if there is only one haslock
        has_oneofunlocked = locked_encoded or secret
        has_allofunlocked = locked_encoded and secret
        if has_oneofunlocked and not has_allofunlocked:
            raise ValueError(
                'all arguments `merkle_proof`, `locked`, and `secret` must be provided'
            )

        last_sent_transfers = []
        for data in transfers_encoded:
            if data[0] == DIRECTTRANSFER:
                last_sent_transfers.append(
                    DirectTransfer.decode(data)
                )
            elif data[0] == MEDIATEDTRANSFER:
                last_sent_transfers.append(
                    MediatedTransfer.decode(data)
                )
            elif data[0] == CANCELTRANSFER:
                last_sent_transfers.append(
                    CancelTransfer.decode(data)
                )
            # convinience for testing only (LockedTransfer are not exchanged between nodes)
            elif data[0] == LOCKEDTRANSFER:
                last_sent_transfers.append(
                    LockedTransfer.decode(data)
                )
            else:
                raise ValueError('invalid transfer type {}'.format(type(data[0])))

        # keep the latest claim
        for transfer in last_sent_transfers:
            if transfer.sender not in self.participants:
                raise ValueError('Invalid tansfer, sender is not a participant')

            sender_state = self.participants[transfer.sender]

            if is_newer_transfer(transfer, sender_state):
                sender_state['last_sent_transfer'] = transfer

        partner = self.partner(sender)
        partner_state = self.participants[partner]

        if last_sent_transfers:
            transfer = last_sent_transfers[-1]  # XXX: check me

        # register un-locked
        if merkleproof_encoded:
            merkle_proof = tuple32(merkleproof_encoded)
            lock = Lock.from_bytes(locked_encoded)

            hashlock = lock.hashlock
            if hashlock != sha3(secret):
                raise ValueError('invalid secret')

            # the partner might not have made a transfer
            if partner_state['last_sent_transfer'] is not None:
                assert check_proof(
                    merkle_proof,
                    partner_state['last_sent_transfer'].locksroot,
                    sha3(transfer.lock.as_bytes),
                )

            partner_state['unlocked'].append(lock)

        if self.closed is None:
            log.debug('closing contract', netcontract_address=pex(self.netcontract_address))
            self.closed = ctx['block_number']