def make_balance_proof_from_counter(counter) -> BalanceProofUnsignedState: return BalanceProofUnsignedState( nonce=next(counter), transferred_amount=next(counter), locked_amount=next(counter), locksroot=Locksroot(sha3(next(counter).to_bytes(1, "big"))), canonical_identifier=factories.make_canonical_identifier( chain_identifier=next(counter), token_network_address=factories.make_address(), channel_identifier=next(counter), ), )
def make_signed_balance_proof_from_counter(counter): lock = Lock( amount=next(counter), expiration=next(counter), secrethash=factories.make_secret_hash(next(counter)), ) lock_expired_balance_proof = factories.create( factories.BalanceProofSignedStateProperties( nonce=next(counter), transferred_amount=next(counter), locked_amount=next(counter), canonical_identifier=factories.make_canonical_identifier( token_network_address=factories.make_address(), channel_identifier=next(counter)), locksroot=Locksroot(sha3(lock.as_bytes)), message_hash=AdditionalHash(sha3(b"")), sender=factories.HOP1, pkey=factories.HOP1_KEY, )) return lock_expired_balance_proof
def merkleroot(merkletree: "MerkleTreeState") -> Locksroot: """ Return the root element of the merkle tree. """ assert merkletree.layers, "the merkle tree layers are empty" assert merkletree.layers[MERKLEROOT], "the root layer is empty" return Locksroot(merkletree.layers[MERKLEROOT][0])
GENESIS_BLOCK_NUMBER = BlockNumber(0) # Set at 64 since parity's default is 64 and Geth's default is 128 # TODO: Make this configurable. Since in parity this is also a configurable value STATE_PRUNING_AFTER_BLOCKS = 64 STATE_PRUNING_SAFETY_MARGIN = 8 NO_STATE_QUERY_AFTER_BLOCKS = STATE_PRUNING_AFTER_BLOCKS - STATE_PRUNING_SAFETY_MARGIN NULL_ADDRESS_BYTES = bytes(20) NULL_ADDRESS = to_checksum_address(NULL_ADDRESS_BYTES) EMPTY_HASH = BlockHash(bytes(32)) EMPTY_BALANCE_HASH = BalanceHash(bytes(32)) EMPTY_MESSAGE_HASH = AdditionalHash(bytes(32)) EMPTY_HASH_KECCAK = keccak(EMPTY_HASH) EMPTY_SIGNATURE = Signature(bytes(65)) EMPTY_MERKLE_ROOT = Locksroot(bytes(32)) EMPTY_SECRET = Secret(b"") ZERO_TOKENS = TokenAmount(0) SECRET_HEXSTRING_LENGTH = len(to_hex(EMPTY_HASH)) SECRETHASH_HEXSTRING_LENGTH = SECRET_HEXSTRING_LENGTH RECEIPT_FAILURE_CODE = 0 class EthClient(Enum): GETH = "geth" PARITY = "parity" ETH_RPC_DEFAULT_PORT = 8545
def deserialize_locksroot(data: str) -> Locksroot: return Locksroot(deserialize_bytes(data))
def test_regression_multiple_revealsecret( raiden_network: List[App], token_addresses: List[TokenAddress]) -> None: """ Multiple RevealSecret messages arriving at the same time must be handled properly. Unlock handling followed these steps: The Unlock message arrives The secret is registered The channel is updated and the correspoding lock is removed * A balance proof for the new channel state is created and sent to the payer The channel is unregistered for the given secrethash The step marked with an asterisk above introduced a context-switch. This allowed a second Reveal Unlock message to be handled before the channel was unregistered. And because the channel was already updated an exception was raised for an unknown secret. """ app0, app1 = raiden_network token = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( views.state_from_app(app0), app0.raiden.default_registry.address, token) assert token_network_address channelstate_0_1 = get_channelstate(app0, app1, token_network_address) payment_identifier = PaymentID(1) secret, secrethash = make_secret_with_hash() expiration = BlockExpiration(app0.raiden.get_block_number() + 100) lock_amount = PaymentWithFeeAmount(10) lock = Lock(amount=lock_amount, expiration=expiration, secrethash=secrethash) nonce = Nonce(1) transferred_amount = TokenAmount(0) mediated_transfer = LockedTransfer( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=nonce, token_network_address=token_network_address, token=token, channel_identifier=channelstate_0_1.identifier, transferred_amount=transferred_amount, locked_amount=LockedAmount(lock_amount), recipient=app1.raiden.address, locksroot=Locksroot(lock.lockhash), lock=lock, target=TargetAddress(app1.raiden.address), initiator=InitiatorAddress(app0.raiden.address), signature=EMPTY_SIGNATURE, metadata=Metadata(routes=[ RouteMetadata(route=[app0.raiden.address, app1.raiden.address]) ]), ) app0.raiden.sign(mediated_transfer) app1.raiden.on_messages([mediated_transfer]) reveal_secret = RevealSecret(message_identifier=make_message_identifier(), secret=secret, signature=EMPTY_SIGNATURE) app0.raiden.sign(reveal_secret) token_network_address = channelstate_0_1.token_network_address unlock = Unlock( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=payment_identifier, nonce=Nonce(mediated_transfer.nonce + 1), token_network_address=token_network_address, channel_identifier=channelstate_0_1.identifier, transferred_amount=TokenAmount(lock_amount), locked_amount=LockedAmount(0), locksroot=LOCKSROOT_OF_NO_LOCKS, secret=secret, signature=EMPTY_SIGNATURE, ) app0.raiden.sign(unlock) messages = [unlock, reveal_secret] receive_method = app1.raiden.on_messages wait = set( gevent.spawn_later(0.1, receive_method, [data]) for data in messages) gevent.joinall(wait, raise_error=True)
def test_receive_secrethashtransfer_unknown( raiden_network: List[RaidenService], token_addresses): app0 = raiden_network[0] token_address = token_addresses[0] token_network_address = views.get_token_network_address_by_token_address( views.state_from_raiden(app0), app0.default_registry.address, token_address) assert token_network_address other_key = HOP1_KEY other_signer = LocalSigner(other_key) canonical_identifier = factories.make_canonical_identifier( token_network_address=token_network_address) amount = TokenAmount(10) locksroot = Locksroot(make_32bytes()) refund_transfer_message = factories.create( factories.RefundTransferProperties( payment_identifier=PaymentID(1), nonce=Nonce(1), token=token_address, canonical_identifier=canonical_identifier, transferred_amount=amount, recipient=TargetAddress(app0.address), locksroot=locksroot, amount=amount, secret=UNIT_SECRET, )) sign_and_inject(refund_transfer_message, other_signer, app0) unlock = Unlock( chain_id=UNIT_CHAIN_ID, message_identifier=make_message_identifier(), payment_identifier=PaymentID(1), nonce=Nonce(1), channel_identifier=canonical_identifier.channel_identifier, token_network_address=token_network_address, transferred_amount=amount, locked_amount=LockedAmount(0), locksroot=locksroot, secret=UNIT_SECRET, signature=EMPTY_SIGNATURE, ) sign_and_inject(unlock, other_signer, app0) secret_request_message = SecretRequest( message_identifier=make_message_identifier(), payment_identifier=PaymentID(1), secrethash=UNIT_SECRETHASH, amount=PaymentAmount(1), expiration=refund_transfer_message.lock.expiration, signature=EMPTY_SIGNATURE, ) sign_and_inject(secret_request_message, other_signer, app0) reveal_secret_message = RevealSecret( message_identifier=make_message_identifier(), secret=UNIT_SECRET, signature=EMPTY_SIGNATURE) sign_and_inject(reveal_secret_message, other_signer, app0)
def make_locksroot() -> Locksroot: return Locksroot(make_32bytes())
STATE_PRUNING_AFTER_BLOCKS = 64 STATE_PRUNING_SAFETY_MARGIN = 8 NO_STATE_QUERY_AFTER_BLOCKS = STATE_PRUNING_AFTER_BLOCKS - STATE_PRUNING_SAFETY_MARGIN NULL_ADDRESS_BYTES = bytes(20) NULL_ADDRESS_HEX = to_hex_address(Address(NULL_ADDRESS_BYTES)) NULL_ADDRESS_CHECKSUM = to_checksum_address(Address(NULL_ADDRESS_BYTES)) EMPTY_HASH = BlockHash(bytes(32)) EMPTY_BALANCE_HASH = BalanceHash(bytes(32)) EMPTY_MESSAGE_HASH = AdditionalHash(bytes(32)) EMPTY_SIGNATURE = Signature(bytes(65)) EMPTY_SECRET = Secret(bytes(32)) EMPTY_SECRETHASH = SecretHash(bytes(32)) EMPTY_SECRET_SHA256 = sha256_secrethash(EMPTY_SECRET) LOCKSROOT_OF_NO_LOCKS = Locksroot(keccak(b"")) EMPTY_LOCKSROOT = Locksroot(bytes(32)) ZERO_TOKENS = TokenAmount(0) ABSENT_SECRET = Secret(b"") SECRET_LENGTH = 32 SECRETHASH_LENGTH = 32 RECEIPT_FAILURE_CODE = 0 class EthClient(Enum): GETH = "geth" PARITY = "parity"
STATE_PRUNING_AFTER_BLOCKS = 64 STATE_PRUNING_SAFETY_MARGIN = 8 NO_STATE_QUERY_AFTER_BLOCKS = STATE_PRUNING_AFTER_BLOCKS - STATE_PRUNING_SAFETY_MARGIN NULL_ADDRESS_BYTES = bytes(20) NULL_ADDRESS = to_checksum_address(NULL_ADDRESS_BYTES) EMPTY_HASH = BlockHash(bytes(32)) EMPTY_TRANSACTION_HASH = TransactionHash(bytes(32)) EMPTY_BALANCE_HASH = BalanceHash(bytes(32)) EMPTY_MESSAGE_HASH = AdditionalHash(bytes(32)) EMPTY_SIGNATURE = Signature(bytes(65)) EMPTY_SECRET = Secret(bytes(32)) EMPTY_SECRETHASH = SecretHash(bytes(32)) EMPTY_SECRET_SHA256 = sha256_secrethash(EMPTY_SECRET) LOCKSROOT_OF_NO_LOCKS = Locksroot(keccak(b"")) ZERO_TOKENS = TokenAmount(0) ABSENT_SECRET = Secret(b"") SECRET_LENGTH = 32 SECRETHASH_LENGTH = 32 RECEIPT_FAILURE_CODE = 0 class EthClient(Enum): GETH = "geth" PARITY = "parity"
def find_max_pending_transfers(gas_limit) -> None: """Measure gas consumption of TokenNetwork.unlock() depending on number of pending transfers and find the maximum number of pending transfers so gas_limit is not exceeded.""" tester = ContractTester(generate_keys=2) tester.deploy_contract("SecretRegistry") tester.deploy_contract( "HumanStandardToken", _initialAmount=100_000, _decimalUnits=3, _tokenName="SomeToken", _tokenSymbol="SMT", ) tester.deploy_contract( "TokenNetwork", _token_address=tester.contract_address("HumanStandardToken"), _secret_registry=tester.contract_address("SecretRegistry"), _chain_id=CHAIN_ID, _settlement_timeout_min=100, _settlement_timeout_max=200, _deprecation_executor=tester.accounts[0], _channel_participant_deposit_limit=10000, _token_network_deposit_limit=10000, ) tester.call_transaction("HumanStandardToken", "transfer", _to=tester.accounts[1], _value=10000) receipt = tester.call_transaction( "TokenNetwork", "openChannel", participant1=tester.accounts[0], participant2=tester.accounts[1], settle_timeout=150, ) channel_identifier = ChannelID( int(encode_hex(receipt["logs"][0]["topics"][1]), 16)) tester.call_transaction( "HumanStandardToken", "approve", sender=tester.accounts[0], _spender=tester.contract_address("TokenNetwork"), _value=10000, ) tester.call_transaction( "HumanStandardToken", "approve", sender=tester.accounts[1], _spender=tester.contract_address("TokenNetwork"), _value=5000, ) tester.call_transaction( "TokenNetwork", "setTotalDeposit", channel_identifier=channel_identifier, participant=tester.accounts[0], total_deposit=5000, partner=tester.accounts[1], ) tester.call_transaction( "TokenNetwork", "setTotalDeposit", channel_identifier=channel_identifier, participant=tester.accounts[1], total_deposit=2000, partner=tester.accounts[0], ) print( "Measuring unlock()'s gas cost for different Merkle tree widths, can take a while..." ) before_closing = tester.tester.take_snapshot() enough = 0 too_much = 1024 nonce = Nonce(10) additional_hash = AdditionalHash(urandom(32)) token_network_address = tester.contract_address("TokenNetwork") while enough + 1 < too_much: tree_size = (enough + too_much) // 2 tester.tester.revert_to_snapshot(before_closing) pending_transfers_tree = get_pending_transfers_tree( tester.web3, unlockable_amounts=[1] * tree_size, expired_amounts=[]) balance_hash = hash_balance_data( transferred_amount=TokenAmount(3000), locked_amount=TokenAmount(2000), locksroot=Locksroot( pending_transfers_tree.hash_of_packed_transfers), ) canonical_identifier = CanonicalIdentifier( chain_identifier=CHAIN_ID, token_network_address=token_network_address, channel_identifier=ChannelID(channel_identifier), ) data_to_sign = pack_balance_proof( nonce=Nonce(nonce), balance_hash=balance_hash, additional_hash=additional_hash, canonical_identifier=canonical_identifier, ) signature = LocalSigner(tester.private_keys[1]).sign(data=data_to_sign) tester.call_transaction( "TokenNetwork", "closeChannel", channel_identifier=channel_identifier, partner=tester.accounts[1], balance_hash=balance_hash, nonce=nonce, additional_hash=additional_hash, signature=signature, ) tester.tester.mine_blocks(160) # close settlement window tester.call_transaction( "TokenNetwork", "settleChannel", channel_identifier=channel_identifier, participant1=tester.accounts[0], participant1_transferred_amount=0, participant1_locked_amount=0, participant1_locksroot=b"\x00" * 32, participant2=tester.accounts[1], participant2_transferred_amount=3000, participant2_locked_amount=2000, participant2_locksroot=pending_transfers_tree. hash_of_packed_transfers, ) receipt = tester.call_transaction( "TokenNetwork", "unlock", channel_identifier=channel_identifier, participant=tester.accounts[0], partner=tester.accounts[1], merkle_tree_leaves=pending_transfers_tree.packed_transfers, ) gas_used = receipt["gasUsed"] if gas_used <= gas_limit: enough = tree_size print( f"{tree_size} pending transfers work ({gas_used} gas needed to unlock)" ) else: too_much = tree_size print( f"{tree_size} pending transfers are too much ({gas_used} gas needed to unlock)" )
def merkleroot(merkletree: 'MerkleTreeState') -> Locksroot: """ Return the root element of the merkle tree. """ assert merkletree.layers, 'the merkle tree layers are empty' assert merkletree.layers[MERKLEROOT], 'the root layer is empty' return Locksroot(merkletree.layers[MERKLEROOT][0])
def test_pfs_send_unique_capacity_and_fee_updates_during_mediated_transfer( raiden_network): """ Tests that PFSCapacityUpdates and PFSFeeUpdates are being sent only once with the most recent state change in a batch. """ app0, app1 = raiden_network chain_state = views.state_from_app(app0) # There have been two PFSCapacityUpdates and two PFSFeeUpdates per channel per node assert len(get_messages(app0)) == 4 # The mediator has two channels assert len(get_messages(app1)) == 4 # Now we create two state_changes (Deposit) regarding the same channel # and trigger handle_state_changes() of node0. The expected outcome # is that only 1 PFSCapacityUpdate and 1 PFSFeeUpdate is being sent # not one per state change pfs_fee_update_1_of_app0 = get_messages(app0)[1] assert isinstance(pfs_fee_update_1_of_app0, PFSFeeUpdate) pfs_capacity_update_2_of_app0 = get_messages(app0)[2] assert isinstance(pfs_capacity_update_2_of_app0, PFSCapacityUpdate) canonical_identifier = pfs_fee_update_1_of_app0.canonical_identifier new_total_deposit_1 = pfs_capacity_update_2_of_app0.other_capacity * 2 deposit_transaction_1 = TransactionChannelDeposit( app1.raiden.address, TokenAmount(new_total_deposit_1), chain_state.block_number) channel_deposit_1 = ContractReceiveChannelDeposit( transaction_hash=make_transaction_hash(), canonical_identifier=canonical_identifier, deposit_transaction=deposit_transaction_1, block_number=chain_state.block_number, block_hash=chain_state.block_hash, fee_config=MediationFeeConfig(), ) new_total_deposit_2 = new_total_deposit_1 * 2 deposit_transaction_2 = TransactionChannelDeposit( app1.raiden.address, TokenAmount(new_total_deposit_2), chain_state.block_number) channel_deposit_2 = ContractReceiveChannelDeposit( transaction_hash=make_transaction_hash(), canonical_identifier=canonical_identifier, deposit_transaction=deposit_transaction_2, block_number=chain_state.block_number, block_hash=chain_state.block_hash, fee_config=MediationFeeConfig(), ) state_changes = [channel_deposit_1, channel_deposit_2] app0.raiden.handle_state_changes(state_changes=state_changes) # Now we should see that app0 send 2 new messages, # one PFSCapacityUpdate and one PFSFeeUpdate with # the updated amount of the initial amount * 4 # so sending should only be triggered by the second state change pfs_capacity_update_3_of_app0 = get_messages(app0)[4] assert isinstance(pfs_capacity_update_3_of_app0, PFSCapacityUpdate) assert len(get_messages(app0)) == 6 assert (pfs_capacity_update_3_of_app0.other_capacity == pfs_capacity_update_2_of_app0.updating_capacity * 4) # Now we want to test if this also works with a state_change # that triggers only a PFSCapacityUpdate and no PFSFeeUpdate. # So at the end we expect 1 more PFSCapacityUpdate in the room. lock_secret_1 = keccak(b"test_end_state") unlock_message_1 = Unlock( chain_id=chain_state.chain_id, message_identifier=MessageID(123132), payment_identifier=PaymentID(1), nonce=Nonce(2), token_network_address=canonical_identifier.token_network_address, channel_identifier=canonical_identifier.channel_identifier, transferred_amount=TokenAmount(400), locked_amount=LockedAmount(0), locksroot=Locksroot(keccak(b"")), secret=Secret(lock_secret_1), signature=Signature(bytes(65)), ) unlock_message_1.sign(app1.raiden.signer) balance_proof_1 = balanceproof_from_envelope(unlock_message_1) unlock_1 = ReceiveUnlock( message_identifier=MessageID(5135), secret=Secret(lock_secret_1), balance_proof=balance_proof_1, sender=balance_proof_1.sender, ) lock_secret_2 = keccak(b"test_end_state_again") unlock_message_2 = Unlock( chain_id=chain_state.chain_id, message_identifier=MessageID(223132), payment_identifier=PaymentID(2), nonce=Nonce(2), token_network_address=canonical_identifier.token_network_address, channel_identifier=canonical_identifier.channel_identifier, transferred_amount=TokenAmount(500), locked_amount=LockedAmount(0), locksroot=Locksroot(keccak(b"")), secret=Secret(lock_secret_2), signature=Signature(bytes(65)), ) unlock_message_2.sign(app1.raiden.signer) balance_proof_2 = balanceproof_from_envelope(unlock_message_2) unlock_2 = ReceiveUnlock( message_identifier=MessageID(5135), secret=Secret(lock_secret_2), balance_proof=balance_proof_2, sender=balance_proof_2.sender, ) state_changes_2 = [unlock_1, unlock_2] app0.raiden.handle_state_changes(state_changes=state_changes_2) assert len(get_messages(app0)) == 7 assert len([ x for x in get_messages(app0) if isinstance(x, PFSCapacityUpdate) ]) == 4