def decode(cls, data): packed = messages.wrap(data) if packed is None: return None # signature must be at the end message_type = type(packed) signature = message_type.fields_spec[-1] assert signature.name == 'signature', 'signature is not the last field' message_data = data[:-signature.size_bytes] message_signature = data[-signature.size_bytes:] message_hash = sha3(message_data) data_that_was_signed = pack_signing_data( message_type.get_bytes_from(data, 'nonce'), message_type.get_bytes_from(data, 'transferred_amount'), # Locked amount should get signed when smart contracts change to include it # message_type.get_bytes_from(data, 'locked_amount'), message_type.get_bytes_from(data, 'channel'), message_type.get_bytes_from(data, 'locksroot'), message_hash, ) address = signing.recover_address(data_that_was_signed, message_signature) if address is None: return None message = cls.unpack(packed) # pylint: disable=no-member message.sender = address return message
def decode(cls, data): packed = messages.wrap(data) if packed is None: return None # signature must be at the end message_type = type(packed) signature = message_type.fields_spec[-1] assert signature.name == 'signature', 'signature is not the last field' message_data = data[:-signature.size_bytes] message_signature = data[-signature.size_bytes:] message_hash = sha3(message_data) data_that_was_signed = pack_signing_data( message_type.get_bytes_from(data, 'nonce'), message_type.get_bytes_from(data, 'transferred_amount'), message_type.get_bytes_from(data, 'channel'), message_type.get_bytes_from(data, 'locksroot'), message_hash, ) publickey = recover_publickey_safe(data_that_was_signed, message_signature) if publickey is None: return None message = cls.unpack(packed) # pylint: disable=no-member message.sender = publickey_to_address(publickey) return message
def make_signed_balance_proof( nonce, transferred_amount, locked_amount, token_network_address, channel_address, locksroot, extra_hash, private_key, sender_address, ): data_to_sign = balance_proof.signing_data( nonce, transferred_amount, locked_amount, channel_address, locksroot, extra_hash, ) balance_hash = hash_balance_data( transferred_amount, locked_amount, locksroot, ) data_to_sign = balance_proof.pack_signing_data( nonce=nonce, balance_hash=balance_hash, additional_hash=extra_hash, channel_identifier=channel_address, token_network_identifier=token_network_address, chain_id=UNIT_CHAIN_ID, ) signature = signing.sign(data_to_sign, private_key) signed_balance_proof = BalanceProofSignedState( nonce, transferred_amount, locked_amount, locksroot, token_network_address, channel_address, extra_hash, signature, sender_address, UNIT_CHAIN_ID, ) return signed_balance_proof
def _data_to_sign(self) -> bytes: balance_hash = hash_balance_data( self.transferred_amount, self.locked_amount, self.locksroot, ) balance_proof_packed = pack_signing_data( nonce=self.nonce, balance_hash=balance_hash, additional_hash=self.message_hash, channel_identifier=self.channel_identifier, token_network_identifier=self.token_network_address, chain_id=self.chain_id, ) return balance_proof_packed
def _data_to_sign(self) -> bytes: balance_hash = hash_balance_data( self.transferred_amount, self.locked_amount, self.locksroot, ) balance_proof_packed = pack_signing_data( nonce=self.nonce, balance_hash=balance_hash, additional_hash=self.message_hash, channel_identifier=self.channel, token_network_identifier=self.token_network_address, chain_id=self.chain_id, ) return balance_proof_packed
def data_to_sign(self): """ Returns an encoded subset of the fields to sign """ packed = self.packed() klass = type(packed) field = klass.fields_spec[-1] assert field.name == 'signature', 'signature is not the last field' data = packed.data return pack_signing_data( klass.get_bytes_from(data, 'nonce'), klass.get_bytes_from(data, 'transferred_amount'), klass.get_bytes_from(data, 'locked_amount'), klass.get_bytes_from(data, 'channel'), klass.get_bytes_from(data, 'locksroot'), self.message_hash, )
def sign(self, private_key, node_address): packed = self.packed() klass = type(packed) field = klass.fields_spec[-1] assert field.name == 'signature', 'signature is not the last field' data = packed.data data_to_sign = pack_signing_data( klass.get_bytes_from(data, 'nonce'), klass.get_bytes_from(data, 'transferred_amount'), klass.get_bytes_from(data, 'channel'), klass.get_bytes_from(data, 'locksroot'), self.message_hash, ) signature = signing.sign(data_to_sign, private_key) packed.signature = signature self.sender = node_address self.signature = signature
def find_max_pending_transfers(gas_limit): """Measure gas consumption of TokenNetwork.unlock() depending on number of pending transfers and find the maximum number of pending transfers so gas_limit is not exceeded.""" tester = ContractTester(generate_keys=2) tester.deploy_contract('SecretRegistry') tester.deploy_contract( 'HumanStandardToken', _initialAmount=100000, _decimalUnits=3, _tokenName='SomeToken', _tokenSymbol='SMT', ) tester.deploy_contract( 'TokenNetwork', _token_address=tester.contract_address('HumanStandardToken'), _secret_registry=tester.contract_address('SecretRegistry'), _chain_id=1, _settlement_timeout_min=100, _settlement_timeout_max=200, ) tester.call_transaction( 'HumanStandardToken', 'transfer', _to=tester.accounts[1], _value=10000, ) receipt = tester.call_transaction( 'TokenNetwork', 'openChannel', participant1=tester.accounts[0], participant2=tester.accounts[1], settle_timeout=150, ) channel_identifier = receipt['logs'][0]['topics'][1] tester.call_transaction( 'HumanStandardToken', 'approve', sender=tester.accounts[0], _spender=tester.contract_address('TokenNetwork'), _value=10000, ) tester.call_transaction( 'HumanStandardToken', 'approve', sender=tester.accounts[1], _spender=tester.contract_address('TokenNetwork'), _value=5000, ) tester.call_transaction( 'TokenNetwork', 'setTotalDeposit', participant=tester.accounts[0], total_deposit=5000, partner=tester.accounts[1], ) tester.call_transaction( 'TokenNetwork', 'setTotalDeposit', participant=tester.accounts[1], total_deposit=2000, partner=tester.accounts[0], ) print( "Measuring unlock()'s gas cost for different Merkle tree widths, can take a while..." ) before_closing = tester.tester.take_snapshot() enough = 0 too_much = 1024 nonce = 10 additional_hash = urandom(32) token_network_identifier = tester.contract_address('TokenNetwork') while enough + 1 < too_much: tree_size = (enough + too_much) // 2 tester.tester.revert_to_snapshot(before_closing) pending_transfers_tree = get_pending_transfers_tree( tester.web3, unlockable_amounts=[1] * tree_size, ) balance_hash = hash_balance_data(3000, 2000, pending_transfers_tree.merkle_root) data_to_sign = pack_signing_data( nonce, balance_hash, additional_hash, channel_identifier, token_network_identifier, 1, ) signature = sign(data_to_sign, tester.private_keys[1]) tester.call_transaction( 'TokenNetwork', 'closeChannel', partner=tester.accounts[1], balance_hash=balance_hash, nonce=nonce, additional_hash=additional_hash, signature=signature, ) tester.tester.mine_blocks(160) # close settlement window tester.call_transaction( 'TokenNetwork', 'settleChannel', participant1=tester.accounts[0], participant1_transferred_amount=0, participant1_locked_amount=0, participant1_locksroot=b'\x00' * 32, participant2=tester.accounts[1], participant2_transferred_amount=3000, participant2_locked_amount=2000, participant2_locksroot=pending_transfers_tree.merkle_root, ) receipt = tester.call_transaction( 'TokenNetwork', 'unlock', participant=tester.accounts[0], partner=tester.accounts[1], merkle_tree_leaves=pending_transfers_tree.packed_transfers, ) gas_used = receipt['gasUsed'] if gas_used <= gas_limit: enough = tree_size print( f'{tree_size} pending transfers work ({gas_used} gas needed to unlock)' ) else: too_much = tree_size print( f'{tree_size} pending transfers are too much ({gas_used} gas needed to unlock)' )