def test_PAYGAS_zero_gas_price(unvalidated_shard_chain): # noqa: F811 # Case 2: PAYGAS triggered with 0 gas price chain = unvalidated_shard_chain vm = chain.get_vm() PAYGAS_contract_normal = PAYGAS_contracts["PAYGAS_contract_normal"] PAYGAS_contract_address = decode_hex(PAYGAS_contract_normal['address']) normal_PAYGAS_contract_deploy_tx = new_sharding_transaction( tx_initiator=PAYGAS_contract_address, data_destination=b'', data_value=0, data_msgdata=b'', data_vrs=b'', code=PAYGAS_contract_normal['bytecode'], ) computation, _ = vm.apply_transaction(normal_PAYGAS_contract_deploy_tx) assert not computation.is_error # Trigger the PAYGAS contract with gas price set to 0 recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 tx_initiator = PAYGAS_contract_address gas_price = bytes([0]) vrs = 64 * b'\xAA' + b'\x01' trigger_tx = new_sharding_transaction(tx_initiator, recipient, amount, gas_price, vrs) with vm.state.state_db(read_only=True) as state_db: balance_before_trigger = state_db.get_balance(PAYGAS_contract_address) computation, _ = vm.apply_transaction(trigger_tx) assert not computation.is_error with vm.state.state_db(read_only=True) as state_db: # Check that balance of the contract is the same except the amount transfered assert balance_before_trigger == state_db.get_balance( PAYGAS_contract_address) + amount
def test_PAYGAS_triggered_twice(unvalidated_shard_chain): # noqa: F811 # Case 4: PAYGAS triggered twice chain = unvalidated_shard_chain vm = chain.get_vm() PAYGAS_contract_triggered_twice = PAYGAS_contracts[ "PAYGAS_contract_triggered_twice"] PAYGAS_contract_address = decode_hex( PAYGAS_contract_triggered_twice['address']) PAYGAS_triggered_twice_deploy_tx = new_sharding_transaction( tx_initiator=PAYGAS_contract_address, data_destination=b'', data_value=0, data_msgdata=b'', data_vrs=b'', code=PAYGAS_contract_triggered_twice['bytecode'], ) computation, _ = vm.apply_transaction(PAYGAS_triggered_twice_deploy_tx) assert not computation.is_error # Trigger the PAYGAS contract which will trigger PAYGAS twice # First time with gas_price specified in transaction data # Second time with 10*gas_price recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 tx_initiator = PAYGAS_contract_address gas_price = 33 vrs = 64 * b'\xAA' + b'\x01' trigger_tx = new_sharding_transaction( tx_initiator, recipient, amount, bytes([gas_price]), vrs, ) last_gas_used = vm.block.header.gas_used with vm.state.state_db(read_only=True) as state_db: balance_before_trigger = state_db.get_balance(PAYGAS_contract_address) recipient_balance_before_trigger = state_db.get_balance(recipient) computation, _ = vm.apply_transaction(trigger_tx) assert not computation.is_error gas_used = vm.block.header.gas_used - last_gas_used with vm.state.state_db(read_only=True) as state_db: # Check that PAYGAS account is charged with normal gas_price instead of 10*gas_price tx_fee = gas_used * gas_price balance_after_trigger = state_db.get_balance( PAYGAS_contract_address) + tx_fee + amount assert balance_before_trigger == balance_after_trigger assert state_db.get_balance( recipient) == recipient_balance_before_trigger + amount
def test_CREATE2_deploy_contract_edge_cases( unvalidated_shard_chain): # noqa: F811 CREATE2_contracts = json.load( open(os.path.join(DIR, '../contract_fixtures/CREATE2_contracts.json'))) simple_transfer_contract = CREATE2_contracts["simple_transfer_contract"] # First case: computed contract address not the same as provided in `transaction.to` chain = unvalidated_shard_chain code = "0xf3" computed_address = generate_CREATE2_contract_address(b"", decode_hex(code)) first_failed_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=code, access_list=[[decode_hex(simple_transfer_contract['address'])], [computed_address]]) vm = chain.get_vm() computation, _ = vm.apply_transaction(first_failed_deploy_tx) assert isinstance(computation._error, IncorrectContractCreationAddress) gas_used = vm.block.header.gas_used assert gas_used > first_failed_deploy_tx.intrinsic_gas last_gas_used = gas_used # Next, complete deploying the contract successful_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'], ) computation, _ = vm.apply_transaction(successful_deploy_tx) assert not computation.is_error gas_used = vm.block.header.gas_used - last_gas_used assert gas_used > successful_deploy_tx.intrinsic_gas last_gas_used = gas_used # Second case: deploy to existing account second_failed_deploy_tx = successful_deploy_tx computation, _ = vm.apply_transaction(second_failed_deploy_tx) assert isinstance(computation._error, ContractCreationCollision) gas_used = vm.block.header.gas_used - last_gas_used assert gas_used > second_failed_deploy_tx.intrinsic_gas
def test_trigger_PAYGAS(unvalidated_shard_chain): # noqa: F811 chain = unvalidated_shard_chain vm = chain.get_vm() PAYGAS_contract_normal = PAYGAS_contracts["PAYGAS_contract_normal"] simple_forwarder_contract = PAYGAS_contracts["simple_forwarder_contract"] PAYGAS_contract_address = decode_hex(PAYGAS_contract_normal['address']) deploy_tx = new_sharding_transaction( tx_initiator=PAYGAS_contract_address, data_destination=b'', data_value=0, data_msgdata=b'', data_vrs=b'', code=PAYGAS_contract_normal['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 = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 0 tx_initiator = PAYGAS_contract_address gas_price = 33 vrs = 64 * b'\xAA' + b'\x01' trigger_tx = new_sharding_transaction( tx_initiator, recipient, amount, bytes([gas_price]), vrs, ) with vm.state.state_db(read_only=True) as state_db: balance_before_trigger = state_db.get_balance( decode_hex(simple_forwarder_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 assert state_db.get_balance(recipient) == amount
def test_PAYGAS_not_triggered(unvalidated_shard_chain): # noqa: F811 # Case 1: PAYGAS not triggered chain = unvalidated_shard_chain vm = chain.get_vm() simple_forwarder_contract = PAYGAS_contracts["simple_forwarder_contract"] forwarder_contract_address = decode_hex( simple_forwarder_contract['address']) forwarder_contract_deploy_tx = new_sharding_transaction( tx_initiator=forwarder_contract_address, data_destination=b'', data_value=0, data_msgdata=b'', data_vrs=b'', code=simple_forwarder_contract['bytecode'], ) computation, _ = vm.apply_transaction(forwarder_contract_deploy_tx) assert not computation.is_error # Trigger the forwarder contract which does not have PAYGAS opcode recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 0 tx_initiator = forwarder_contract_address gas_price = bytes([0]) vrs = 64 * b'\xAA' + b'\x01' trigger_tx = new_sharding_transaction(tx_initiator, recipient, amount, gas_price, vrs) with vm.state.state_db(read_only=True) as state_db: balance_before_trigger = state_db.get_balance( forwarder_contract_address) computation, _ = vm.apply_transaction(trigger_tx) assert not computation.is_error with vm.state.state_db(read_only=True) as state_db: # Check that balance of the contract is the same assert balance_before_trigger == state_db.get_balance( forwarder_contract_address)
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
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 test_PAYGAS_not_in_top_level_call(unvalidated_shard_chain): # noqa: F811 # Case 3: PAYGAS is not triggered in a top level call chain = unvalidated_shard_chain vm = chain.get_vm() PAYGAS_contract_normal = PAYGAS_contracts["PAYGAS_contract_normal"] simple_forwarder_contract = PAYGAS_contracts["simple_forwarder_contract"] # Use the forwarder contract to make the call to PAYGAS contract # Order: forwarder -> PAYGAS contract -> recipient forwarder_address = decode_hex(simple_forwarder_contract['address']) forwarder_contract_deploy_tx = new_sharding_transaction( tx_initiator=forwarder_address, data_destination=b'', data_value=0, data_msgdata=b'', data_vrs=b'', code=simple_forwarder_contract['bytecode'], ) computation, _ = vm.apply_transaction(forwarder_contract_deploy_tx) assert not computation.is_error PAYGAS_contract_address = decode_hex(PAYGAS_contract_normal['address']) normal_PAYGAS_contract_deploy_tx = new_sharding_transaction( tx_initiator=PAYGAS_contract_address, data_destination=b'', data_value=0, data_msgdata=b'', data_vrs=b'', code=PAYGAS_contract_normal['bytecode'], ) computation, _ = vm.apply_transaction(normal_PAYGAS_contract_deploy_tx) assert not computation.is_error recipient = decode_hex('0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c') amount = 100 tx_initiator = forwarder_address vrs = 64 * b'\xAA' + b'\x01' access_list = [[tx_initiator], [recipient], [PAYGAS_contract_address]] trigger_tx = new_sharding_transaction(tx_initiator, PAYGAS_contract_address, amount, recipient, vrs, access_list=access_list) with vm.state.state_db(read_only=True) as state_db: PAYGAS_balance_before_trigger = state_db.get_balance( PAYGAS_contract_address) forwarder_balance_before_trigger = state_db.get_balance( forwarder_address) recipient_balance_before_trigger = state_db.get_balance(recipient) computation, _ = vm.apply_transaction(trigger_tx) assert not computation.is_error with vm.state.state_db(read_only=True) as state_db: # Check that balance of these accounts are the same except the amount transfered assert PAYGAS_balance_before_trigger == state_db.get_balance( PAYGAS_contract_address) assert forwarder_balance_before_trigger == state_db.get_balance( forwarder_address) + amount assert state_db.get_balance( recipient) == recipient_balance_before_trigger + amount