def deploy_contract_web3( contract_name: str, deploy_client: JSONRPCClient, num_confirmations: int = None, constructor_arguments: typing.Tuple[typing.Any, ...] = (), ) -> typing.Address: contract_interface = CONTRACT_MANAGER.get_contract(contract_name) contract = deploy_client.web3.eth.contract( abi=contract_interface['abi'], bytecode=contract_interface['bin'], ) transaction = contract.constructor( *constructor_arguments).buildTransaction() transaction['nonce'] = deploy_client.nonce() signed_txn = deploy_client.web3.eth.account.signTransaction( transaction, deploy_client.privkey, ) tx_hash = deploy_client.web3.eth.sendRawTransaction( signed_txn.rawTransaction) deploy_client.poll(transaction_hash=tx_hash, confirmations=num_confirmations) receipt = deploy_client.get_transaction_receipt(tx_hash) if receipt.get('status', 0) == 0: raise RuntimeError('contract was not sucessfully deployed') return typing.Address( unhexlify(remove_0x_prefix(receipt['contractAddress'])), )
def get_all_netting_channel_events( chain: BlockChainService, token_network_address: TokenNetworkAddress, netting_channel_identifier: ChannelID, contract_manager: ContractManager, from_block: BlockSpecification = GENESIS_BLOCK_NUMBER, to_block: BlockSpecification = 'latest', ) -> List[Dict]: """ Helper to get all events of a NettingChannelContract. """ filter_args = get_filter_args_for_all_events_from_channel( token_network_address=token_network_address, channel_identifier=netting_channel_identifier, contract_manager=contract_manager, from_block=from_block, to_block=to_block, ) return get_contract_events( chain, contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), typing.Address(token_network_address), filter_args['topics'], from_block, to_block, )
def __init__( self, jsonrpc_client, token_network_address: typing.TokenNetworkAddress, contract_manager: ContractManager, ): if not is_binary_address(token_network_address): raise InvalidAddress( 'Expected binary address format for token nework') check_address_has_code( jsonrpc_client, typing.Address(token_network_address), CONTRACT_TOKEN_NETWORK, ) self.contract_manager = contract_manager proxy = jsonrpc_client.new_contract_proxy( self.contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), to_normalized_address(token_network_address), ) compare_contract_versions( proxy=proxy, expected_version=contract_manager.contracts_version, contract_name=CONTRACT_TOKEN_NETWORK, address=typing.Address(token_network_address), ) self.address = token_network_address self.proxy = proxy self.client = jsonrpc_client self.node_address = privatekey_to_address(self.client.privkey) self.open_channel_transactions = dict() # Forbids concurrent operations on the same channel self.channel_operations_lock = defaultdict(RLock) # Serializes concurent deposits on this token network. This must be an # exclusive lock, since we need to coordinate the approve and # setTotalDeposit calls. self.deposit_lock = Semaphore()
def address_checksum_and_decode(addr: str) -> typing.Address: """ Accepts a string address and turns it into binary. Makes sure that the string address provided starts is 0x prefixed and checksummed according to EIP55 specification """ if not is_0x_prefixed(addr): raise InvalidAddress('Address must be 0x prefixed') if not is_checksum_address(addr): raise InvalidAddress('Address must be EIP55 checksummed') addr_bytes = decode_hex(addr) assert len(addr_bytes) in (20, 0) return typing.Address(addr_bytes)
def deploy_contract_web3( contract_name: str, deploy_client: JSONRPCClient, contract_manager: ContractManager, constructor_arguments: typing.Tuple[typing.Any, ...] = (), ) -> typing.Address: compiled = { contract_name: contract_manager.get_contract(contract_name), } contract_proxy = deploy_client.deploy_solidity_contract( contract_name, compiled, constructor_parameters=constructor_arguments, ) return typing.Address(to_canonical_address(contract_proxy.contract.address))
def deploy_contract_web3( contract_name: str, deploy_client: JSONRPCClient, num_confirmations: int = None, constructor_arguments: typing.Tuple[typing.Any, ...] = (), ) -> typing.Address: compiled = { contract_name: CONTRACT_MANAGER.get_contract(contract_name), } contract_proxy = deploy_client.deploy_solidity_contract( contract_name, compiled, constructor_parameters=constructor_arguments, confirmations=num_confirmations, ) return typing.Address(to_canonical_address( contract_proxy.contract.address))
def deploy_contract_web3( contract_name: str, deploy_client: JSONRPCClient, *args, ) -> typing.Address: manager = ContractManager(CONTRACTS_SOURCE_DIRS) contract_interface = manager.abi[contract_name] tx_hash = deploy_client.send_transaction( to=typing.Address(b''), data=contract_interface['bin'], ) tx_hash = unhexlify(tx_hash) deploy_client.poll(tx_hash) receipt = deploy_client.get_transaction_receipt(tx_hash) contract_address = receipt['contractAddress'] return to_canonical_address(contract_address)
def handle_inittarget( state_change: ActionInitTarget, channel_state: NettingChannelState, pseudo_random_generator: random.Random, block_number: typing.BlockNumber, ): """ Handles an ActionInitTarget state change. """ transfer = state_change.transfer route = state_change.route assert channel_state.identifier == transfer.balance_proof.channel_identifier is_valid, channel_events, errormsg = channel.handle_receive_lockedtransfer( channel_state, transfer, ) if is_valid: # A valid balance proof does not mean the payment itself is still valid. # e.g. the lock may be near expiration or have expired. This is fine. The # message with an unusable lock must be handled to properly synchronize the # local view of the partner's channel state, allowing the next balance # proofs to be handled. This however, must only be done once, which is # enforced by the nonce increasing sequentially, which is verified by # the handler handle_receive_lockedtransfer. target_state = TargetTransferState(route, transfer) safe_to_wait, _ = is_safe_to_wait( transfer.lock.expiration, channel_state.reveal_timeout, block_number, ) # If there is not enough time to safely unlock the lock on-chain # silently let the transfer expire. The target task must be created to # handle the ReceiveLockExpired state change, which will clear the # expired lock. if safe_to_wait: message_identifier = message_identifier_from_prng( pseudo_random_generator) recipient = transfer.initiator secret_request = SendSecretRequest( recipient=typing.Address(recipient), channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE, message_identifier=message_identifier, payment_identifier=transfer.payment_identifier, amount=transfer.lock.amount, expiration=transfer.lock.expiration, secrethash=transfer.lock.secrethash, ) channel_events.append(secret_request) iteration = TransitionResult(target_state, channel_events) else: # If the balance proof is not valid, do *not* create a task. Otherwise it's # possible for an attacker to send multiple invalid transfers, and increase # the memory usage of this Node. unlock_failed = EventUnlockClaimFailed( identifier=transfer.payment_identifier, secrethash=transfer.lock.secrethash, reason=errormsg, ) channel_events.append(unlock_failed) iteration = TransitionResult(None, channel_events) return iteration
def make_address() -> typing.Address: return typing.Address(make_20bytes())
def publickey_to_address(publickey: bytes) -> typing.Address: return typing.Address(sha3(publickey[1:])[12:])
def deploy_solidity_contract( self, # pylint: disable=too-many-locals contract_name: str, all_contracts: typing.Dict[str, typing.ABI], libraries: typing.Dict[str, typing.Address] = None, constructor_parameters: typing.Tuple[typing.Any] = None, contract_path: str = None, ): """ Deploy a solidity contract. Args: contract_name: The name of the contract to compile. all_contracts: The json dictionary containing the result of compiling a file. libraries: A list of libraries to use in deployment. constructor_parameters: A tuple of arguments to pass to the constructor. contract_path: If we are dealing with solc >= v0.4.9 then the path to the contract is a required argument to extract the contract data from the `all_contracts` dict. """ if libraries: libraries = dict(libraries) else: libraries = dict() constructor_parameters = constructor_parameters or list() all_contracts = copy.deepcopy(all_contracts) if contract_name in all_contracts: contract_key = contract_name elif contract_path is not None: contract_key = os.path.basename( contract_path) + ':' + contract_name if contract_key not in all_contracts: raise ValueError('Unknown contract {}'.format(contract_name)) else: raise ValueError( 'Unknown contract {} and no contract_path given'.format( contract_name), ) contract = all_contracts[contract_key] contract_interface = contract['abi'] symbols = solidity_unresolved_symbols(contract['bin']) if symbols: available_symbols = list( map(solidity_library_symbol, all_contracts.keys())) unknown_symbols = set(symbols) - set(available_symbols) if unknown_symbols: msg = 'Cannot deploy contract, known symbols {}, unresolved symbols {}.'.format( available_symbols, unknown_symbols, ) raise Exception(msg) dependencies = deploy_dependencies_symbols(all_contracts) deployment_order = dependencies_order_of_build( contract_key, dependencies) deployment_order.pop() # remove `contract_name` from the list log.debug( 'Deploying dependencies: {}'.format(str(deployment_order)), node=pex(self.address), ) for deploy_contract in deployment_order: dependency_contract = all_contracts[deploy_contract] hex_bytecode = solidity_resolve_symbols( dependency_contract['bin'], libraries) bytecode = decode_hex(hex_bytecode) dependency_contract['bin'] = bytecode gas_limit = self.web3.eth.getBlock( 'latest')['gasLimit'] * 8 // 10 transaction_hash = self.send_transaction( to=typing.Address(b''), startgas=gas_limit, data=bytecode, ) self.poll(transaction_hash) receipt = self.get_transaction_receipt(transaction_hash) contract_address = receipt['contractAddress'] # remove the hexadecimal prefix 0x from the address contract_address = remove_0x_prefix(contract_address) libraries[deploy_contract] = contract_address deployed_code = self.web3.eth.getCode( to_checksum_address(contract_address)) if not deployed_code: raise RuntimeError( 'Contract address has no code, check gas usage.') hex_bytecode = solidity_resolve_symbols(contract['bin'], libraries) bytecode = decode_hex(hex_bytecode) contract['bin'] = bytecode if isinstance(contract['bin'], str): contract['bin'] = decode_hex(contract['bin']) if not constructor_parameters: constructor_parameters = () contract = self.web3.eth.contract(abi=contract['abi'], bytecode=contract['bin']) contract_transaction = contract.constructor( *constructor_parameters).buildTransaction() transaction_hash = self.send_transaction( to=typing.Address(b''), data=contract_transaction['data'], startgas=contract_transaction['gas'], ) self.poll(transaction_hash) receipt = self.get_transaction_receipt(transaction_hash) contract_address = receipt['contractAddress'] deployed_code = self.web3.eth.getCode( to_checksum_address(contract_address)) if not deployed_code: raise RuntimeError( 'Deployment of {} failed. Contract address has no code, check gas usage.' .format(contract_name, ), ) return self.new_contract_proxy( contract_interface, contract_address, )
def handle_secretrequest( initiator_state: InitiatorTransferState, state_change: ReceiveSecretRequest, channel_state: NettingChannelState, pseudo_random_generator: random.Random, ) -> TransitionResult: is_message_from_target = ( state_change.sender == initiator_state.transfer_description.target and state_change.secrethash == initiator_state.transfer_description.secrethash and state_change.payment_identifier == initiator_state.transfer_description.payment_identifier) lock = channel.get_lock( channel_state.our_state, initiator_state.transfer_description.secrethash, ) already_received_secret_request = initiator_state.received_secret_request is_valid_secretrequest = (state_change.amount == initiator_state.transfer_description.amount and state_change.expiration == lock.expiration) if already_received_secret_request and is_message_from_target: # A secret request was received earlier, all subsequent are ignored # as it might be an attack iteration = TransitionResult(initiator_state, list()) elif is_valid_secretrequest and is_message_from_target: # Reveal the secret to the target node and wait for its confirmation. # At this point the transfer is not cancellable anymore as either the lock # timeouts or a secret reveal is received. # # Note: The target might be the first hop # message_identifier = message_identifier_from_prng( pseudo_random_generator) transfer_description = initiator_state.transfer_description recipient = transfer_description.target revealsecret = SendSecretReveal( recipient=typing.Address(recipient), channel_identifier=CHANNEL_IDENTIFIER_GLOBAL_QUEUE, message_identifier=message_identifier, secret=transfer_description.secret, ) initiator_state.revealsecret = revealsecret initiator_state.received_secret_request = True iteration = TransitionResult(initiator_state, [revealsecret]) elif not is_valid_secretrequest and is_message_from_target: cancel = EventPaymentSentFailed( payment_network_identifier=channel_state. payment_network_identifier, token_network_identifier=channel_state.token_network_identifier, identifier=initiator_state.transfer_description.payment_identifier, target=initiator_state.transfer_description.target, reason='bad secret request message from target', ) initiator_state.received_secret_request = True iteration = TransitionResult(initiator_state, [cancel]) else: iteration = TransitionResult(initiator_state, list()) return iteration