def wait_for_sync_etherscan( rpc_client: JSONRPCClient, url: str, tolerance: int, sleep: float ) -> None: local_block = rpc_client.block_number() etherscan_block = etherscan_query_with_retries(url, sleep) syncing_str = "\rSyncing ... Current: {} / Target: ~{}" if local_block >= etherscan_block - tolerance: return print("Waiting for the ethereum node to synchronize. [Use ^C to exit]") print(syncing_str.format(local_block, etherscan_block), end="") for i in count(): sys.stdout.flush() gevent.sleep(sleep) local_block = rpc_client.block_number() # update the oracle block number sparsely to not spam the server if local_block >= etherscan_block or i % 50 == 0: etherscan_block = etherscan_query_with_retries(url, sleep) if local_block >= etherscan_block - tolerance: return print(syncing_str.format(local_block, etherscan_block), end="") # add a newline so that the next print will start have it's own line print("")
def blocks_to_sync(rpc_client: JSONRPCClient) -> BlockTimeout: sync_status = rpc_client.web3.eth.syncing if sync_status is False: return BlockTimeout(0) assert isinstance(sync_status, Mapping), MYPY_ANNOTATION highest_block = sync_status["highestBlock"] current_block = rpc_client.block_number() return BlockTimeout(highest_block - current_block)
def wait_for_sync_blockcypher( rpc_client: JSONRPCClient, tolerance: BlockTimeout, sleep: float ) -> None: syncing_str = "\rSyncing ... Current: {} / Target: ~{}" error_str = "Could not get blockchain information from blockcypher. Ignoring." local_block = rpc_client.block_number() blockcypher_block = blockcypher_query_with_retries(sleep) if blockcypher_block is None: print(error_str) return if local_block >= blockcypher_block - tolerance: return print("Waiting for the ethereum node to synchronize. [Use ^C to exit]") print(syncing_str.format(local_block, blockcypher_block), end="") for i in count(): sys.stdout.flush() gevent.sleep(sleep) local_block = rpc_client.block_number() # update the oracle block number sparsely to not spam the server if local_block >= blockcypher_block or i % 50 == 0: blockcypher_block = blockcypher_query_with_retries(sleep) if blockcypher_block is None: print(error_str) return if local_block >= blockcypher_block - tolerance: return print(syncing_str.format(local_block, blockcypher_block), end="") # add a newline so that the next print will start have it's own line print("")
def is_synced(rpc_client: JSONRPCClient) -> bool: sync_status = rpc_client.web3.eth.syncing # the node is synchronized if sync_status is False: return True assert isinstance(sync_status, Mapping), MYPY_ANNOTATION highest_block = sync_status["highestBlock"] current_block = rpc_client.block_number() if highest_block - current_block > tolerance: return False return True
def test_register_secret_batch_with_pruned_block( proxy_manager: ProxyManager, secret_registry_proxy: SecretRegistry, web3: Web3, private_keys: List[PrivateKey], ) -> None: """Test secret registration with a pruned given block.""" rpc_client = JSONRPCClient(web3, private_keys[1]) # Now wait until this block becomes pruned pruned_number = rpc_client.block_number() rpc_client.wait_until_block( target_block_number=BlockNumber(pruned_number + STATE_PRUNING_AFTER_BLOCKS) ) secret_registry_batch_happy_path(proxy_manager, secret_registry_proxy)
def check_ethereum_confirmed_block_is_not_pruned( jsonrpc_client: JSONRPCClient, secret_registry: SecretRegistry, confirmation_blocks: int ) -> None: """Checks the Ethereum client is not pruning data too aggressively, because in some circunstances it is necessary for a node to fetch additional data from the smart contract. """ unconfirmed_block_number = jsonrpc_client.block_number() # This is a small error margin. It is possible during normal operation for: # # - AlarmTask sees a new block and calls RaidenService._callback_new_block # - The service gets the current latest block number and computes the # confirmed block number. # - The service fetches every filter, this can take a while. # - While the above is happening, it is possible for a `few_blocks` to be # mined. # - The decode function is called, and tries to access what it thinks is # the latest_confirmed_block, but it is in reality `few_blocks` older. # # This value bellow is the expected drift, that allows the decode function # mentioned above to work properly. maximum_delay_to_process_a_block = 2 minimum_available_history = confirmation_blocks + maximum_delay_to_process_a_block target_confirmed_block = unconfirmed_block_number - minimum_available_history try: # Using the secret registry is arbitrary, any proxy with an `eth_call` # would work here. secret_registry.get_secret_registration_block_by_secrethash( EMPTY_SECRETHASH, block_identifier=target_confirmed_block ) except ValueError: # If this exception is raised the Ethereum node is too aggressive with # the block pruning. click.secho( f"The ethereum client does not have the necessary data available. " f"The client can not operate because the prunning strategy is too " f"agressive. Please make sure that at very minimum " f"{minimum_available_history} blocks of history are available.", fg="red", ) sys.exit(1)
def estimate_blocktime(rpc_client: JSONRPCClient, oldest: int = 256) -> float: """Calculate a blocktime estimate based on some past blocks. Args: oldest: delta in block numbers to go back. Return: average block time in seconds """ last_block_number = rpc_client.block_number() # around genesis block there is nothing to estimate if last_block_number < 1: return 15 # if there are less than `oldest` blocks available, start at block 1 if last_block_number < oldest: interval = (last_block_number - 1) or 1 else: interval = last_block_number - oldest assert interval > 0 last_timestamp = rpc_client.get_block(last_block_number)["timestamp"] first_timestamp = rpc_client.get_block(last_block_number - interval)["timestamp"] delta = last_timestamp - first_timestamp return delta / interval
def main(output_directory, network_id, eth_rpc_endpoint, contracts_version): web3 = Web3(HTTPProvider(rpc_normalized_endpoint(eth_rpc_endpoint))) try: check_ethereum_client_is_supported(web3) except ConnectionError: click.secho( f"Couldn't connect to the ethereum node, double check it is running " f"on {eth_rpc_endpoint}, this option can be changed with " f"{ETH_RPC_CONFIG_OPTION}", fg="red", ) return check_ethereum_network_id(network_id, web3) # This script does not send any transactions, the privatekey is generate # just because it is a dependency for JSONRPCClient. unecessary_privatekey = factories.make_privatekey_bin() rpc_client = JSONRPCClient(web3=web3, privkey=unecessary_privatekey) check_synced(rpc_client) deployment_data = get_contracts_deployment_info(chain_id=network_id, version=contracts_version) if not deployment_data: raise RuntimeError( f"There is no deployment data available for contracts-version {contracts_version}." ) network_name = ID_TO_CHAINNAME.get(network_id) if network_name is None: raise RuntimeError(f"Network with id {network_id} is not known.") contracts = deployment_data["contracts"] token_network_registry_deployed_at = BlockNumber( contracts[CONTRACT_TOKEN_NETWORK_REGISTRY]["block_number"] ) token_network_registry_address = TokenNetworkRegistryAddress( to_canonical_address(contracts[CONTRACT_TOKEN_NETWORK_REGISTRY]["address"]) ) secret_registry_address = SecretRegistryAddress( to_canonical_address(contracts[CONTRACT_SECRET_REGISTRY]["address"]) ) contracts_path = contracts_precompiled_path(contracts_version) contract_manager = ContractManager(contracts_path) current_block_number = rpc_client.block_number() confirmed_block = rpc_client.get_block( BlockNumber(current_block_number - DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS) ) all_events_for_a_deployment = fetch_all_events_for_a_deployment( contract_manager=contract_manager, web3=web3, token_network_registry_address=token_network_registry_address, secret_registry_address=secret_registry_address, start_block=token_network_registry_deployed_at, target_block=confirmed_block["number"], ) target_block_formatted = to_hex(confirmed_block["hash"]) file_path = os.path.join( output_directory, ( f"{network_name}-" f"{to_checksum_address(token_network_registry_address)}-" f"{target_block_formatted}.json.gz" ), ) block_data = { "gasLimit": confirmed_block["gasLimit"], "gasUsed": confirmed_block["gasUsed"], "hash": to_hex(confirmed_block["hash"]), "number": confirmed_block["number"], } block_data_formatted = simplejson.dumps(block_data).encode("utf8") with gzip.open(file_path, mode="wb") as handler: # Format is `jsonlines` (http://jsonlines.org/), this is used because we # don't have to keep all the events in memory to start encoding the data. for event in all_events_for_a_deployment: format_event_for_serialization(event) data = simplejson.dumps(event).encode("utf8") handler.write(data + b"\n") # Write the block details at the end handler.write(block_data_formatted + b"\n")
def test_payment_channel_proxy_basics( token_network_registry_address: TokenNetworkRegistryAddress, token_network_proxy: TokenNetwork, token_proxy: Token, chain_id: ChainID, private_keys: List[PrivateKey], web3: Web3, contract_manager: ContractManager, reveal_timeout: BlockTimeout, ) -> None: token_network_address = token_network_proxy.address partner = privatekey_to_address(private_keys[0]) rpc_client = JSONRPCClient(web3, private_keys[1]) proxy_manager = ProxyManager( rpc_client=rpc_client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) token_network_proxy = proxy_manager.token_network( address=token_network_address, block_identifier=BLOCK_ID_LATEST ) start_block = web3.eth.blockNumber channel_details = token_network_proxy.new_netting_channel( partner=partner, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier=BLOCK_ID_LATEST, ) channel_identifier = channel_details.channel_identifier assert channel_identifier is not None channel_state = NettingChannelState( canonical_identifier=CanonicalIdentifier( chain_identifier=chain_id, token_network_address=token_network_address, channel_identifier=channel_identifier, ), token_address=token_network_proxy.token_address(), token_network_registry_address=token_network_registry_address, reveal_timeout=reveal_timeout, settle_timeout=BlockTimeout(TEST_SETTLE_TIMEOUT_MIN), fee_schedule=FeeScheduleState(), our_state=NettingChannelEndState( address=token_network_proxy.client.address, contract_balance=Balance(0) ), partner_state=NettingChannelEndState(address=partner, contract_balance=Balance(0)), open_transaction=SuccessfulTransactionState(finished_block_number=BlockNumber(0)), ) channel_proxy_1 = proxy_manager.payment_channel( channel_state=channel_state, block_identifier=BLOCK_ID_LATEST ) assert channel_proxy_1.channel_identifier == channel_identifier assert channel_proxy_1.opened(BLOCK_ID_LATEST) is True # Test deposit initial_token_balance = 100 token_proxy.transfer(rpc_client.address, TokenAmount(initial_token_balance)) assert token_proxy.balance_of(rpc_client.address) == initial_token_balance assert token_proxy.balance_of(partner) == 0 channel_proxy_1.approve_and_set_total_deposit( total_deposit=TokenAmount(10), block_identifier=BLOCK_ID_LATEST ) # ChannelOpened, ChannelNewDeposit channel_events = get_all_netting_channel_events( proxy_manager=proxy_manager, token_network_address=token_network_address, netting_channel_identifier=channel_proxy_1.channel_identifier, contract_manager=contract_manager, from_block=start_block, to_block=web3.eth.blockNumber, ) assert len(channel_events) == 2 block_before_close = web3.eth.blockNumber empty_balance_proof = BalanceProof( channel_identifier=channel_proxy_1.channel_identifier, token_network_address=token_network_address, balance_hash=EMPTY_BALANCE_HASH, nonce=0, chain_id=chain_id, transferred_amount=TokenAmount(0), ) closing_data = ( empty_balance_proof.serialize_bin(msg_type=MessageTypeId.BALANCE_PROOF) + EMPTY_SIGNATURE ) channel_proxy_1.close( nonce=Nonce(0), balance_hash=EMPTY_BALANCE_HASH, additional_hash=EMPTY_MESSAGE_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data), block_identifier=BLOCK_ID_LATEST, ) assert channel_proxy_1.closed(BLOCK_ID_LATEST) is True # ChannelOpened, ChannelNewDeposit, ChannelClosed channel_events = get_all_netting_channel_events( proxy_manager=proxy_manager, token_network_address=token_network_address, netting_channel_identifier=channel_proxy_1.channel_identifier, contract_manager=contract_manager, from_block=start_block, to_block=web3.eth.blockNumber, ) assert len(channel_events) == 3 # check the settlement timeouts again assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN # update transfer -- we need to wait on +1 since we use the latest block on parity for # estimate gas and at the time the latest block is the settle timeout block. # More info: https://github.com/raiden-network/raiden/pull/3699#discussion_r270477227 rpc_client.wait_until_block( target_block_number=BlockNumber(rpc_client.block_number() + TEST_SETTLE_TIMEOUT_MIN + 1) ) transaction_hash = channel_proxy_1.settle( transferred_amount=TokenAmount(0), locked_amount=LockedAmount(0), locksroot=LOCKSROOT_OF_NO_LOCKS, partner_transferred_amount=TokenAmount(0), partner_locked_amount=LockedAmount(0), partner_locksroot=LOCKSROOT_OF_NO_LOCKS, block_identifier=BLOCK_ID_LATEST, ) assert is_tx_hash_bytes(transaction_hash) assert channel_proxy_1.settled(BLOCK_ID_LATEST) is True # ChannelOpened, ChannelNewDeposit, ChannelClosed, ChannelSettled channel_events = get_all_netting_channel_events( proxy_manager=proxy_manager, token_network_address=token_network_address, netting_channel_identifier=channel_proxy_1.channel_identifier, contract_manager=contract_manager, from_block=start_block, to_block=web3.eth.blockNumber, ) assert len(channel_events) == 4 channel_details = token_network_proxy.new_netting_channel( partner=partner, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier=BLOCK_ID_LATEST, ) new_channel_identifier = channel_details.channel_identifier assert new_channel_identifier is not None channel_state = NettingChannelState( canonical_identifier=CanonicalIdentifier( chain_identifier=chain_id, token_network_address=token_network_address, channel_identifier=new_channel_identifier, ), token_address=token_network_proxy.token_address(), token_network_registry_address=token_network_registry_address, reveal_timeout=reveal_timeout, settle_timeout=BlockTimeout(TEST_SETTLE_TIMEOUT_MIN), fee_schedule=FeeScheduleState(), our_state=NettingChannelEndState( address=token_network_proxy.client.address, contract_balance=Balance(0) ), partner_state=NettingChannelEndState(address=partner, contract_balance=Balance(0)), open_transaction=SuccessfulTransactionState(finished_block_number=BlockNumber(0)), ) channel_proxy_2 = proxy_manager.payment_channel( channel_state=channel_state, block_identifier=BLOCK_ID_LATEST ) assert channel_proxy_2.channel_identifier == new_channel_identifier assert channel_proxy_2.opened(BLOCK_ID_LATEST) is True msg = "The channel was already closed, the second call must fail" with pytest.raises(RaidenRecoverableError): channel_proxy_1.close( nonce=Nonce(0), balance_hash=EMPTY_BALANCE_HASH, additional_hash=EMPTY_MESSAGE_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data), block_identifier=block_before_close, ) pytest.fail(msg) msg = "The channel is not open at latest, this must raise" with pytest.raises(RaidenUnrecoverableError): channel_proxy_1.close( nonce=Nonce(0), balance_hash=EMPTY_BALANCE_HASH, additional_hash=EMPTY_MESSAGE_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data), block_identifier=BLOCK_ID_LATEST, ) pytest.fail(msg) msg = ( "The channel was not opened at the provided block (latest). " "This call should never have been attempted." ) with pytest.raises(BrokenPreconditionError): channel_proxy_1.approve_and_set_total_deposit( total_deposit=TokenAmount(20), block_identifier=BLOCK_ID_LATEST ) pytest.fail(msg)
def test_payment_channel_proxy_basics( token_network_proxy, token_proxy, chain_id, private_keys, web3, contract_manager ): token_network_address = token_network_proxy.address partner = privatekey_to_address(private_keys[0]) client = JSONRPCClient(web3, private_keys[1]) chain = BlockChainService(jsonrpc_client=client, contract_manager=contract_manager) token_network_proxy = chain.token_network(address=token_network_address) start_block = web3.eth.blockNumber channel_identifier = token_network_proxy.new_netting_channel( partner=partner, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest" ) assert channel_identifier is not None channel_proxy_1 = chain.payment_channel( canonical_identifier=CanonicalIdentifier( chain_identifier=chain_id, token_network_address=token_network_address, channel_identifier=channel_identifier, ) ) channel_filter = channel_proxy_1.all_events_filter(from_block=start_block, to_block="latest") assert channel_proxy_1.channel_identifier == channel_identifier assert channel_proxy_1.opened("latest") is True # Test deposit initial_token_balance = 100 token_proxy.transfer(client.address, initial_token_balance) assert token_proxy.balance_of(client.address) == initial_token_balance assert token_proxy.balance_of(partner) == 0 channel_proxy_1.set_total_deposit(total_deposit=10, block_identifier="latest") assert len(channel_filter.get_all_entries()) == 2 # ChannelOpened, ChannelNewDeposit block_before_close = web3.eth.blockNumber channel_proxy_1.close( nonce=0, balance_hash=EMPTY_HASH, additional_hash=EMPTY_HASH, signature=EMPTY_SIGNATURE, block_identifier="latest", ) assert channel_proxy_1.closed("latest") is True # ChannelOpened, ChannelNewDeposit, ChannelClosed assert len(channel_filter.get_all_entries()) == 3 # check the settlement timeouts again assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN # update transfer -- we need to wait on +1 since we use the latest block on parity for # estimate gas and at the time the latest block is the settle timeout block. # More info: https://github.com/raiden-network/raiden/pull/3699#discussion_r270477227 chain.wait_until_block(target_block_number=client.block_number() + TEST_SETTLE_TIMEOUT_MIN + 1) channel_proxy_1.settle( transferred_amount=0, locked_amount=0, locksroot=EMPTY_HASH, partner_transferred_amount=0, partner_locked_amount=0, partner_locksroot=EMPTY_HASH, block_identifier="latest", ) assert channel_proxy_1.settled("latest") is True # ChannelOpened, ChannelNewDeposit, ChannelClosed, ChannelSettled assert len(channel_filter.get_all_entries()) == 4 new_channel_identifier = token_network_proxy.new_netting_channel( partner=partner, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest" ) assert new_channel_identifier is not None channel_proxy_2 = chain.payment_channel( canonical_identifier=CanonicalIdentifier( chain_identifier=chain_id, token_network_address=token_network_address, channel_identifier=new_channel_identifier, ) ) assert channel_proxy_2.channel_identifier == new_channel_identifier assert channel_proxy_2.opened("latest") is True msg = "The channel was already closed, the second call must fail" with pytest.raises(RaidenRecoverableError, message=msg): channel_proxy_1.close( nonce=0, balance_hash=EMPTY_HASH, additional_hash=EMPTY_HASH, signature=EMPTY_SIGNATURE, block_identifier=block_before_close, ) msg = "The channel is not open at latest, this must raise" with pytest.raises(RaidenUnrecoverableError, message=msg): channel_proxy_1.close( nonce=0, balance_hash=EMPTY_HASH, additional_hash=EMPTY_HASH, signature=EMPTY_SIGNATURE, block_identifier="latest", ) msg = "The channel is closed, set total deposit must fail" with pytest.raises(ChannelOutdatedError, message=msg): channel_proxy_1.set_total_deposit(total_deposit=20, block_identifier="latest")
def test_token_network_proxy(token_network_proxy, private_keys, token_proxy, chain_id, web3, contract_manager): assert token_network_proxy.settlement_timeout_min( ) == TEST_SETTLE_TIMEOUT_MIN assert token_network_proxy.settlement_timeout_max( ) == TEST_SETTLE_TIMEOUT_MAX token_network_address = to_canonical_address( token_network_proxy.proxy.contract.address) c1_signer = LocalSigner(private_keys[1]) c1_client = JSONRPCClient(web3, private_keys[1]) c1_proxy_manager = ProxyManager( rpc_client=c1_client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) c2_client = JSONRPCClient(web3, private_keys[2]) c2_proxy_manager = ProxyManager( rpc_client=c2_client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) c2_signer = LocalSigner(private_keys[2]) c1_token_network_proxy = c1_proxy_manager.token_network( token_network_address) c2_token_network_proxy = c2_proxy_manager.token_network( token_network_address) initial_token_balance = 100 token_proxy.transfer(c1_client.address, initial_token_balance) token_proxy.transfer(c2_client.address, initial_token_balance) initial_balance_c1 = token_proxy.balance_of(c1_client.address) assert initial_balance_c1 == initial_token_balance initial_balance_c2 = token_proxy.balance_of(c2_client.address) assert initial_balance_c2 == initial_token_balance # instantiating a new channel - test basic assumptions assert (c1_token_network_proxy.get_channel_identifier_or_none( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", ) is None) msg = "Hex encoded addresses are not supported, an assertion must be raised" with pytest.raises(AssertionError): c1_token_network_proxy.get_channel_identifier( participant1=to_checksum_address(c1_client.address), participant2=to_checksum_address(c2_client.address), block_identifier="latest", ) pytest.fail(msg) msg = "Zero is not a valid channel_identifier identifier, an exception must be raised." with pytest.raises(InvalidChannelID): assert c1_token_network_proxy.channel_is_opened( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", channel_identifier=0, ) pytest.fail(msg) msg = "Zero is not a valid channel_identifier identifier. an exception must be raised." with pytest.raises(InvalidChannelID): assert c1_token_network_proxy.channel_is_closed( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", channel_identifier=0, ) pytest.fail(msg) msg = ("Opening a channel with a settle_timeout lower then token " "network's minimum will fail. This must be validated and the " "transaction must not be sent.") with pytest.raises(InvalidSettleTimeout): c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN - 1, given_block_identifier="latest", ) pytest.fail(msg) # Using exactly the minimal timeout must succeed c1_token_network_proxy.new_netting_channel( partner=make_address(), settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest", ) msg = ("Opening a channel with a settle_timeout larger then token " "network's maximum will fail. This must be validated and the " "transaction must not be sent.") with pytest.raises(InvalidSettleTimeout): c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MAX + 1, given_block_identifier="latest", ) pytest.fail(msg) # Using exactly the maximal timeout must succeed c1_token_network_proxy.new_netting_channel( partner=make_address(), settle_timeout=TEST_SETTLE_TIMEOUT_MAX, given_block_identifier="latest", ) msg = ( "Opening a channel with itself is not allow. This must be validated and " "the transaction must not be sent.") with pytest.raises(SamePeerAddress): c1_token_network_proxy.new_netting_channel( partner=c1_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest", ) pytest.fail(msg) msg = "Trying a deposit to an inexisting channel must fail." with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=100, total_deposit=1, partner=c2_client.address, ) pytest.fail(msg) empty_balance_proof = BalanceProof( channel_identifier=100, token_network_address=c1_token_network_proxy.address, balance_hash=encode_hex(EMPTY_BALANCE_HASH), nonce=0, chain_id=chain_id, transferred_amount=0, ) closing_data = (empty_balance_proof.serialize_bin( msg_type=MessageTypeId.BALANCE_PROOF) + EMPTY_SIGNATURE) msg = "Trying to close an inexisting channel must fail." match = "The channel was not open at the provided block" with pytest.raises(RaidenUnrecoverableError, match=match): c1_token_network_proxy.close( channel_identifier=100, partner=c2_client.address, balance_hash=EMPTY_HASH, nonce=0, additional_hash=EMPTY_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=c1_signer.sign(data=closing_data), given_block_identifier="latest", ) pytest.fail(msg) channel_identifier = c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest", ) msg = "new_netting_channel did not return a valid channel id" assert isinstance(channel_identifier, T_ChannelID), msg msg = "multiple channels with the same peer are not allowed" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest", ) pytest.fail(msg) assert (c1_token_network_proxy.get_channel_identifier_or_none( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", ) is not None) assert (c1_token_network_proxy.channel_is_opened( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", channel_identifier=channel_identifier, ) is True) msg = "set_total_deposit must fail if the amount exceed the account's balance" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=initial_token_balance + 1, partner=c2_client.address, ) pytest.fail(msg) msg = "set_total_deposit must fail with a negative amount" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=-1, partner=c2_client.address, ) pytest.fail(msg) msg = "set_total_deposit must fail with a zero amount" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=0, partner=c2_client.address, ) pytest.fail(msg) c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=10, partner=c2_client.address, ) transferred_amount = 3 balance_proof = BalanceProof( channel_identifier=channel_identifier, token_network_address=to_checksum_address(token_network_address), nonce=1, chain_id=chain_id, transferred_amount=transferred_amount, ) signature = c1_signer.sign(data=balance_proof.serialize_bin()) balance_proof.signature = encode_hex(signature) signature_number = int.from_bytes(signature, "big") bit_to_change = random.randint(0, SIGNATURE_SIZE_IN_BITS - 1) signature_number_bit_flipped = signature_number ^ (2**bit_to_change) invalid_signatures = [ EMPTY_SIGNATURE, b"\x11" * 65, signature_number_bit_flipped.to_bytes(len(signature), "big"), ] msg = "close must fail if the closing_signature is invalid" for invalid_signature in invalid_signatures: closing_data = ( balance_proof.serialize_bin(msg_type=MessageTypeId.BALANCE_PROOF) + invalid_signature) with pytest.raises(RaidenUnrecoverableError): c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), non_closing_signature=invalid_signature, closing_signature=c2_signer.sign(data=closing_data), given_block_identifier="latest", ) pytest.fail(msg) blocknumber_prior_to_close = c2_client.block_number() closing_data = balance_proof.serialize_bin( msg_type=MessageTypeId.BALANCE_PROOF) + decode_hex( balance_proof.signature) c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), non_closing_signature=decode_hex(balance_proof.signature), closing_signature=c2_signer.sign(data=closing_data), given_block_identifier="latest", ) assert (c1_token_network_proxy.channel_is_closed( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", channel_identifier=channel_identifier, ) is True) assert (c1_token_network_proxy.get_channel_identifier_or_none( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", ) is not None) msg = ( "given_block_identifier is the block at which the transaction is being " "sent. If the channel is already closed at that block the client code " "has a programming error. An exception is raised for that.") with pytest.raises(RaidenUnrecoverableError): c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), non_closing_signature=decode_hex(balance_proof.signature), closing_signature=c2_signer.sign(data=closing_data), given_block_identifier="latest", ) pytest.fail(msg) msg = ("The channel cannot be closed two times. If it was not closed at " "given_block_identifier but it is closed at the time the proxy is " "called an exception must be raised.") with pytest.raises(RaidenRecoverableError): c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), non_closing_signature=decode_hex(balance_proof.signature), closing_signature=c2_signer.sign(data=closing_data), given_block_identifier=blocknumber_prior_to_close, ) pytest.fail(msg) msg = "depositing to a closed channel must fail" match = "closed" with pytest.raises(RaidenRecoverableError, match=match): c2_token_network_proxy.set_total_deposit( given_block_identifier=blocknumber_prior_to_close, channel_identifier=channel_identifier, total_deposit=20, partner=c1_client.address, ) pytest.fail(msg) c1_proxy_manager.wait_until_block( target_block_number=c1_proxy_manager.client.block_number() + TEST_SETTLE_TIMEOUT_MIN) invalid_transferred_amount = 1 msg = "settle with invalid transferred_amount data must fail" with pytest.raises(BrokenPreconditionError): c2_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=invalid_transferred_amount, locked_amount=0, locksroot=LOCKSROOT_OF_NO_LOCKS, partner=c1_client.address, partner_transferred_amount=transferred_amount, partner_locked_amount=0, partner_locksroot=LOCKSROOT_OF_NO_LOCKS, given_block_identifier="latest", ) pytest.fail(msg) c2_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=0, locked_amount=0, locksroot=LOCKSROOT_OF_NO_LOCKS, partner=c1_client.address, partner_transferred_amount=transferred_amount, partner_locked_amount=0, partner_locksroot=LOCKSROOT_OF_NO_LOCKS, given_block_identifier="latest", ) assert (c1_token_network_proxy.get_channel_identifier_or_none( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", ) is None) assert token_proxy.balance_of(c1_client.address) == (initial_balance_c1 - transferred_amount) assert token_proxy.balance_of(c2_client.address) == (initial_balance_c2 + transferred_amount) msg = "depositing to a settled channel must fail" with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=10, partner=c2_client.address, ) pytest.fail(msg)
def test_token_network_proxy_update_transfer(token_network_proxy, private_keys, token_proxy, chain_id, web3, contract_manager): """Tests channel lifecycle, with `update_transfer` before settling""" token_network_address = to_canonical_address( token_network_proxy.proxy.address) c1_client = JSONRPCClient(web3, private_keys[1]) c1_proxy_manager = ProxyManager( rpc_client=c1_client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) c1_signer = LocalSigner(private_keys[1]) c2_client = JSONRPCClient(web3, private_keys[2]) c2_proxy_manager = ProxyManager( rpc_client=c2_client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) c1_token_network_proxy = c1_proxy_manager.token_network( address=token_network_address, block_identifier=BLOCK_ID_LATEST) c2_token_network_proxy = c2_proxy_manager.token_network( address=token_network_address, block_identifier=BLOCK_ID_LATEST) # create a channel channel_identifier, _, _ = c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=10, given_block_identifier=BLOCK_ID_LATEST) # deposit to the channel initial_balance = 100 token_proxy.transfer(c1_client.address, initial_balance) token_proxy.transfer(c2_client.address, initial_balance) initial_balance_c1 = token_proxy.balance_of(c1_client.address) assert initial_balance_c1 == initial_balance initial_balance_c2 = token_proxy.balance_of(c2_client.address) assert initial_balance_c2 == initial_balance c1_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, total_deposit=10, partner=c2_client.address, ) c2_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, total_deposit=10, partner=c1_client.address, ) # balance proof signed by c1 transferred_amount_c1 = 1 transferred_amount_c2 = 3 balance_proof_c1 = BalanceProof( channel_identifier=channel_identifier, token_network_address=token_network_address, nonce=1, chain_id=chain_id, transferred_amount=transferred_amount_c1, ) balance_proof_c1.signature = encode_hex( LocalSigner( private_keys[1]).sign(data=balance_proof_c1.serialize_bin())) # balance proof signed by c2 balance_proof_c2 = BalanceProof( channel_identifier=channel_identifier, token_network_address=token_network_address, nonce=2, chain_id=chain_id, transferred_amount=transferred_amount_c2, ) balance_proof_c2.signature = encode_hex( LocalSigner( private_keys[2]).sign(data=balance_proof_c2.serialize_bin())) non_closing_data = balance_proof_c1.serialize_bin( msg_type=MessageTypeId.BALANCE_PROOF_UPDATE) + decode_hex( balance_proof_c1.signature) non_closing_signature = LocalSigner( c2_client.privkey).sign(data=non_closing_data) with pytest.raises(RaidenUnrecoverableError) as exc: c2_token_network_proxy.update_transfer( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=balance_proof_c1.balance_hash, nonce=balance_proof_c1.nonce, additional_hash=decode_hex(balance_proof_c1.additional_hash), closing_signature=decode_hex(balance_proof_c1.signature), non_closing_signature=non_closing_signature, given_block_identifier=BLOCK_ID_LATEST, ) assert "not in a closed state" in str(exc) # close by c1 closing_data = balance_proof_c2.serialize_bin( msg_type=MessageTypeId.BALANCE_PROOF) + decode_hex( balance_proof_c2.signature) c1_token_network_proxy.close( channel_identifier=channel_identifier, partner=c2_client.address, balance_hash=balance_proof_c2.balance_hash, nonce=balance_proof_c2.nonce, additional_hash=decode_hex(balance_proof_c2.additional_hash), non_closing_signature=decode_hex(balance_proof_c2.signature), closing_signature=c1_signer.sign(data=closing_data), given_block_identifier=BLOCK_ID_LATEST, ) # update transfer with completely invalid closing signature with pytest.raises(RaidenUnrecoverableError) as excinfo: c2_token_network_proxy.update_transfer( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=balance_proof_c1.balance_hash, nonce=balance_proof_c1.nonce, additional_hash=decode_hex(balance_proof_c1.additional_hash), closing_signature=b"", non_closing_signature=b"", given_block_identifier=BLOCK_ID_LATEST, ) assert str(excinfo.value) == "Couldn't verify the balance proof signature" # using invalid non-closing signature # Usual mistake when calling update Transfer - balance proof signature is missing in the data non_closing_data = balance_proof_c1.serialize_bin( msg_type=MessageTypeId.BALANCE_PROOF_UPDATE) non_closing_signature = LocalSigner( c2_client.privkey).sign(data=non_closing_data) with pytest.raises(RaidenUnrecoverableError): c2_token_network_proxy.update_transfer( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=balance_proof_c1.balance_hash, nonce=balance_proof_c1.nonce, additional_hash=decode_hex(balance_proof_c1.additional_hash), closing_signature=decode_hex(balance_proof_c1.signature), non_closing_signature=non_closing_signature, given_block_identifier=BLOCK_ID_LATEST, ) non_closing_data = balance_proof_c1.serialize_bin( msg_type=MessageTypeId.BALANCE_PROOF_UPDATE) + decode_hex( balance_proof_c1.signature) non_closing_signature = LocalSigner( c2_client.privkey).sign(data=non_closing_data) c2_token_network_proxy.update_transfer( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=balance_proof_c1.balance_hash, nonce=balance_proof_c1.nonce, additional_hash=decode_hex(balance_proof_c1.additional_hash), closing_signature=decode_hex(balance_proof_c1.signature), non_closing_signature=non_closing_signature, given_block_identifier=BLOCK_ID_LATEST, ) with pytest.raises(BrokenPreconditionError) as exc: c1_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=transferred_amount_c1, locked_amount=0, locksroot=LOCKSROOT_OF_NO_LOCKS, partner=c2_client.address, partner_transferred_amount=transferred_amount_c2, partner_locked_amount=0, partner_locksroot=LOCKSROOT_OF_NO_LOCKS, given_block_identifier=BLOCK_ID_LATEST, ) assert "cannot be settled before settlement window is over" in str(exc) c1_client.wait_until_block(target_block_number=c1_client.block_number() + 10) # settling with an invalid amount with pytest.raises(BrokenPreconditionError): c1_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=2, locked_amount=0, locksroot=LOCKSROOT_OF_NO_LOCKS, partner=c2_client.address, partner_transferred_amount=2, partner_locked_amount=0, partner_locksroot=LOCKSROOT_OF_NO_LOCKS, given_block_identifier=BLOCK_ID_LATEST, ) # proper settle c1_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=transferred_amount_c1, locked_amount=0, locksroot=LOCKSROOT_OF_NO_LOCKS, partner=c2_client.address, partner_transferred_amount=transferred_amount_c2, partner_locked_amount=0, partner_locksroot=LOCKSROOT_OF_NO_LOCKS, given_block_identifier=BLOCK_ID_LATEST, ) assert token_proxy.balance_of( c2_client.address) == (initial_balance_c2 + transferred_amount_c1 - transferred_amount_c2) assert token_proxy.balance_of( c1_client.address) == (initial_balance_c1 + transferred_amount_c2 - transferred_amount_c1) # Already settled with pytest.raises(BrokenPreconditionError) as exc: c2_token_network_proxy.approve_and_set_total_deposit( given_block_identifier=BLOCK_ID_LATEST, channel_identifier=channel_identifier, total_deposit=20, partner=c1_client.address, ) assert "getChannelIdentifier returned 0" in str(exc)
class ScenarioRunner: def __init__( self, account: Account, auth: str, data_path: Path, scenario_file: Path, environment: EnvironmentConfig, success: Event, raiden_client: Optional[str], task_state_callback: Optional[ Callable[["ScenarioRunner", "Task", "TaskState"], None] ] = None, smoketest_deployment_data: DeployedContracts = None, delete_snapshots: bool = False, ) -> None: self.success = success self.smoketest_deployment_data = smoketest_deployment_data self.delete_snapshots = delete_snapshots self.data_path = data_path self.environment = environment # Set the client executable to use if raiden_client is not None: self.environment.raiden_client = raiden_client self.task_count = 0 self.running_task_count = 0 self.task_cache: Dict[str, Task] = {} self.task_state_callback = task_state_callback # Storage for arbitrary data tasks might need to persist self.task_storage: Dict[str, dict] = defaultdict(dict) self.definition = ScenarioDefinition(scenario_file, data_path, self.environment) log.debug("Local seed", seed=self.local_seed) self.run_number = determine_run_number(self.definition.scenario_dir) log.info("Run number", run_number=self.run_number) self.protocol = "http" self.session = make_session(auth, self.definition.settings, self.definition.nodes) web3 = Web3(HTTPProvider(environment.eth_rpc_endpoints[0], session=self.session)) self.chain_id = ChainID(web3.eth.chainId) self.definition.settings.eth_rpc_endpoint_iterator = environment.eth_rpc_endpoint_iterator self.definition.settings.chain_id = self.chain_id assert account.privkey, "Account not unlockable" self.client = JSONRPCClient( web3=web3, privkey=account.privkey, gas_price_strategy=faster_gas_price_strategy, block_num_confirmations=DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS, ) assert account.address, "Account not loaded" balance = self.client.balance(account.address) if balance < OWN_ACCOUNT_BALANCE_MIN: raise ScenarioError( f"Insufficient balance ({balance / 10 ** 18} Eth) " f"in account {to_checksum_address(account.address)} " f'on chain "{self.definition.settings.chain_id}"' f" - it needs additional {(OWN_ACCOUNT_BALANCE_MIN - balance) / 10 ** 18} Eth (" f"that is {OWN_ACCOUNT_BALANCE_MIN - balance} Wei)." ) self.node_controller = NodeController( runner=self, config=self.definition.nodes, raiden_client=self.environment.raiden_client, delete_snapshots=self.delete_snapshots, ) task_config = self.definition.scenario.root_config task_class = self.definition.scenario.root_class self.root_task = task_class(runner=self, config=task_config) @property def local_seed(self) -> str: """Return a persistent random seed value. We need a unique seed per scenario player 'installation'. This is used in the node private key generation to prevent re-use of node keys between multiple users of the scenario player. The seed is stored in a file inside the ``.definition.settings.sp_root_dir``. """ assert self.definition.settings.sp_root_dir seed_file = self.definition.settings.sp_root_dir.joinpath("seed.txt") if not seed_file.exists(): seed = str(encode_hex(bytes(random.randint(0, 255) for _ in range(20)))) seed_file.write_text(seed) else: seed = seed_file.read_text().strip() return seed def ensure_token_network_discovery( self, token: CustomToken, token_network_addresses: TokenNetworkAddress ) -> None: """Ensure that all our nodes have discovered the same token network.""" for node in self.node_controller: # type: ignore node_endpoint = API_URL_TOKEN_NETWORK_ADDRESS.format( protocol=self.protocol, target_host=node.base_url, token_address=to_checksum_address(token.address), ) address = wait_for_token_network_discovery( node_endpoint, self.definition.settings, self.session ) if to_canonical_address(address) != Address(token_network_addresses): raise RuntimeError( f"Nodes diverged on the token network address, there should be " f"exactly one token network available for all nodes. Current " f"values : {to_hex(token_network_addresses)}" ) def run_scenario(self) -> None: with Janitor() as nursery: self.node_controller.set_nursery(nursery) self.node_controller.initialize_nodes() try: for node_runner in self.node_controller._node_runners: node_runner.start() except Exception: log.error("failed to start", exc_info=True) raise node_addresses = self.node_controller.addresses scenario = nursery.spawn_under_watch( self.setup_environment_and_run_main_task, node_addresses ) scenario.name = "orchestration" # Wait for either a crash in one of the Raiden nodes or for the # scenario to exit (successfully or not). greenlets = {scenario} gevent.joinall(greenlets, raise_error=True, count=1) self.success.set() def setup_environment_and_run_main_task(self, node_addresses: Set[ChecksumAddress]) -> None: """This will first make sure the on-chain state is setup properly, and then execute the scenario. The on-chain state consists of: - Deployment of the test CustomToken - For each of the Raiden nodes, make sure they have enough: - Ether to pay for the transactions. - Utility token balances in the user deposit smart contract. - Tokens to be used with the test token network. """ block_execution_started = self.client.block_number() settings = self.definition.settings udc_settings = settings.services.udc smoketesting = False if self.chain_id != CHAINNAME_TO_ID["smoketest"]: deploy = get_contracts_deployment_info( self.chain_id, RAIDEN_CONTRACT_VERSION, development_environment=self.environment.development_environment, ) else: smoketesting = True deploy = self.smoketest_deployment_data msg = "There is no deployment details for the given chain_id and contracts version pair" assert deploy, msg proxy_manager = get_proxy_manager(self.client, deploy) # Tracking pool to synchronize on all concurrent transactions pool = Pool() log.debug("Funding Raiden node's accounts with ether") self.setup_raiden_nodes_ether_balances(pool, node_addresses) if is_udc_enabled(udc_settings): ( userdeposit_proxy, user_token_proxy, ) = get_udc_and_corresponding_token_from_dependencies( udc_address=udc_settings.address, chain_id=settings.chain_id, proxy_manager=proxy_manager, development_environment=self.environment.development_environment, ) log.debug("Minting utility tokens and /scheduling/ transfers to the nodes") mint_greenlets = self.setup_mint_user_deposit_tokens_for_distribution( pool, userdeposit_proxy, user_token_proxy, node_addresses ) self.setup_raiden_nodes_with_sufficient_user_deposit_balances( pool, userdeposit_proxy, node_addresses, mint_greenlets ) # This is a blocking call. If the token has to be deployed it will # block until mined and confirmed, since that is a requirement for the # following setup calls. token_proxy = self.setup_token_contract_for_token_network(proxy_manager) if smoketesting: token_network_registry_proxy = get_token_network_registry_from_dependencies( settings=settings, proxy_manager=proxy_manager, smoketest_deployment_data=deploy, development_environment=self.environment.development_environment, ) else: token_network_registry_proxy = get_token_network_registry_from_dependencies( settings=settings, proxy_manager=proxy_manager, development_environment=self.environment.development_environment, ) self.setup_raiden_token_balances(pool, token_proxy, node_addresses) # Wait for all the transactions # - Move ether from the orcheastration account (the scenario player), # to the raiden nodes. # - Mint enough utility tokens (user deposit tokens) for the # orchestration account to transfer for the nodes. # - Mint network tokens for the nodes to use in the scenarion. # - Deposit utility tokens for the raiden nodes in the user deposit # contract. log.debug("Waiting for funding transactions to be mined") pool.join(raise_error=True) log.debug("Registering token to create the network") token_network_address = maybe_create_token_network( token_network_registry_proxy, token_proxy ) log.debug("Waiting for the REST APIs") wait_for_nodes_to_be_ready(self.node_controller._node_runners, self.session) log.info("Making sure all nodes have the same token network") self.ensure_token_network_discovery(token_proxy, token_network_address) log.info( "Setup done, running scenario", token_network_address=to_checksum_address(token_network_address), ) # Expose attributes used by the tasks self.token = token_proxy self.contract_manager = proxy_manager.contract_manager self.token_network_address = to_checksum_address(token_network_address) self.block_execution_started = block_execution_started self.root_task() def setup_raiden_nodes_ether_balances( self, pool: Pool, node_addresses: Set[ChecksumAddress] ) -> Set[Greenlet]: """ Makes sure every Raiden node has at least `NODE_ACCOUNT_BALANCE_MIN`. """ greenlets: Set[Greenlet] = set() for address in node_addresses: g = pool.spawn( eth_maybe_transfer, orchestration_client=self.client, target=to_canonical_address(address), minimum_balance=NODE_ACCOUNT_BALANCE_MIN, maximum_balance=NODE_ACCOUNT_BALANCE_FUND, ) greenlets.add(g) return greenlets def setup_mint_user_deposit_tokens_for_distribution( self, pool: Pool, userdeposit_proxy: UserDeposit, token_proxy: CustomToken, node_addresses: Set[ChecksumAddress], ) -> Set[Greenlet]: """Ensures the scenario player account has enough tokens and allowance to fund the Raiden nodes. """ settings = self.definition.settings udc_settings = settings.services.udc balance_per_node = settings.services.udc.token.balance_per_node msg = "udc is not enabled, this function should not be called" assert is_udc_enabled(udc_settings), msg node_count = len(node_addresses) required_allowance = balance_per_node * node_count allowance_greenlet = pool.spawn( userdeposit_maybe_increase_allowance, token_proxy=token_proxy, userdeposit_proxy=userdeposit_proxy, orchestrator_address=self.client.address, minimum_allowance=required_allowance, maximum_allowance=UINT256_MAX, ) mint_greenlet = pool.spawn( token_maybe_mint, token_proxy=token_proxy, target_address=to_checksum_address(self.client.address), minimum_balance=required_allowance, maximum_balance=ORCHESTRATION_MAXIMUM_BALANCE, ) return {allowance_greenlet, mint_greenlet} def setup_raiden_token_balances( self, pool: Pool, token_proxy: CustomToken, node_addresses: Set[ChecksumAddress] ) -> Set[Greenlet]: """Mint the necessary amount of tokens from `token_proxy` for every `node_addresses`. This will use the scenario player's account, therefore it doesn't have to wait for the ether transfers to finish. """ token_min_amount = self.definition.token.min_balance token_max_amount = self.definition.token.max_funding greenlets: Set[Greenlet] = set() for address in node_addresses: g = pool.spawn( token_maybe_mint, token_proxy=token_proxy, target_address=address, minimum_balance=token_min_amount, maximum_balance=token_max_amount, ) greenlets.add(g) return greenlets def setup_raiden_nodes_with_sufficient_user_deposit_balances( self, pool: Pool, userdeposit_proxy: UserDeposit, node_addresses: Set[ChecksumAddress], mint_greenlets: Set[Greenlet], ) -> Set[Greenlet]: """Makes sure every Raiden node's account has enough tokens in the user deposit contract. For these transfers to work, the approve and mint transacations have to be mined and confirmed. This is necessary because otherwise the gas estimation of the deposits fail. """ msg = "udc is not enabled, this function should not be called" assert is_udc_enabled(self.definition.settings.services.udc), msg minimum_effective_deposit = self.definition.settings.services.udc.token.balance_per_node maximum_funding = self.definition.settings.services.udc.token.max_funding log.debug("Depositing utility tokens for the nodes") greenlets: Set[Greenlet] = set() for address in node_addresses: g = pool.spawn( userdeposit_maybe_deposit, userdeposit_proxy=userdeposit_proxy, mint_greenlets=mint_greenlets, target_address=to_canonical_address(address), minimum_effective_deposit=minimum_effective_deposit, maximum_funding=maximum_funding, ) greenlets.add(g) return greenlets def setup_token_contract_for_token_network(self, proxy_manager: ProxyManager) -> CustomToken: """Ensure there is a deployed token contract and return a `CustomToken` proxy to it. This token will be used for the scenario's token network. This will either: - Use the token from the address provided in the scenario configuration. - Use a previously deployed token, with the details loaded from the disk. - Deploy a new token if neither of the above options is used. """ token_definition = self.definition.token reuse_token_from_file = token_definition.can_reuse_token if token_definition.address: token_address = to_canonical_address(token_definition.address) elif reuse_token_from_file: token_details = load_token_configuration_from_file(token_definition.token_file) token_address = to_canonical_address(token_details["address"]) else: contract_data = proxy_manager.contract_manager.get_contract(CONTRACT_CUSTOM_TOKEN) contract, receipt = self.client.deploy_single_contract( contract_name=CONTRACT_CUSTOM_TOKEN, contract=contract_data, constructor_parameters=( ORCHESTRATION_MAXIMUM_BALANCE, token_definition.decimals, token_definition.name, token_definition.symbol, ), ) token_address = to_canonical_address(contract.address) if token_definition.should_reuse_token: details = TokenDetails( { "name": token_definition.name, "address": to_checksum_address(token_address), "block": receipt["blockNumber"], } ) save_token_configuration_to_file(token_definition.token_file, details) return proxy_manager.custom_token(TokenAddress(token_address), "latest") def task_state_changed(self, task: "Task", state: "TaskState"): if self.task_state_callback: self.task_state_callback(self, task, state) def get_node_address(self, index): return self.node_controller[index].address def get_node_baseurl(self, index): return self.node_controller[index].base_url
def test_remote_transaction_with_zero_gasprice_is_not_mined( web3: Web3, deploy_key: PrivateKey, eth_nodes_configuration: List[EthNodeDescription]) -> None: """ If the non-local transaction is sent with a gas price set to zero it is not mined. """ host = "127.0.0.1" assert eth_nodes_configuration[0].miner miner_rpc_port = eth_nodes_configuration[0].rpc_port assert not eth_nodes_configuration[1].miner rpc_port = eth_nodes_configuration[1].rpc_port miner_web3 = Web3(HTTPProvider(f"http://{host}:{miner_rpc_port}")) miner_client = JSONRPCClient(miner_web3, deploy_key) web3 = Web3(HTTPProvider(f"http://{host}:{rpc_port}")) client = JSONRPCClient(web3, deploy_key) before_deploy_block = client.block_number() normal_gas_proxy, _ = deploy_rpc_test_contract(client, "RpcTest") num_blocks_to_wait = client.block_number() - before_deploy_block gas_price = GasPrice(0) gas_price_strategy = make_fixed_gas_price_strategy(gas_price) client.web3.eth.setGasPriceStrategy(gas_price_strategy) zero_gas_proxy = client.new_contract_proxy( abi=normal_gas_proxy.abi, contract_address=normal_gas_proxy.address) address = normal_gas_proxy.address assert len(client.web3.eth.getCode(address)) > 0 estimated_transaction = client.estimate_gas(zero_gas_proxy, "ret", {}) assert estimated_transaction, "Gas estimation should not fail here" zerogas_transaction_sent = client.transact(estimated_transaction) # wait for how many blocks it took to mine the deployment, since this is a # private chain, if the new transaction will be mined it should be roughly # in the same time frame (adding two blocks to cover race conditions) target_block_number = client.block_number() + num_blocks_to_wait + 2 while client.block_number() < target_block_number: gevent.sleep(0.5) try: miner_zerogas_tx = miner_client.web3.eth.getTransaction( zerogas_transaction_sent.transaction_hash) miner_zerogas_receipt = miner_client.web3.eth.getTransactionReceipt( zerogas_transaction_sent.transaction_hash) except TransactionNotFound: miner_zerogas_tx = None miner_zerogas_receipt = None msg = "The transaction was discarded by the miner, there is no transaction and no receipt" assert miner_zerogas_tx is None, msg assert miner_zerogas_receipt is None, msg zerogas_tx = client.web3.eth.getTransaction( zerogas_transaction_sent.transaction_hash) msg = ( "The transaction was NOT discarded by the original node, because it is a local transaction" ) assert zerogas_tx is not None, msg try: zerogas_receipt = client.web3.eth.getTransactionReceipt( zerogas_transaction_sent.transaction_hash) except TransactionNotFound: zerogas_receipt = None msg = "The transaction does NOT have a receipt because the miner rejected it" assert zerogas_receipt is None, msg
def test_payment_channel_outdated_channel_close( token_network_proxy, private_keys, chain_id, web3, contract_manager, ): token_network_address = to_canonical_address( token_network_proxy.proxy.contract.address) partner = privatekey_to_address(private_keys[0]) client = JSONRPCClient(web3, private_keys[1]) chain = BlockChainService(client) token_network_proxy = TokenNetwork( jsonrpc_client=client, token_network_address=token_network_address, contract_manager=contract_manager, ) start_block = web3.eth.blockNumber # create a channel channel_identifier = token_network_proxy.new_netting_channel( partner, TEST_SETTLE_TIMEOUT_MIN, ) assert channel_identifier is not None # create channel proxies channel_proxy_1 = PaymentChannel( token_network=token_network_proxy, channel_identifier=channel_identifier, contract_manager=contract_manager, ) channel_filter = channel_proxy_1.all_events_filter( from_block=start_block, to_block='latest', ) assert channel_proxy_1.channel_identifier == channel_identifier assert channel_proxy_1.opened() is True # balance proof by c1 balance_proof = BalanceProof( channel_identifier=channel_identifier, token_network_address=to_checksum_address(token_network_address), nonce=0, chain_id=chain_id, transferred_amount=0, ) balance_proof.signature = encode_hex( LocalSigner(private_keys[0]).sign( data=balance_proof.serialize_bin(), ), ) # correct close token_network_proxy.close( channel_identifier=channel_identifier, partner=partner, balance_hash=bytes(32), nonce=balance_proof.nonce, additional_hash=bytes(32), signature=decode_hex(balance_proof.signature), ) assert channel_proxy_1.closed() is True events = channel_filter.get_all_entries() assert len(events) == 2 # ChannelOpened, ChannelClosed # check the settlement timeouts again assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN # update transfer chain.wait_until_block(target_block_number=client.block_number() + TEST_SETTLE_TIMEOUT_MIN) token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=0, locked_amount=0, locksroot=EMPTY_HASH, partner=partner, partner_transferred_amount=0, partner_locked_amount=0, partner_locksroot=EMPTY_HASH, ) assert channel_proxy_1.settled() is True events = channel_filter.get_all_entries() assert len(events) == 3 # ChannelOpened, ChannelClosed, ChannelSettled # Create a new channel with a different identifier # create a channel new_channel_identifier = token_network_proxy.new_netting_channel( partner, TEST_SETTLE_TIMEOUT_MIN, ) assert new_channel_identifier is not None # create channel proxies channel_proxy_2 = PaymentChannel( token_network=token_network_proxy, channel_identifier=new_channel_identifier, contract_manager=contract_manager, ) assert channel_proxy_2.channel_identifier == new_channel_identifier assert channel_proxy_2.opened() is True with pytest.raises(ChannelOutdatedError): token_network_proxy.close( channel_identifier=channel_identifier, partner=partner, balance_hash=bytes(32), nonce=balance_proof.nonce, additional_hash=bytes(32), signature=decode_hex(balance_proof.signature), )
def test_payment_channel_proxy_basics( token_network_proxy, private_keys, token_proxy, chain_id, web3, contract_manager, ): token_network_address = to_canonical_address( token_network_proxy.proxy.contract.address) c1_client = JSONRPCClient(web3, private_keys[1]) c1_chain = BlockChainService(c1_client) c2_client = JSONRPCClient(web3, private_keys[2]) c1_token_network_proxy = TokenNetwork( jsonrpc_client=c1_client, token_network_address=token_network_address, contract_manager=contract_manager, ) c2_token_network_proxy = TokenNetwork( jsonrpc_client=c2_client, token_network_address=token_network_address, contract_manager=contract_manager, ) start_block = web3.eth.blockNumber # create a channel channel_identifier = c1_token_network_proxy.new_netting_channel( c2_client.address, TEST_SETTLE_TIMEOUT_MIN, ) assert channel_identifier is not None # create channel proxies channel_proxy_1 = PaymentChannel( token_network=c1_token_network_proxy, channel_identifier=channel_identifier, contract_manager=contract_manager, ) channel_proxy_2 = PaymentChannel( token_network=c2_token_network_proxy, channel_identifier=channel_identifier, contract_manager=contract_manager, ) channel_filter = channel_proxy_1.all_events_filter( from_block=start_block, to_block='latest', ) assert channel_proxy_1.channel_identifier == channel_identifier assert channel_proxy_2.channel_identifier == channel_identifier assert channel_proxy_1.opened() is True assert channel_proxy_2.opened() is True # check the settlement timeouts assert channel_proxy_1.settle_timeout() == channel_proxy_2.settle_timeout() assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN events = channel_filter.get_all_entries() assert len(events) == 1 # ChannelOpened # test deposits initial_token_balance = 100 token_proxy.transfer(c1_client.address, initial_token_balance) initial_balance_c1 = token_proxy.balance_of(c1_client.address) assert initial_balance_c1 == initial_token_balance initial_balance_c2 = token_proxy.balance_of(c2_client.address) assert initial_balance_c2 == 0 # actual deposit channel_proxy_1.set_total_deposit(10) events = channel_filter.get_all_entries() assert len(events) == 2 # ChannelOpened, ChannelNewDeposit # balance proof by c2 transferred_amount = 3 balance_proof = BalanceProof( channel_identifier=channel_identifier, token_network_address=to_checksum_address(token_network_address), nonce=1, chain_id=chain_id, transferred_amount=transferred_amount, ) balance_proof.signature = encode_hex( LocalSigner(private_keys[1]).sign( data=balance_proof.serialize_bin(), ), ) # correct close c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), signature=decode_hex(balance_proof.signature), ) assert channel_proxy_1.closed() is True assert channel_proxy_2.closed() is True events = channel_filter.get_all_entries() assert len(events) == 3 # ChannelOpened, ChannelNewDeposit, ChannelClosed # check the settlement timeouts again assert channel_proxy_1.settle_timeout() == channel_proxy_2.settle_timeout() assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN # update transfer c1_chain.wait_until_block(target_block_number=c1_client.block_number() + TEST_SETTLE_TIMEOUT_MIN, ) c2_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=0, locked_amount=0, locksroot=EMPTY_HASH, partner=c1_client.address, partner_transferred_amount=transferred_amount, partner_locked_amount=0, partner_locksroot=EMPTY_HASH, ) assert channel_proxy_1.settled() is True assert channel_proxy_2.settled() is True events = channel_filter.get_all_entries() assert len( events ) == 4 # ChannelOpened, ChannelNewDeposit, ChannelClosed, ChannelSettled
def test_payment_channel_proxy_basics( token_network_proxy, private_keys, token_proxy, chain_id, web3, contract_manager, ): token_network_address = to_canonical_address(token_network_proxy.proxy.contract.address) c1_client = JSONRPCClient(web3, private_keys[1]) c1_chain = BlockChainService(private_keys[1], c1_client) c2_client = JSONRPCClient(web3, private_keys[2]) c1_token_network_proxy = TokenNetwork( jsonrpc_client=c1_client, token_network_address=token_network_address, contract_manager=contract_manager, ) c2_token_network_proxy = TokenNetwork( jsonrpc_client=c2_client, token_network_address=token_network_address, contract_manager=contract_manager, ) start_block = web3.eth.blockNumber # create a channel channel_identifier = c1_token_network_proxy.new_netting_channel( c2_client.address, TEST_SETTLE_TIMEOUT_MIN, ) assert channel_identifier is not None # create channel proxies channel_proxy_1 = PaymentChannel( token_network=c1_token_network_proxy, channel_identifier=channel_identifier, contract_manager=contract_manager, ) channel_proxy_2 = PaymentChannel( token_network=c2_token_network_proxy, channel_identifier=channel_identifier, contract_manager=contract_manager, ) channel_filter = channel_proxy_1.all_events_filter( from_block=start_block, to_block='latest', ) assert channel_proxy_1.channel_identifier == channel_identifier assert channel_proxy_2.channel_identifier == channel_identifier assert channel_proxy_1.opened() is True assert channel_proxy_2.opened() is True # check the settlement timeouts assert channel_proxy_1.settle_timeout() == channel_proxy_2.settle_timeout() assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN events = channel_filter.get_all_entries() assert len(events) == 1 # ChannelOpened # test deposits initial_token_balance = 100 token_proxy.transfer(c1_client.address, initial_token_balance) initial_balance_c1 = token_proxy.balance_of(c1_client.address) assert initial_balance_c1 == initial_token_balance initial_balance_c2 = token_proxy.balance_of(c2_client.address) assert initial_balance_c2 == 0 # actual deposit channel_proxy_1.set_total_deposit(10) events = channel_filter.get_all_entries() assert len(events) == 2 # ChannelOpened, ChannelNewDeposit # balance proof by c2 transferred_amount = 3 balance_proof = BalanceProof( channel_identifier=channel_identifier, token_network_address=to_checksum_address(token_network_address), nonce=1, chain_id=chain_id, transferred_amount=transferred_amount, ) balance_proof.signature = encode_hex(eth_sign( privkey=encode_hex(private_keys[1]), data=balance_proof.serialize_bin(), )) # correct close c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), signature=decode_hex(balance_proof.signature), ) assert channel_proxy_1.closed() is True assert channel_proxy_2.closed() is True events = channel_filter.get_all_entries() assert len(events) == 3 # ChannelOpened, ChannelNewDeposit, ChannelClosed # check the settlement timeouts again assert channel_proxy_1.settle_timeout() == channel_proxy_2.settle_timeout() assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN # update transfer wait_until_block(c1_chain, c1_client.block_number() + TEST_SETTLE_TIMEOUT_MIN) c2_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=0, locked_amount=0, locksroot=EMPTY_HASH, partner=c1_client.address, partner_transferred_amount=transferred_amount, partner_locked_amount=0, partner_locksroot=EMPTY_HASH, ) assert channel_proxy_1.settled() is True assert channel_proxy_2.settled() is True events = channel_filter.get_all_entries() assert len(events) == 4 # ChannelOpened, ChannelNewDeposit, ChannelClosed, ChannelSettled
def test_payment_channel_outdated_channel_close( token_network_proxy, private_keys, chain_id, web3, contract_manager, ): token_network_address = to_canonical_address(token_network_proxy.proxy.contract.address) partner = privatekey_to_address(private_keys[0]) client = JSONRPCClient(web3, private_keys[1]) chain = BlockChainService(private_keys[1], client) token_network_proxy = TokenNetwork( jsonrpc_client=client, token_network_address=token_network_address, contract_manager=contract_manager, ) start_block = web3.eth.blockNumber # create a channel channel_identifier = token_network_proxy.new_netting_channel( partner, TEST_SETTLE_TIMEOUT_MIN, ) assert channel_identifier is not None # create channel proxies channel_proxy_1 = PaymentChannel( token_network=token_network_proxy, channel_identifier=channel_identifier, contract_manager=contract_manager, ) channel_filter = channel_proxy_1.all_events_filter( from_block=start_block, to_block='latest', ) assert channel_proxy_1.channel_identifier == channel_identifier assert channel_proxy_1.opened() is True # balance proof by c1 balance_proof = BalanceProof( channel_identifier=channel_identifier, token_network_address=to_checksum_address(token_network_address), nonce=0, chain_id=chain_id, transferred_amount=0, ) balance_proof.signature = encode_hex(eth_sign( privkey=encode_hex(private_keys[0]), data=balance_proof.serialize_bin(), )) # correct close token_network_proxy.close( channel_identifier=channel_identifier, partner=partner, balance_hash=bytes(32), nonce=balance_proof.nonce, additional_hash=bytes(32), signature=decode_hex(balance_proof.signature), ) assert channel_proxy_1.closed() is True events = channel_filter.get_all_entries() assert len(events) == 2 # ChannelOpened, ChannelClosed # check the settlement timeouts again assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN # update transfer wait_until_block(chain, client.block_number() + TEST_SETTLE_TIMEOUT_MIN) token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=0, locked_amount=0, locksroot=EMPTY_HASH, partner=partner, partner_transferred_amount=0, partner_locked_amount=0, partner_locksroot=EMPTY_HASH, ) assert channel_proxy_1.settled() is True events = channel_filter.get_all_entries() assert len(events) == 3 # ChannelOpened, ChannelClosed, ChannelSettled # Create a new channel with a different identifier # create a channel new_channel_identifier = token_network_proxy.new_netting_channel( partner, TEST_SETTLE_TIMEOUT_MIN, ) assert new_channel_identifier is not None # create channel proxies channel_proxy_2 = PaymentChannel( token_network=token_network_proxy, channel_identifier=new_channel_identifier, contract_manager=contract_manager, ) assert channel_proxy_2.channel_identifier == new_channel_identifier assert channel_proxy_2.opened() is True with pytest.raises(ChannelOutdatedError): token_network_proxy.close( channel_identifier=channel_identifier, partner=partner, balance_hash=bytes(32), nonce=balance_proof.nonce, additional_hash=bytes(32), signature=decode_hex(balance_proof.signature), )
def test_token_network_proxy(token_network_proxy, private_keys, token_proxy, chain_id, web3, contract_manager): assert token_network_proxy.settlement_timeout_min( ) == TEST_SETTLE_TIMEOUT_MIN assert token_network_proxy.settlement_timeout_max( ) == TEST_SETTLE_TIMEOUT_MAX token_network_address = to_canonical_address( token_network_proxy.proxy.contract.address) c1_signer = LocalSigner(private_keys[1]) c1_client = JSONRPCClient(web3, private_keys[1]) c1_chain = BlockChainService(jsonrpc_client=c1_client, contract_manager=contract_manager) c2_client = JSONRPCClient(web3, private_keys[2]) c1_token_network_proxy = TokenNetwork( jsonrpc_client=c1_client, token_network_address=token_network_address, contract_manager=contract_manager, ) c2_token_network_proxy = TokenNetwork( jsonrpc_client=c2_client, token_network_address=token_network_address, contract_manager=contract_manager, ) initial_token_balance = 100 token_proxy.transfer(c1_client.address, initial_token_balance) token_proxy.transfer(c2_client.address, initial_token_balance) initial_balance_c1 = token_proxy.balance_of(c1_client.address) assert initial_balance_c1 == initial_token_balance initial_balance_c2 = token_proxy.balance_of(c2_client.address) assert initial_balance_c2 == initial_token_balance # instantiating a new channel - test basic assumptions assert (c1_token_network_proxy._channel_exists_and_not_settled( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", ) is False) channel_identifier = c1_token_network_proxy._call_and_check_result( "latest", "getChannelIdentifier", to_checksum_address(c1_client.address), to_checksum_address(c2_client.address), ) assert channel_identifier == 0 msg = "Zero is not a valid channel_identifier identifier, ValueError must be " "raised." with pytest.raises(ValueError, message=msg): assert c1_token_network_proxy.channel_is_opened( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", channel_identifier=0, ) msg = "Zero is not a valid channel_identifier identifier. ValueError must be " "raised." with pytest.raises(ValueError, message=msg): assert c1_token_network_proxy.channel_is_closed( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", channel_identifier=0, ) msg = ("Opening a channel with a settle_timeout lower then token " "network's minimum will fail. This must be validated and the " "transaction must not be sent.") with pytest.raises(InvalidSettleTimeout, message=msg): c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN - 1, given_block_identifier="latest", ) msg = ("Opening a channel with a settle_timeout larger then token " "network's maximum will fail. This must be validated and the " "transaction must not be sent.") with pytest.raises(InvalidSettleTimeout, message=msg): c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MAX + 1, given_block_identifier="latest", ) msg = ( "Opening a channel with itself is not allow. This must be validated and " "the transaction must not be sent.") with pytest.raises(SamePeerAddress, message=msg): c1_token_network_proxy.new_netting_channel( partner=c1_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest", ) msg = "Trying a deposit to an inexisting channel must fail." with pytest.raises(RaidenUnrecoverableError, message=msg, match="does not exist"): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=1, total_deposit=1, partner=c2_client.address, ) msg = "Trying to close an inexisting channel must fail." match = "The channel was not open at the provided block" with pytest.raises(RaidenUnrecoverableError, message=msg, match=match): c1_token_network_proxy.close( channel_identifier=1, partner=c2_client.address, balance_hash=EMPTY_HASH, nonce=0, additional_hash=EMPTY_HASH, signature=EMPTY_SIGNATURE, given_block_identifier="latest", ) channel_identifier = c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest", ) msg = "new_netting_channel did not return a valid channel id" assert isinstance(channel_identifier, T_ChannelID), msg msg = "multiple channels with the same peer are not allowed" with pytest.raises(DuplicatedChannelError, message=msg): c1_token_network_proxy.new_netting_channel( partner=c2_client.address, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest", ) assert (c1_token_network_proxy._channel_exists_and_not_settled( participant1=c1_client.address, participant2=c2_client.address, channel_identifier=channel_identifier, block_identifier="latest", ) is True) assert (c1_token_network_proxy.channel_is_opened( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", channel_identifier=channel_identifier, ) is True) msg = "set_total_deposit must fail if the amount exceed the account's balance" with pytest.raises(DepositMismatch, message=msg): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=initial_token_balance + 1, partner=c2_client.address, ) msg = "set_total_deposit must fail with a negative amount" with pytest.raises(DepositMismatch): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=-1, partner=c2_client.address, ) msg = "set_total_deposit must fail with a zero amount" with pytest.raises(DepositMismatch): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=0, partner=c2_client.address, ) c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=10, partner=c2_client.address, ) transferred_amount = 3 balance_proof = BalanceProof( channel_identifier=channel_identifier, token_network_address=to_checksum_address(token_network_address), nonce=1, chain_id=chain_id, transferred_amount=transferred_amount, ) signature = c1_signer.sign(data=balance_proof.serialize_bin()) balance_proof.signature = encode_hex(signature) signature_number = int.from_bytes(signature, "big") bit_to_change = random.randint(0, SIGNATURE_SIZE_IN_BITS - 1) signature_number_bit_flipped = signature_number ^ (2**bit_to_change) invalid_signatures = [ EMPTY_SIGNATURE, b"\x11" * 65, signature_number_bit_flipped.to_bytes(len(signature), "big"), ] msg = "close must fail if the signature is invalid" for invalid_signature in invalid_signatures: with pytest.raises(RaidenUnrecoverableError, message=msg): c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), signature=invalid_signature, given_block_identifier="latest", ) blocknumber_prior_to_close = c2_client.block_number() c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), signature=decode_hex(balance_proof.signature), given_block_identifier="latest", ) assert (c1_token_network_proxy.channel_is_closed( participant1=c1_client.address, participant2=c2_client.address, block_identifier="latest", channel_identifier=channel_identifier, ) is True) assert (c1_token_network_proxy._channel_exists_and_not_settled( participant1=c1_client.address, participant2=c2_client.address, channel_identifier=channel_identifier, block_identifier="latest", ) is True) msg = ( "given_block_identifier is the block at which the transaction is being " "sent. If the channel is already closed at that block the client code " "has a programming error. An exception is raised for that.") with pytest.raises(RaidenUnrecoverableError, message=msg): c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), signature=decode_hex(balance_proof.signature), given_block_identifier="latest", ) msg = ("The channel cannot be closed two times. If it was not closed at " "given_block_identifier but it is closed at the time the proxy is " "called an exception must be raised.") with pytest.raises(RaidenRecoverableError, message=msg): c2_token_network_proxy.close( channel_identifier=channel_identifier, partner=c1_client.address, balance_hash=decode_hex(balance_proof.balance_hash), nonce=balance_proof.nonce, additional_hash=decode_hex(balance_proof.additional_hash), signature=decode_hex(balance_proof.signature), given_block_identifier=blocknumber_prior_to_close, ) msg = "depositing to a closed channel must fail" match = "setTotalDeposit call will fail. Channel is already closed" with pytest.raises(RaidenRecoverableError, message=msg, match=match): c2_token_network_proxy.set_total_deposit( given_block_identifier=blocknumber_prior_to_close, channel_identifier=channel_identifier, total_deposit=20, partner=c1_client.address, ) c1_chain.wait_until_block(target_block_number=c1_chain.block_number() + TEST_SETTLE_TIMEOUT_MIN) invalid_transferred_amount = 1 msg = "settle with invalid transferred_amount data must fail" with pytest.raises(RaidenUnrecoverableError, message=msg): c2_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=invalid_transferred_amount, locked_amount=0, locksroot=EMPTY_HASH, partner=c1_client.address, partner_transferred_amount=transferred_amount, partner_locked_amount=0, partner_locksroot=EMPTY_HASH, given_block_identifier="latest", ) c2_token_network_proxy.settle( channel_identifier=channel_identifier, transferred_amount=0, locked_amount=0, locksroot=EMPTY_HASH, partner=c1_client.address, partner_transferred_amount=transferred_amount, partner_locked_amount=0, partner_locksroot=EMPTY_HASH, given_block_identifier="latest", ) assert (c1_token_network_proxy._channel_exists_and_not_settled( participant1=c1_client.address, participant2=c2_client.address, channel_identifier=channel_identifier, block_identifier="latest", ) is False) assert token_proxy.balance_of(c1_client.address) == (initial_balance_c1 - transferred_amount) assert token_proxy.balance_of(c2_client.address) == (initial_balance_c2 + transferred_amount) msg = "depositing to a settled channel must fail" match = "setTotalDeposit call will fail." with pytest.raises(RaidenUnrecoverableError, message=msg, match=match): c1_token_network_proxy.set_total_deposit( given_block_identifier="latest", channel_identifier=channel_identifier, total_deposit=10, partner=c2_client.address, )
def test_remote_transaction_with_zero_gasprice_is_not_mined( web3: Web3, deploy_key: PrivateKey, blockchain_rpc_ports: List[Port], blockchain_type: str) -> None: """ If the non-local transaction is sent with a gas price set to zero it is not mined. """ host = "127.0.0.1" miner_rpc_port, rpc_port = blockchain_rpc_ports miner_web3 = Web3(HTTPProvider(f"http://{host}:{miner_rpc_port}")) miner_client = JSONRPCClient(miner_web3, deploy_key) web3 = Web3(HTTPProvider(f"http://{host}:{rpc_port}")) client = JSONRPCClient(web3, deploy_key) before_deploy_block = client.block_number() normal_gas_proxy, _ = deploy_rpc_test_contract(client, "RpcTest") num_blocks_to_wait = client.block_number() - before_deploy_block gas_price = GasPrice(0) gas_price_strategy = make_fixed_gas_price_strategy(gas_price) client.web3.eth.setGasPriceStrategy(gas_price_strategy) zero_gas_proxy = client.new_contract_proxy( abi=normal_gas_proxy.contract.abi, contract_address=normal_gas_proxy.contract_address) address = normal_gas_proxy.contract_address assert len(client.web3.eth.getCode(to_checksum_address(address))) > 0 check_block = client.get_checking_block() gas_estimate = zero_gas_proxy.estimate_gas(check_block, "ret") assert gas_estimate, "Gas estimation should not fail here" zerogas_txhash = zero_gas_proxy.transact("ret", gas_estimate) # wait for how many blocks it took to mine the deployment, since this is a # private chain, if the new transaction will be mined it should be roughly # in the same time frame (adding two blocks to cover race conditions) target_block_number = client.block_number() + num_blocks_to_wait + 2 while client.block_number() < target_block_number: gevent.sleep(0.5) miner_zerogas_tx = miner_client.web3.eth.getTransaction(zerogas_txhash) miner_zerogas_receipt = miner_client.web3.eth.getTransactionReceipt( zerogas_txhash) msg = "The transaction was discarded by the miner, there is no transaction and no receipt" assert miner_zerogas_tx is None, msg assert miner_zerogas_receipt is None, msg zerogas_tx = client.web3.eth.getTransaction(zerogas_txhash) zerogas_receipt = client.web3.eth.getTransactionReceipt(zerogas_txhash) msg = ( "The transaction was NOT discarded by the original node, because it is a local transaction" ) assert zerogas_tx is not None, msg zerogas_receipt = client.web3.eth.getTransactionReceipt(zerogas_txhash) msg = "The transaction does NOT have a receipt because the miner rejected it" if blockchain_type == "geth": assert zerogas_receipt is None, msg elif blockchain_type == "parity": assert zerogas_receipt["blockNumber"] is None, msg else: raise RuntimeError(f"Unknown blockchain_type {blockchain_type}")
def test_payment_channel_proxy_basics(token_network_proxy, token_proxy, chain_id, private_keys, web3, contract_manager): token_network_address = token_network_proxy.address partner = privatekey_to_address(private_keys[0]) client = JSONRPCClient(web3, private_keys[1]) proxy_manager = ProxyManager( rpc_client=client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) token_network_proxy = proxy_manager.token_network( address=token_network_address) start_block = web3.eth.blockNumber channel_identifier = token_network_proxy.new_netting_channel( partner=partner, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest") assert channel_identifier is not None channel_proxy_1 = proxy_manager.payment_channel( canonical_identifier=CanonicalIdentifier( chain_identifier=chain_id, token_network_address=token_network_address, channel_identifier=channel_identifier, )) channel_filter = channel_proxy_1.all_events_filter(from_block=start_block, to_block="latest") assert channel_proxy_1.channel_identifier == channel_identifier assert channel_proxy_1.opened("latest") is True # Test deposit initial_token_balance = 100 token_proxy.transfer(client.address, initial_token_balance) assert token_proxy.balance_of(client.address) == initial_token_balance assert token_proxy.balance_of(partner) == 0 channel_proxy_1.set_total_deposit(total_deposit=10, block_identifier="latest") assert len(channel_filter.get_all_entries() ) == 2 # ChannelOpened, ChannelNewDeposit block_before_close = web3.eth.blockNumber empty_balance_proof = BalanceProof( channel_identifier=channel_proxy_1.channel_identifier, token_network_address=token_network_address, balance_hash=encode_hex(EMPTY_BALANCE_HASH), nonce=0, chain_id=chain_id, transferred_amount=0, ) closing_data = (empty_balance_proof.serialize_bin( msg_type=MessageTypeId.BALANCE_PROOF) + EMPTY_SIGNATURE) channel_proxy_1.close( nonce=0, balance_hash=EMPTY_HASH, additional_hash=EMPTY_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=LocalSigner(private_keys[1]).sign(data=closing_data), block_identifier="latest", ) assert channel_proxy_1.closed("latest") is True # ChannelOpened, ChannelNewDeposit, ChannelClosed assert len(channel_filter.get_all_entries()) == 3 # check the settlement timeouts again assert channel_proxy_1.settle_timeout() == TEST_SETTLE_TIMEOUT_MIN # update transfer -- we need to wait on +1 since we use the latest block on parity for # estimate gas and at the time the latest block is the settle timeout block. # More info: https://github.com/raiden-network/raiden/pull/3699#discussion_r270477227 proxy_manager.wait_until_block(target_block_number=client.block_number() + TEST_SETTLE_TIMEOUT_MIN + 1) channel_proxy_1.settle( transferred_amount=0, locked_amount=0, locksroot=LOCKSROOT_OF_NO_LOCKS, partner_transferred_amount=0, partner_locked_amount=0, partner_locksroot=LOCKSROOT_OF_NO_LOCKS, block_identifier="latest", ) assert channel_proxy_1.settled("latest") is True # ChannelOpened, ChannelNewDeposit, ChannelClosed, ChannelSettled assert len(channel_filter.get_all_entries()) == 4 new_channel_identifier = token_network_proxy.new_netting_channel( partner=partner, settle_timeout=TEST_SETTLE_TIMEOUT_MIN, given_block_identifier="latest") assert new_channel_identifier is not None channel_proxy_2 = proxy_manager.payment_channel( canonical_identifier=CanonicalIdentifier( chain_identifier=chain_id, token_network_address=token_network_address, channel_identifier=new_channel_identifier, )) assert channel_proxy_2.channel_identifier == new_channel_identifier assert channel_proxy_2.opened("latest") is True msg = "The channel was already closed, the second call must fail" with pytest.raises(RaidenRecoverableError): channel_proxy_1.close( nonce=0, balance_hash=EMPTY_HASH, additional_hash=EMPTY_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=LocalSigner( private_keys[1]).sign(data=closing_data), block_identifier=block_before_close, ) pytest.fail(msg) msg = "The channel is not open at latest, this must raise" with pytest.raises(RaidenUnrecoverableError): channel_proxy_1.close( nonce=0, balance_hash=EMPTY_HASH, additional_hash=EMPTY_HASH, non_closing_signature=EMPTY_SIGNATURE, closing_signature=LocalSigner( private_keys[1]).sign(data=closing_data), block_identifier="latest", ) pytest.fail(msg) msg = ("The channel was not opened at the provided block (latest). " "This call should never have been attempted.") with pytest.raises(BrokenPreconditionError): channel_proxy_1.set_total_deposit(total_deposit=20, block_identifier="latest") pytest.fail(msg)
def setup_raiden( matrix_server: str, print_step: StepPrinter, contracts_version, eth_rpc_endpoint: str, web3: Web3, base_datadir: Path, keystore: Path, ) -> RaidenTestSetup: print_step("Deploying Raiden contracts") client = JSONRPCClient(web3, get_private_key(keystore)) contract_manager = ContractManager( contracts_precompiled_path(contracts_version)) proxy_manager = ProxyManager( rpc_client=client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) token = deploy_token( deploy_client=client, contract_manager=contract_manager, initial_amount=TokenAmount(1000), decimals=0, token_name="TKN", token_symbol="TKN", token_contract_name=CONTRACT_CUSTOM_TOKEN, ) contract_addresses = deploy_smoketest_contracts( client=client, chain_id=CHAINNAME_TO_ID["smoketest"], contract_manager=contract_manager, token_address=token.address, ) confirmed_block_identifier = client.get_confirmed_blockhash() registry = proxy_manager.token_network_registry( TokenNetworkRegistryAddress( contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY]), block_identifier=confirmed_block_identifier, ) registry.add_token( token_address=TokenAddress(to_canonical_address(token.address)), channel_participant_deposit_limit=TokenAmount(UINT256_MAX), token_network_deposit_limit=TokenAmount(UINT256_MAX), given_block_identifier=confirmed_block_identifier, ) print_step("Setting up Raiden") user_deposit_contract_address = to_checksum_address( contract_addresses[CONTRACT_USER_DEPOSIT]) args = { "address": to_checksum_address(TEST_ACCOUNT_ADDRESS), "datadir": keystore, "eth_rpc_endpoint": eth_rpc_endpoint, "gas_price": "fast", "keystore_path": keystore, "matrix_server": matrix_server, "chain_id": str(CHAINNAME_TO_ID["smoketest"]), "password_file": click.File()(os.path.join(base_datadir, "pw")), "user_deposit_contract_address": user_deposit_contract_address, "sync_check": False, "environment_type": Environment.DEVELOPMENT, } # Wait until the secret registry is confirmed, otherwise the RaidenService # inialization will fail, needed for the check # `check_ethereum_confirmed_block_is_not_pruned`. current_block = client.block_number() target_block_number = current_block + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS while current_block < target_block_number: current_block = client.block_number() sleep(0.5) return RaidenTestSetup(args=args, token=token, contract_addresses=contract_addresses)
def setup_raiden( transport, matrix_server, print_step, contracts_version, eth_client, eth_rpc_endpoint, web3, base_datadir, keystore, ): print_step("Deploying Raiden contracts") if eth_client is EthClient.PARITY: client = JSONRPCClient(web3, get_private_key(keystore), gas_estimate_correction=lambda gas: gas * 2) else: client = JSONRPCClient(web3, get_private_key(keystore)) contract_manager = ContractManager( contracts_precompiled_path(contracts_version)) proxy_manager = ProxyManager( rpc_client=client, contract_manager=contract_manager, metadata=ProxyManagerMetadata( token_network_registry_deployed_at=GENESIS_BLOCK_NUMBER, filters_start_at=GENESIS_BLOCK_NUMBER, ), ) token = deploy_token( deploy_client=client, contract_manager=contract_manager, initial_amount=1000, decimals=0, token_name="TKN", token_symbol="TKN", token_contract_name=CONTRACT_HUMAN_STANDARD_TOKEN, ) contract_addresses = deploy_smoketest_contracts( client=client, chain_id=NETWORKNAME_TO_ID["smoketest"], contract_manager=contract_manager, token_address=to_canonical_address(token.contract.address), ) registry = proxy_manager.token_network_registry( contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY]) registry.add_token( token_address=to_canonical_address(token.contract.address), channel_participant_deposit_limit=UINT256_MAX, token_network_deposit_limit=UINT256_MAX, block_identifier=client.get_confirmed_blockhash(), ) print_step("Setting up Raiden") tokennetwork_registry_contract_address = to_checksum_address( contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY]) secret_registry_contract_address = to_checksum_address( contract_addresses[CONTRACT_SECRET_REGISTRY]) args = { "address": to_checksum_address(TEST_ACCOUNT_ADDRESS), "datadir": keystore, "eth_rpc_endpoint": eth_rpc_endpoint, "gas_price": "fast", "keystore_path": keystore, "matrix_server": matrix_server, "network_id": str(NETWORKNAME_TO_ID["smoketest"]), "password_file": click.File()(os.path.join(base_datadir, "pw")), "tokennetwork_registry_contract_address": tokennetwork_registry_contract_address, "secret_registry_contract_address": secret_registry_contract_address, "sync_check": False, "transport": transport, } service_registry_contract_address = to_checksum_address( contract_addresses[CONTRACT_SERVICE_REGISTRY]) args[ "service_registry_contract_address"] = service_registry_contract_address monitoring_service_contract_address = to_checksum_address( contract_addresses[CONTRACT_MONITORING_SERVICE]) args[ "monitoring_service_contract_address"] = monitoring_service_contract_address one_to_n_contract_address = to_checksum_address( contract_addresses[CONTRACT_ONE_TO_N]) args["one_to_n_contract_address"] = one_to_n_contract_address # Wait until the secret registry is confirmed, otherwise the App # inialization will fail, needed for the check # `check_ethereum_confirmed_block_is_not_pruned`. current_block = client.block_number() target_block_number = current_block + DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS while current_block < target_block_number: current_block = client.block_number() sleep(0.5) return { "args": args, "contract_addresses": contract_addresses, "token": token }