def new_sharding_transaction(tx_initiator, data_destination, data_value, data_msgdata, data_vrs, code='', salt=b'\x00' * 32, gas=1000000, access_list=None): """ Create and return a sharding transaction. Data will be encoded in the following order [destination, value, msg_data, vrs]. """ assert len(data_vrs) in (0, 65) tx_data = (pad32(data_destination) + pad32(bytes([data_value])) + pad32(data_msgdata) + pad32(data_vrs[:32]) + pad32(data_vrs[32:64]) + bytes(data_vrs[64:])) if access_list is None: access_list = [[tx_initiator]] if data_destination: access_list.append([data_destination]) return ShardingTransaction( chain_id=1, shard_id=1, to=tx_initiator, data=tx_data, gas=gas, access_list=access_list, code=decode_hex(code), salt=salt, )
def test_get_nonce(vm): computation, _ = vm.apply_transaction(ShardingTransaction(**merge(DEFAULT_BASE_TX_PARAMS, { "data": int_to_big_endian(NONCE_GETTER_ID), }))) assert computation.output == pad32(b"\x00") computation, _ = vm.apply_transaction(SIGNED_DEFAULT_TRANSACTION) computation, _ = vm.apply_transaction(ShardingTransaction(**merge(DEFAULT_BASE_TX_PARAMS, { "data": int_to_big_endian(NONCE_GETTER_ID), }))) assert computation.output == pad32(b"\x01")
def ecmul(computation): computation.gas_meter.consume_gas(constants.GAS_ECMUL, reason='ECMUL Precompile') try: result = _ecmull(computation.msg.data) except ValidationError: raise VMError("Invalid ECMUL parameters") result_x, result_y = result result_bytes = b''.join(( pad32(int_to_big_endian(result_x.n)), pad32(int_to_big_endian(result_y.n)), )) computation.output = result_bytes return computation
def ecmul(computation): computation.consume_gas(constants.GAS_ECMUL, reason='ECMUL Precompile') try: result = _ecmull(computation.msg.data) except ValidationError: raise VMError("Invalid ECMUL parameters") result_x, result_y = result result_bytes = b''.join(( pad32(int_to_big_endian(result_x.n)), pad32(int_to_big_endian(result_y.n)), )) computation.output = result_bytes return computation
def precompile_ecrecover(computation): computation.gas_meter.consume_gas(constants.GAS_ECRECOVER, reason="ECRecover Precompile") raw_message_hash = computation.msg.data[:32] message_hash = pad32r(raw_message_hash) v_bytes = pad32r(computation.msg.data[32:64]) v = big_endian_to_int(v_bytes) r_bytes = pad32r(computation.msg.data[64:96]) r = big_endian_to_int(r_bytes) s_bytes = pad32r(computation.msg.data[96:128]) s = big_endian_to_int(s_bytes) try: validate_lt_secpk1n(r) validate_lt_secpk1n(s) validate_lte(v, 28) validate_gte(v, 27) except ValidationError: return computation try: raw_public_key = ecdsa_raw_recover(message_hash, (v, r, s)) except ValueError: return computation public_key = encode_raw_public_key(raw_public_key) address = public_key_to_address(public_key) padded_address = pad32(address) computation.output = padded_address return computation
def ecrecover(computation): computation.gas_meter.consume_gas(constants.GAS_ECRECOVER, reason="ECRecover Precompile") raw_message_hash = computation.msg.data[:32] message_hash = pad32r(raw_message_hash) v_bytes = pad32r(computation.msg.data[32:64]) v = big_endian_to_int(v_bytes) r_bytes = pad32r(computation.msg.data[64:96]) r = big_endian_to_int(r_bytes) s_bytes = pad32r(computation.msg.data[96:128]) s = big_endian_to_int(s_bytes) try: validate_lt_secpk1n(r, title="ECRecover: R") validate_lt_secpk1n(s, title="ECRecover: S") validate_lte(v, 28, title="ECRecover: V") validate_gte(v, 27, title="ECRecover: V") except ValidationError: return computation canonical_v = v - 27 try: signature = keys.Signature(vrs=(canonical_v, r, s)) public_key = signature.recover_public_key_from_msg_hash(message_hash) except BadSignature: return computation address = public_key.to_canonical_address() padded_address = pad32(address) computation.output = padded_address return computation
def hash(self) -> bytes: header_hash = keccak( b''.join(( int_to_bytes32(self.shard_id), int_to_bytes32(self.expected_period_number), self.period_start_prevhash, self.parent_hash, self.transaction_root, pad32(self.coinbase), self.state_root, self.receipt_root, int_to_bytes32(self.number), )) ) # Hash of Collation header is the right most 26 bytes of `sha3(header)` # It's padded to 32 bytes because `bytes32` is easier to handle in Vyper return pad32(header_hash[6:])
async def test_shard_syncer(n_peers, connections): cancel_token = CancelToken("canceltoken") PeerTuple = collections.namedtuple("PeerTuple", ["node", "server", "syncer"]) peer_tuples = [] for i in range(n_peers): private_key = keys.PrivateKey(pad32(int_to_big_endian(i + 1))) port = get_open_port() address = Address("127.0.0.1", port, port) node = Node(private_key.public_key, address) server = ShardingServer(private_key, address, network_id=9324090483, min_peers=0, peer_class=ShardingPeer) asyncio.ensure_future(server.run()) peer_tuples.append( PeerTuple( node=node, server=server, syncer=server.syncer, )) # connect peers to each other await asyncio.gather(*[ peer_tuples[i].server.peer_pool._connect_to_nodes( [peer_tuples[j].node]) for i, j in connections ]) for i, j in connections: peer_remotes = [ peer.remote for peer in peer_tuples[i].server.peer_pool.peers ] assert peer_tuples[j].node in peer_remotes # let each node propose and check that collation appears at all other nodes for proposer in peer_tuples: collation = proposer.syncer.propose() await asyncio.wait_for(asyncio.gather(*[ peer_tuple.syncer.collations_received_event.wait() for peer_tuple in peer_tuples if peer_tuple != proposer ]), timeout=10) for peer_tuple in peer_tuples: assert peer_tuple.syncer.shard.get_collation_by_hash( collation.hash) == collation # stop everything cancel_token.trigger() await asyncio.gather( *[peer_tuple.server.cancel() for peer_tuple in peer_tuples]) await asyncio.gather( *[peer_tuple.syncer.cancel() for peer_tuple in peer_tuples])
def ripemd160(computation): word_count = ceil32(len(computation.msg.data)) // 32 gas_fee = constants.GAS_RIPEMD160 + word_count * constants.GAS_RIPEMD160WORD computation.gas_meter.consume_gas(gas_fee, reason="RIPEMD160 Precompile") # TODO: this only works if openssl is installed. hash = hashlib.new('ripemd160', computation.msg.data).digest() padded_hash = pad32(hash) computation.output = padded_hash return computation
def ecpairing(computation): if len(computation.msg.data) % 192: # data length must be an exact multiple of 192 raise VMError("Invalid ECPAIRING parameters") num_points = len(computation.msg.data) // 192 gas_fee = constants.GAS_ECPAIRING_BASE + num_points * constants.GAS_ECPAIRING_PER_POINT computation.gas_meter.consume_gas(gas_fee, reason='ECPAIRING Precompile') try: result = _ecpairing(computation.msg.data) except ValidationError: raise VMError("Invalid ECPAIRING parameters") if result is True: computation.output = pad32(b'\x01') elif result is False: computation.output = pad32(b'\x00') else: raise Exception("Invariant: unreachable code path") return computation
def encode_for_smc(self) -> bytes: encoded = b"".join([ int_to_bytes32(self.shard_id), self.chunk_root, int_to_bytes32(self.period), pad32(self.proposer_address), ]) if len(encoded) != self.smc_encoded_size: raise ValueError("Encoded header size is {} instead of {} bytes".format( len(encoded), self.smc_encoded_size, )) return encoded
def ecpairing(computation): if len(computation.msg.data) % 192: # data length must be an exact multiple of 192 raise VMError("Invalid ECPAIRING parameters") num_points = len(computation.msg.data) // 192 gas_fee = constants.GAS_ECPAIRING_BASE + num_points * constants.GAS_ECPAIRING_PER_POINT computation.consume_gas(gas_fee, reason='ECPAIRING Precompile') try: result = _ecpairing(computation.msg.data) except ValidationError: raise VMError("Invalid ECPAIRING parameters") if result is True: computation.output = pad32(b'\x01') elif result is False: computation.output = pad32(b'\x00') else: raise Exception("Invariant: unreachable code path") return computation
def get_storage(self, address, slot): validate_canonical_address(address) validate_uint256(slot) account = self._get_account(address) storage = StateTrie(Trie(self.db, account.storage_root)) slot_as_key = pad32(int_to_big_endian(slot)) if slot_as_key in storage: encoded_value = storage[slot_as_key] return rlp.decode(encoded_value, sedes=rlp.sedes.big_endian_int) else: return 0
def get_storage(self, address, slot): validate_canonical_address(address, title="Storage Address") validate_uint256(slot, title="Storage Slot") account = self._get_account(address) storage = HashTrie(HexaryTrie(self._journaldb, account.storage_root)) slot_as_key = pad32(int_to_big_endian(slot)) if slot_as_key in storage: encoded_value = storage[slot_as_key] return rlp.decode(encoded_value, sedes=rlp.sedes.big_endian_int) else: return 0
def assemble_data_field(user_account_transaction, include_signature=True): if include_signature: signature = b"".join([ pad32(int_to_big_endian(user_account_transaction.v)), pad32(int_to_big_endian(user_account_transaction.r)), pad32(int_to_big_endian(user_account_transaction.s)), ]) else: signature = b"" return b''.join([ signature, pad32(int_to_big_endian(user_account_transaction.nonce)), pad32(int_to_big_endian(user_account_transaction.int_gas_price)), pad32(int_to_big_endian(user_account_transaction.value)), pad32(int_to_big_endian(user_account_transaction.min_block)), pad32(int_to_big_endian(user_account_transaction.max_block)), pad32(user_account_transaction.destination), user_account_transaction.msg_data, ])
def hash(self) -> bytes: header_hash = keccak( b''.join(( int_to_bytes32(self.shard_id), int_to_bytes32(self.expected_period_number), self.period_start_prevhash, self.parent_hash, self.transaction_root, pad32(self.coinbase), self.state_root, self.receipt_root, int_to_bytes32(self.number), )) ) return header_hash
def set_storage(self, address, slot, value): validate_uint256(value, title="Storage Value") validate_uint256(slot, title="Storage Slot") validate_canonical_address(address, title="Storage Address") account = self._get_account(address) storage = HashTrie(HexaryTrie(self._journaldb, account.storage_root)) slot_as_key = pad32(int_to_big_endian(slot)) if value: encoded_value = rlp.encode(value) storage[slot_as_key] = encoded_value else: del storage[slot_as_key] self._set_account(address, account.copy(storage_root=storage.root_hash))
def set_storage(self, address, slot, value): validate_uint256(value) validate_uint256(slot) validate_canonical_address(address) account = self._get_account(address) storage = StateTrie(Trie(self.db, account.storage_root)) slot_as_key = pad32(int_to_big_endian(slot)) if value: encoded_value = rlp.encode(value) storage[slot_as_key] = encoded_value else: del storage[slot_as_key] account.storage_root = storage.root_hash self._set_account(address, account)
def test_sharding_apply_transaction(unvalidated_shard_chain): # noqa: F811 chain = unvalidated_shard_chain CREATE2_contracts = json.load( open(os.path.join(DIR, '../contract_fixtures/CREATE2_contracts.json'))) simple_transfer_contract = CREATE2_contracts["simple_transfer_contract"] CREATE2_contract = CREATE2_contracts["CREATE2_contract"] simple_factory_contract_bytecode = CREATE2_contracts[ "simple_factory_contract"]["bytecode"] # First test: simple ether transfer contract first_deploy_tx = new_sharding_transaction( tx_initiator=decode_hex(simple_transfer_contract['address']), data_destination=b'', data_value=0, data_msgdata=b'', data_vrs=b'', code=simple_transfer_contract['bytecode'], ) vm = chain.get_vm() computation, _ = vm.apply_transaction(first_deploy_tx) assert not computation.is_error gas_used = vm.block.header.gas_used assert gas_used > first_deploy_tx.intrinsic_gas last_gas_used = gas_used # Transfer ether to recipient recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 tx_initiator = decode_hex(simple_transfer_contract['address']) transfer_tx = new_sharding_transaction(tx_initiator, recipient, amount, b'', b'') computation, _ = vm.apply_transaction(transfer_tx) assert not computation.is_error gas_used = vm.block.header.gas_used - last_gas_used assert gas_used > transfer_tx.intrinsic_gas last_gas_used = vm.block.header.gas_used with vm.state.state_db(read_only=True) as state_db: assert state_db.get_balance(recipient) == amount # Second test: contract that deploy new contract with CREATE2 second_deploy_tx = new_sharding_transaction( tx_initiator=decode_hex(CREATE2_contract['address']), data_destination=b'', data_value=0, data_msgdata=b'', data_vrs=b'', code=CREATE2_contract['bytecode'], ) computation, _ = vm.apply_transaction(second_deploy_tx) assert not computation.is_error gas_used = vm.block.header.gas_used - last_gas_used assert gas_used > second_deploy_tx.intrinsic_gas last_gas_used = vm.block.header.gas_used # Invoke the contract to deploy new contract tx_initiator = decode_hex(CREATE2_contract['address']) newly_deployed_contract_address = generate_CREATE2_contract_address( int_to_big_endian(0), decode_hex(simple_factory_contract_bytecode)) invoke_tx = new_sharding_transaction( tx_initiator, b'', 0, b'', b'', access_list=[[tx_initiator, pad32(b'')], [newly_deployed_contract_address]]) computation, _ = vm.apply_transaction(invoke_tx) assert not computation.is_error gas_used = vm.block.header.gas_used - last_gas_used assert gas_used > invoke_tx.intrinsic_gas with vm.state.state_db(read_only=True) as state_db: newly_deployed_contract_address = generate_CREATE2_contract_address( int_to_big_endian(0), decode_hex(simple_factory_contract_bytecode)) assert state_db.get_code( newly_deployed_contract_address) == b'\xbe\xef' assert state_db.get_storage(decode_hex(CREATE2_contract['address']), 0) == 1
def generate_privkey(): """Generate a new SECP256K1 private key and return it""" privkey = ec.generate_private_key(CURVE, default_backend()) return keys.PrivateKey(pad32(int_to_big_endian(privkey.private_numbers().private_value)))
def generate_random_keypair(): key_object = keys.PrivateKey( pad32(int_to_big_endian(random.getrandbits(8 * 32)))) return key_object.to_bytes(), key_object.public_key.to_canonical_address()
def generate_privkey() -> datatypes.PrivateKey: """Generate a new SECP256K1 private key and return it""" privkey = ec.generate_private_key(CURVE, default_backend()) return keys.PrivateKey( pad32(int_to_big_endian(privkey.private_numbers().private_value)))
def get_storage_key(address, slot): return keccak(address) + STORAGE_TRIE_PREFIX + pad32(int_to_big_endian(slot))
def generate_random_keypair_and_address() -> Tuple[PrivateKey, PublicKey, Address]: priv_key = keys.PrivateKey(pad32(int_to_big_endian(random.getrandbits(8 * 32)))) return priv_key, priv_key.public_key, Address(priv_key.public_key.to_canonical_address())
def test_pad_32(value, expected): assert pad32(value) == expected
def test_contract_with_no_nonce_tracking( unvalidated_shard_chain): # noqa: F811 chain = unvalidated_shard_chain vm = chain.get_vm() no_nonce_tracking_contract = nonce_tracking_contracts[ "no_nonce_tracking_contract"] no_nonce_tracking_contract_address = decode_hex( no_nonce_tracking_contract['address']) deploy_tx = new_sharding_transaction( tx_initiator=no_nonce_tracking_contract_address, data_destination=b'', data_value=0, data_msgdata=b'', data_vrs=b'', code=no_nonce_tracking_contract['bytecode'], ) computation, _ = vm.apply_transaction(deploy_tx) assert not computation.is_error gas_used = vm.block.header.gas_used assert gas_used > deploy_tx.intrinsic_gas last_gas_used = gas_used # Trigger the contract recipient = b'' nonce = 0 tx_initiator = no_nonce_tracking_contract_address gas_price = 10 vrs = 64 * b'\xAA' + b'\x01' access_list = [[tx_initiator, pad32(b'\x00')]] trigger_tx = new_sharding_transaction( tx_initiator, recipient, nonce, bytes([gas_price]), vrs, access_list=access_list, ) with vm.state.state_db(read_only=True) as state_db: balance_before_trigger = state_db.get_balance( no_nonce_tracking_contract_address) computation, _ = vm.apply_transaction(trigger_tx) assert not computation.is_error gas_used = vm.block.header.gas_used - last_gas_used assert gas_used > trigger_tx.intrinsic_gas last_gas_used = vm.block.header.gas_used with vm.state.state_db(read_only=True) as state_db: assert state_db.get_balance( tx_initiator) == balance_before_trigger - gas_used * gas_price # Replay the same transaciton with vm.state.state_db(read_only=True) as state_db: balance_before_trigger = state_db.get_balance( no_nonce_tracking_contract_address) computation, _ = vm.apply_transaction(trigger_tx) assert not computation.is_error gas_used = vm.block.header.gas_used - last_gas_used assert gas_used > trigger_tx.intrinsic_gas last_gas_used = vm.block.header.gas_used with vm.state.state_db(read_only=True) as state_db: # Check that fee is charged since there's no replay protection assert state_db.get_balance( tx_initiator) == balance_before_trigger - gas_used * gas_price