def test_withdraw_tampered_lock_amount(tree, tester_channels, tester_state, tester_token, settle_timeout): """ withdraw must fail if the lock amonut is tampered. """ pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0] current_block = tester_state.block.number expiration = current_block + settle_timeout - 1 locks = [ make_lock( hashlock=hashlock, expiration=expiration, ) for hashlock in tree ] merkle_tree = Merkletree(sha3(lock.as_bytes) for lock in locks) opened_block = nettingchannel.opened(sender=pkey0) nonce = 1 + (opened_block * (2**32)) direct_transfer = make_direct_transfer( nonce=nonce, channel=channel0.channel_address, locksroot=merkle_tree.merkleroot, token=tester_token.address, recipient=privatekey_to_address(pkey1)) address = privatekey_to_address(pkey0) sign_key = PrivateKey(pkey0) direct_transfer.sign(sign_key, address) direct_transfer_hash = sha3(direct_transfer.packed().data[:-65]) nettingchannel.close( direct_transfer.nonce, direct_transfer.transferred_amount, direct_transfer.locksroot, direct_transfer_hash, direct_transfer.signature, sender=pkey1, ) for lock in locks: secret = HASHLOCKS_SECRESTS[lock.hashlock] lock_encoded = lock.as_bytes merkle_proof = merkle_tree.make_proof(sha3(lock_encoded)) tampered_lock = make_lock( amount=lock.amount * 100, hashlock=lock.hashlock, expiration=lock.expiration, ) tampered_lock_encoded = sha3(tampered_lock.as_bytes) with pytest.raises(TransactionFailed): nettingchannel.withdraw( tampered_lock_encoded, ''.join(merkle_proof), secret, sender=pkey1, )
def test_withdraw_fails_with_partial_merkle_proof(tree, tester_channels, tester_chain, settle_timeout): """ withdraw must fail if informed proof is not complete. """ pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0] current_block = tester_chain.block.number expiration = current_block + settle_timeout - 1 locks = [ make_lock( hashlock=hashlock, expiration=expiration, ) for hashlock in tree ] leaves = [sha3(lock.as_bytes) for lock in locks] layers = compute_layers(leaves) merkle_tree = MerkleTreeState(layers) opened_block = nettingchannel.opened(sender=pkey0) nonce = 1 + (opened_block * (2**32)) direct_transfer = make_direct_transfer( nonce=nonce, channel=channel0.identifier, locksroot=merkleroot(merkle_tree), recipient=privatekey_to_address(pkey1)) address = privatekey_to_address(pkey0) sign_key = PrivateKey(pkey0) direct_transfer.sign(sign_key, address) direct_transfer_hash = sha3(direct_transfer.packed().data[:-65]) nettingchannel.close( direct_transfer.nonce, direct_transfer.transferred_amount, direct_transfer.locksroot, direct_transfer_hash, direct_transfer.signature, sender=pkey1, ) for lock in locks: secret = HASHLOCKS_SECRESTS[lock.hashlock] lock_encoded = lock.as_bytes merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded)) # withdraw must fail regardless of which part of the proof is removed for hash_ in merkle_proof: tampered_proof = list(merkle_proof) tampered_proof.remove(hash_) with pytest.raises(TransactionFailed): nettingchannel.withdraw( lock_encoded, b''.join(tampered_proof), secret, sender=pkey1, )
def test_withdraw_tampered_merkle_proof(tree, tester_channels, tester_state, settle_timeout): """ withdraw must fail if the proof is tampered. """ pkey0, pkey1, nettingchannel, _, _ = tester_channels[0] current_block = tester_state.block.number expiration = current_block + settle_timeout - 1 locks = [ make_lock( hashlock=hashlock, expiration=expiration, ) for hashlock in tree ] merkle_tree = Merkletree(sha3(lock.as_bytes) for lock in locks) opened_block = nettingchannel.opened(sender=pkey0) nonce = 1 + (opened_block * (2**32)) direct_transfer = make_direct_transfer( nonce=nonce, locksroot=merkle_tree.merkleroot, recipient=privatekey_to_address(pkey1)) address = privatekey_to_address(pkey0) sign_key = PrivateKey(pkey0) direct_transfer.sign(sign_key, address) direct_transfer_data = str(direct_transfer.packed().data) nettingchannel.close(direct_transfer_data, sender=pkey1) for lock in locks: secret = HASHLOCKS_SECRESTS[lock.hashlock] lock_encoded = lock.as_bytes merkle_proof = merkle_tree.make_proof(sha3(lock_encoded)) # withdraw must fail regardless of which part of the proof is tampered for pos, hash_ in enumerate(merkle_proof): # changing arbitrary bytes from the proof tampered_hash = bytearray(hash_) tampered_hash[5], tampered_hash[6] = tampered_hash[ 6], tampered_hash[5] tampered_proof = list(merkle_proof) tampered_proof[pos] = str(tampered_hash) with pytest.raises(TransactionFailed): nettingchannel.withdraw( lock_encoded, ''.join(tampered_proof), secret, sender=pkey1, )
def test_withdraw_fails_with_partial_merkle_proof( tree, tester_channels, tester_state, settle_timeout): """ withdraw must fail if informed proof is not complete. """ pkey0, pkey1, nettingchannel, _, _ = tester_channels[0] current_block = tester_state.block.number expiration = current_block + settle_timeout - 1 locks = [ make_lock( hashlock=hashlock, expiration=expiration, ) for hashlock in tree ] merkle_tree = Merkletree(sha3(lock.as_bytes) for lock in locks) opened_block = nettingchannel.opened(sender=pkey0) nonce = 1 + (opened_block * (2 ** 32)) direct_transfer = make_direct_transfer( nonce=nonce, locksroot=merkle_tree.merkleroot, ) address = privatekey_to_address(pkey0) sign_key = PrivateKey(pkey0) direct_transfer.sign(sign_key, address) direct_transfer_data = str(direct_transfer.packed().data) nettingchannel.close(direct_transfer_data, sender=pkey1) for lock in locks: secret = HASHLOCKS_SECRESTS[lock.hashlock] lock_encoded = lock.as_bytes merkle_proof = merkle_tree.make_proof(sha3(lock_encoded)) # withdraw must fail regardless of which part of the proof is removed for hash_ in merkle_proof: tampered_proof = list(merkle_proof) tampered_proof.remove(hash_) with pytest.raises(TransactionFailed): nettingchannel.withdraw( lock_encoded, ''.join(tampered_proof), secret, sender=pkey1, )
def test_withdraw_tampered_lock_amount( tree, tester_channels, tester_chain, tester_token, settle_timeout, ): """ withdraw must fail if the lock amonut is tampered. """ pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0] current_block = tester_chain.block.number expiration = current_block + settle_timeout - 1 locks = [ make_lock( secrethash=secrethash, expiration=expiration, ) for secrethash in tree ] leaves = [sha3(lock.as_bytes) for lock in locks] layers = compute_layers(leaves) merkle_tree = MerkleTreeState(layers) opened_block = nettingchannel.opened(sender=pkey0) nonce = 1 + (opened_block * (2 ** 32)) direct_transfer = make_direct_transfer( nonce=nonce, channel=channel0.identifier, locksroot=merkleroot(merkle_tree), token=tester_token.address, recipient=privatekey_to_address(pkey1), ) address = privatekey_to_address(pkey0) sign_key = PrivateKey(pkey0) direct_transfer.sign(sign_key, address) direct_transfer_hash = sha3(direct_transfer.packed().data[:-65]) nettingchannel.close( direct_transfer.nonce, direct_transfer.transferred_amount, direct_transfer.locksroot, direct_transfer_hash, direct_transfer.signature, sender=pkey1, ) for lock in locks: secret = SECRETHASHES_SECRESTS[lock.secrethash] lock_encoded = lock.as_bytes merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded)) tampered_lock = make_lock( amount=lock.amount * 100, secrethash=lock.secrethash, expiration=lock.expiration, ) tampered_lock_encoded = sha3(tampered_lock.as_bytes) with pytest.raises(TransactionFailed): nettingchannel.withdraw( tampered_lock_encoded, b''.join(merkle_proof), secret, sender=pkey1, )
def test_withdraw_tampered_merkle_proof(tree, tester_channels, tester_chain, settle_timeout): """ withdraw must fail if the proof is tampered. """ pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0] current_block = tester_chain.block.number expiration = current_block + settle_timeout - 1 locks = [ make_lock( secrethash=secrethash, expiration=expiration, ) for secrethash in tree ] leaves = [sha3(lock.as_bytes) for lock in locks] layers = compute_layers(leaves) merkle_tree = MerkleTreeState(layers) opened_block = nettingchannel.opened(sender=pkey0) nonce = 1 + (opened_block * (2 ** 32)) direct_transfer = make_direct_transfer( nonce=nonce, channel=channel0.identifier, locksroot=merkleroot(merkle_tree), recipient=privatekey_to_address(pkey1), ) address = privatekey_to_address(pkey0) sign_key = PrivateKey(pkey0) direct_transfer.sign(sign_key, address) direct_transfer_hash = sha3(direct_transfer.packed().data[:-65]) nettingchannel.close( direct_transfer.nonce, direct_transfer.transferred_amount, direct_transfer.locksroot, direct_transfer_hash, direct_transfer.signature, sender=pkey1, ) for lock in locks: secret = SECRETHASHES_SECRESTS[lock.secrethash] lock_encoded = lock.as_bytes merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded)) # withdraw must fail regardless of which part of the proof is tampered for pos, hash_ in enumerate(merkle_proof): # changing arbitrary bytes from the proof tampered_hash = bytearray(hash_) tampered_hash[6], tampered_hash[7] = tampered_hash[7], tampered_hash[6] tampered_proof = list(merkle_proof) tampered_proof[pos] = tampered_hash joiner = b'' with pytest.raises(TransactionFailed): nettingchannel.withdraw( lock_encoded, joiner.join(tampered_proof), secret, sender=pkey1, )
def test_withdraw_tampered_lock_amount( tree, tester_channels, tester_chain, tester_token, settle_timeout): """ withdraw must fail if the lock amonut is tampered. """ pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0] current_block = tester_chain.block.number expiration = current_block + settle_timeout - 1 locks = [ make_lock( hashlock=hashlock, expiration=expiration, ) for hashlock in tree ] leaves = [sha3(lock.as_bytes) for lock in locks] layers = compute_layers(leaves) merkle_tree = MerkleTreeState(layers) opened_block = nettingchannel.opened(sender=pkey0) nonce = 1 + (opened_block * (2 ** 32)) direct_transfer = make_direct_transfer( nonce=nonce, channel=channel0.channel_address, locksroot=merkleroot(merkle_tree), token=tester_token.address, recipient=privatekey_to_address(pkey1) ) address = privatekey_to_address(pkey0) sign_key = PrivateKey(pkey0) direct_transfer.sign(sign_key, address) direct_transfer_hash = sha3(direct_transfer.packed().data[:-65]) nettingchannel.close( direct_transfer.nonce, direct_transfer.transferred_amount, direct_transfer.locksroot, direct_transfer_hash, direct_transfer.signature, sender=pkey1, ) for lock in locks: secret = HASHLOCKS_SECRESTS[lock.hashlock] lock_encoded = lock.as_bytes merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded)) tampered_lock = make_lock( amount=lock.amount * 100, hashlock=lock.hashlock, expiration=lock.expiration, ) tampered_lock_encoded = sha3(tampered_lock.as_bytes) with pytest.raises(TransactionFailed): nettingchannel.withdraw( tampered_lock_encoded, b''.join(merkle_proof), secret, sender=pkey1, )
def test_withdraw_tampered_merkle_proof(tree, tester_channels, tester_chain, settle_timeout): """ withdraw must fail if the proof is tampered. """ pkey0, pkey1, nettingchannel, channel0, _ = tester_channels[0] current_block = tester_chain.block.number expiration = current_block + settle_timeout - 1 locks = [ make_lock( hashlock=hashlock, expiration=expiration, ) for hashlock in tree ] leaves = [sha3(lock.as_bytes) for lock in locks] layers = compute_layers(leaves) merkle_tree = MerkleTreeState(layers) opened_block = nettingchannel.opened(sender=pkey0) nonce = 1 + (opened_block * (2 ** 32)) direct_transfer = make_direct_transfer( nonce=nonce, channel=channel0.channel_address, locksroot=merkleroot(merkle_tree), recipient=privatekey_to_address(pkey1) ) address = privatekey_to_address(pkey0) sign_key = PrivateKey(pkey0) direct_transfer.sign(sign_key, address) direct_transfer_hash = sha3(direct_transfer.packed().data[:-65]) nettingchannel.close( direct_transfer.nonce, direct_transfer.transferred_amount, direct_transfer.locksroot, direct_transfer_hash, direct_transfer.signature, sender=pkey1, ) for lock in locks: secret = HASHLOCKS_SECRESTS[lock.hashlock] lock_encoded = lock.as_bytes merkle_proof = compute_merkleproof_for(merkle_tree, sha3(lock_encoded)) # withdraw must fail regardless of which part of the proof is tampered for pos, hash_ in enumerate(merkle_proof): # changing arbitrary bytes from the proof tampered_hash = bytearray(hash_) tampered_hash[6], tampered_hash[7] = tampered_hash[7], tampered_hash[6] tampered_proof = list(merkle_proof) tampered_proof[pos] = tampered_hash joiner = b'' with pytest.raises(TransactionFailed): nettingchannel.withdraw( lock_encoded, joiner.join(tampered_proof), secret, sender=pkey1, )
def test_pfs_global_messages( matrix_transports, monkeypatch, ): """ Test that `update_pfs` from `RaidenEventHandler` sends balance proof updates to the global PATH_FINDING_BROADCASTING_ROOM room on Send($BalanceProof)* events, i.e. events, that send a new balance proof to the channel partner. """ transport = matrix_transports[0] transport._client.api.retry_timeout = 0 transport._send_raw = MagicMock() raiden_service = MockRaidenService(None) transport.start( raiden_service, raiden_service.message_handler, None, ) pfs_room_name = make_room_alias(transport.network_id, PATH_FINDING_BROADCASTING_ROOM) pfs_room = transport._global_rooms.get(pfs_room_name) assert isinstance(pfs_room, Room) pfs_room.send_text = MagicMock(spec=pfs_room.send_text) raiden_service.transport = transport transport.log = MagicMock() # create mock events that should trigger a send lock = make_lock() hash_time_lock = HashTimeLockState(lock.amount, lock.expiration, lock.secrethash) def make_unsigned_balance_proof(nonce): return BalanceProofUnsignedState.from_dict( make_balance_proof(nonce=nonce, signer=LocalSigner(HOP1_KEY), amount=1).to_dict(), ) transfer1 = LockedTransferUnsignedState( balance_proof=make_unsigned_balance_proof(nonce=1), payment_identifier=1, token=b'1', lock=hash_time_lock, target=HOP1, initiator=HOP1, ) transfer2 = LockedTransferUnsignedState( balance_proof=make_unsigned_balance_proof(nonce=2), payment_identifier=1, token=b'1', lock=hash_time_lock, target=HOP1, initiator=HOP1, ) send_balance_proof_events = [ SendLockedTransfer(HOP1, 1, 1, transfer1), SendRefundTransfer(HOP1, 1, 1, transfer2), SendBalanceProof(HOP1, 1, 1, 1, b'1', b'x' * 32, make_unsigned_balance_proof(nonce=3)), SendLockExpired(HOP1, 1, make_unsigned_balance_proof(nonce=4), b'x' * 32), ] for num, event in enumerate(send_balance_proof_events): assert event.balance_proof.nonce == num + 1 # make sure we cover all configured event types assert all(event in [type(event) for event in send_balance_proof_events] for event in SEND_BALANCE_PROOF_EVENTS) event_handler = raiden_event_handler.RaidenEventHandler() # let our mock objects pass validation channelstate_mock = Mock() channelstate_mock.reveal_timeout = 1 monkeypatch.setattr( raiden_event_handler, 'get_channelstate_by_token_network_and_partner', lambda *args, **kwargs: channelstate_mock, ) monkeypatch.setattr(raiden_event_handler, 'state_from_raiden', lambda *args, **kwargs: 1) monkeypatch.setattr(event_handler, 'handle_send_lockedtransfer', lambda *args, **kwargs: 1) monkeypatch.setattr(event_handler, 'handle_send_refundtransfer', lambda *args, **kwargs: 1) # handle the events for event in send_balance_proof_events: event_handler.on_raiden_event( raiden_service, event, ) gevent.idle() # ensure all events triggered a send for their respective balance_proof # matrix transport may concatenate multiple messages send in one interval assert pfs_room.send_text.call_count >= 1 concatenated_call_args = ' '.join( str(arg) for arg in pfs_room.send_text.call_args_list) assert all(f'"nonce": {i + 1}' in concatenated_call_args for i in range(len(SEND_BALANCE_PROOF_EVENTS))) transport.stop() transport.get()