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)
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)
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
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)
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)
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))
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()
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)
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 == ''
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)
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
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)
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
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)
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
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
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']