diff --git a/libethereum/Block.cpp b/libethereum/Block.cpp index f9de3c7e7..de58e2406 100644 --- a/libethereum/Block.cpp +++ b/libethereum/Block.cpp @@ -351,8 +351,7 @@ pair< TransactionReceipts, bool > Block::sync( // caller if we hit the limit for ( Transaction& transaction : transactions ) { - transaction.checkOutExternalGas( - _bc.chainParams(), _bc.info().timestamp(), _bc.number(), false ); + transaction.checkOutExternalGas( _bc.chainParams(), _bc.info().timestamp(), _bc.number() ); } assert( _bc.currentHash() == m_currentBlock.parentHash() ); @@ -633,7 +632,7 @@ u256 Block::enact( VerifiedBlockRef const& _block, BlockChain const& _bc ) { // << state().getNonce( tr.from() ) << ") value = " << tr.value() << // endl; const_cast< Transaction& >( tr ).checkOutExternalGas( - _bc.chainParams(), _bc.info().timestamp(), _bc.number(), false ); + _bc.chainParams(), _bc.info().timestamp(), _bc.number() ); execute( _bc.lastBlockHashes(), tr ); // cerr << "Now: " // << "State #" << state().getNonce( tr.from() ) << endl; diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index faf04ec7d..8c01d137f 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -1172,7 +1172,7 @@ h256 Client::importTransaction( Transaction const& _t ) { // We need to check external gas under mutex to be sure about current block number // correctness const_cast< Transaction& >( _t ).checkOutExternalGas( - chainParams(), bc().info().timestamp(), number(), false ); + chainParams(), bc().info().timestamp(), number() ); } Executive::verifyTransaction( _t, bc().info().timestamp(), @@ -1348,7 +1348,7 @@ Json::Value Client::traceBlock( BlockNumber _blockNumber, Json::Value const& _js Transaction tx = transactions.at( k ); auto hashString = toHexPrefixed( tx.sha3() ); transactionLog["txHash"] = hashString; - tx.checkOutExternalGas( chainParams(), bc().info().timestamp(), number(), false ); + tx.checkOutExternalGas( chainParams(), bc().info().timestamp(), number() ); auto tracer = std::make_shared< AlethStandardTrace >( tx, historicBlock.author(), traceOptions ); auto executionResult = diff --git a/libethereum/SchainPatch.cpp b/libethereum/SchainPatch.cpp index f3a5f8daa..fde678f6c 100644 --- a/libethereum/SchainPatch.cpp +++ b/libethereum/SchainPatch.cpp @@ -36,6 +36,8 @@ SchainPatchEnum getEnumForPatchName( const std::string& _patchName ) { return SchainPatchEnum::VerifyBlsSyncPatch; else if ( _patchName == "FlexibleDeploymentPatch" ) return SchainPatchEnum::FlexibleDeploymentPatch; + else if ( _patchName == "ExternalGasPatch" ) + return SchainPatchEnum::ExternalGasPatch; else throw std::out_of_range( _patchName ); } @@ -72,6 +74,8 @@ std::string getPatchNameForEnum( SchainPatchEnum _enumValue ) { return "VerifyBlsSyncPatch"; case SchainPatchEnum::FlexibleDeploymentPatch: return "FlexibleDeploymentPatch"; + case SchainPatchEnum::ExternalGasPatch: + return "ExternalGasPatch"; default: throw std::out_of_range( "UnknownPatch #" + std::to_string( static_cast< size_t >( _enumValue ) ) ); diff --git a/libethereum/SchainPatch.h b/libethereum/SchainPatch.h index 9af149fb9..75f2c878f 100644 --- a/libethereum/SchainPatch.h +++ b/libethereum/SchainPatch.h @@ -146,4 +146,9 @@ DEFINE_AMNESIC_PATCH( VerifyBlsSyncPatch ); */ DEFINE_SIMPLE_PATCH( FlexibleDeploymentPatch ); +/* + * Context: fix externalGas calculation + */ +DEFINE_SIMPLE_PATCH( ExternalGasPatch ); + #endif // SCHAINPATCH_H diff --git a/libethereum/SchainPatchEnum.h b/libethereum/SchainPatchEnum.h index ac0b1c19a..69f023143 100644 --- a/libethereum/SchainPatchEnum.h +++ b/libethereum/SchainPatchEnum.h @@ -20,6 +20,7 @@ enum class SchainPatchEnum { EIP1559TransactionsPatch, VerifyBlsSyncPatch, FlexibleDeploymentPatch, + ExternalGasPatch, PatchesCount }; diff --git a/libethereum/SkaleHost.cpp b/libethereum/SkaleHost.cpp index 47714ebfe..b2d05bd99 100644 --- a/libethereum/SkaleHost.cpp +++ b/libethereum/SkaleHost.cpp @@ -659,7 +659,7 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro if ( m_m_transaction_cache.find( sha.asArray() ) != m_m_transaction_cache.cend() ) { Transaction t = m_m_transaction_cache.at( sha.asArray() ); t.checkOutExternalGas( - m_client.chainParams(), latestInfo.timestamp(), m_client.number(), true ); + m_client.chainParams(), latestInfo.timestamp(), m_client.number() ); out_txns.push_back( t ); LOG( m_debugLogger ) << "Dropping good txn " << sha << std::endl; m_debugTracer.tracepoint( "drop_good" ); @@ -675,7 +675,7 @@ void SkaleHost::createBlock( const ConsensusExtFace::transactions_vector& _appro Transaction t( data, CheckTransaction::Everything, true, EIP1559TransactionsPatch::isEnabledInWorkingBlock() ); t.checkOutExternalGas( - m_client.chainParams(), latestInfo.timestamp(), m_client.number(), false ); + m_client.chainParams(), latestInfo.timestamp(), m_client.number() ); out_txns.push_back( t ); LOG( m_debugLogger ) << "Will import consensus-born txn"; m_debugTracer.tracepoint( "import_consensus_born" ); diff --git a/libethereum/Transaction.cpp b/libethereum/Transaction.cpp index d2c7f9962..eee35a457 100644 --- a/libethereum/Transaction.cpp +++ b/libethereum/Transaction.cpp @@ -195,12 +195,23 @@ u256 Transaction::gasPrice() const { } } -void Transaction::checkOutExternalGas( const ChainParams& _cp, time_t _committedBlockTimestamp, - uint64_t _committedBlockNumber, bool _force ) { +void Transaction::checkOutExternalGas( + const ChainParams& _cp, time_t _committedBlockTimestamp, uint64_t _committedBlockNumber ) { u256 const& difficulty = _cp.externalGasDifficulty; assert( difficulty > 0 ); - if ( ( _force || !m_externalGasIsChecked ) && !isInvalid() ) { - h256 hash = dev::sha3( sender().ref() ) ^ dev::sha3( nonce() ) ^ dev::sha3( gasPrice() ); + if ( !isInvalid() ) { + h256 hash; + if ( !ExternalGasPatch::isEnabledWhen( _committedBlockTimestamp ) ) { + hash = dev::sha3( sender().ref() ) ^ dev::sha3( nonce() ) ^ dev::sha3( gasPrice() ); + } else { + // reset externalGas value + // we may face patch activation after txn was added to the queue but before it was + // executed. therefore we need to recalculate externalGas + m_externalGasIsChecked = false; + m_externalGas.reset(); + hash = dev::sha3( sender().ref() ) ^ dev::sha3( nonce() ) ^ + dev::sha3( TransactionBase::gasPrice() ); + } if ( !hash ) { hash = h256( 1 ); } diff --git a/libethereum/Transaction.h b/libethereum/Transaction.h index 9d3894f31..0f6d5d754 100644 --- a/libethereum/Transaction.h +++ b/libethereum/Transaction.h @@ -122,8 +122,8 @@ class Transaction : public TransactionBase { u256 gasPrice() const; - void checkOutExternalGas( const ChainParams& _cp, time_t _committedBlockTimestamp, - uint64_t _committedBlockNumber, bool _force ); + void checkOutExternalGas( + const ChainParams& _cp, time_t _committedBlockTimestamp, uint64_t _committedBlockNumber ); void ignoreExternalGas() { m_externalGasIsChecked = true; diff --git a/libskale/State.cpp b/libskale/State.cpp index 405eb2c69..3fdfb4e19 100644 --- a/libskale/State.cpp +++ b/libskale/State.cpp @@ -64,6 +64,14 @@ using dev::eth::TransactionReceipt; #define ETH_VMTRACE 0 #endif +const std::map< std::pair< uint64_t, std::string >, uint64_t > State::txnsToSkipExecution{ + { { 1020352220, "3464b9a165a29fde2ce644882e82d99edbff5f530413f6cc18b26bf97e6478fb" }, 40729 }, + { { 1482601649, "d3f25440b752f4ad048b618554f71cec08a73af7bf88b6a7d55581f3a792d823" }, 32151 }, + { { 974399131, "fcd7ecb7c359af0a93a02e5d84957e0c6f90da4584c058e9c5e988b27a237693" }, 23700 }, + { { 1482601649, "6f2074cfe73a258c049ac2222101b7020461c2d40dcd5ab9587d5bbdd13e4c68" }, 55293 }, + { { 21, "95fb5557db8cc6de0aff3a64c18a6d9378b0d312b24f5d77e8dbf5cc0612d74f" }, 23232 } +}; // the last value is for the test + State::State( dev::u256 const& _accountStartNonce, boost::filesystem::path const& _dbPath, dev::h256 const& _genesis, BaseState _bs, dev::u256 _initialFunds, dev::s256 _contractStorageLimit ) @@ -1004,6 +1012,14 @@ bool State::empty() const { return false; } +bool State::ifShouldSkipExecution( uint64_t _chainId, const dev::h256& _hash ) { + return txnsToSkipExecution.count( { _chainId, _hash.hex() } ) > 0; +} + +uint64_t State::getGasUsedForSkippedTransaction( uint64_t _chainId, const dev::h256& _hash ) { + return txnsToSkipExecution.at( { _chainId, _hash.hex() } ); +} + std::pair< ExecutionResult, TransactionReceipt > State::execute( EnvInfo const& _envInfo, eth::ChainOperationParams const& _chainParams, Transaction const& _t, Permanence _p, OnOpFunc const& _onOp ) { @@ -1024,7 +1040,15 @@ std::pair< ExecutionResult, TransactionReceipt > State::execute( EnvInfo const& onOp = e.simpleTrace(); #endif u256 const startGasUsed = _envInfo.gasUsed(); - bool const statusCode = executeTransaction( e, _t, onOp ); + bool statusCodeTmp = false; + if ( _p == Permanence::Committed && ifShouldSkipExecution( _chainParams.chainID, _t.sha3() ) ) { + e.initialize( _t ); + e.execute(); + statusCodeTmp = false; + } else { + statusCodeTmp = executeTransaction( e, _t, onOp ); + } + bool const statusCode = statusCodeTmp; std::string strRevertReason; if ( res.excepted == dev::eth::TransactionException::RevertInstruction ) { @@ -1056,9 +1080,17 @@ std::pair< ExecutionResult, TransactionReceipt > State::execute( EnvInfo const& // shaLastTx.hex() << "\n"; TransactionReceipt receipt = - _envInfo.number() >= _chainParams.byzantiumForkBlock ? - TransactionReceipt( statusCode, startGasUsed + e.gasUsed(), e.logs() ) : - TransactionReceipt( EmptyTrie, startGasUsed + e.gasUsed(), e.logs() ); + TransactionReceipt( statusCode, startGasUsed + e.gasUsed(), e.logs() ); + if ( _p == Permanence::Committed && + ifShouldSkipExecution( _chainParams.chainID, _t.sha3() ) ) { + receipt = TransactionReceipt( statusCode, + startGasUsed + getGasUsedForSkippedTransaction( _chainParams.chainID, _t.sha3() ), + e.logs() ); + } else { + receipt = _envInfo.number() >= _chainParams.byzantiumForkBlock ? + TransactionReceipt( statusCode, startGasUsed + e.gasUsed(), e.logs() ) : + TransactionReceipt( EmptyTrie, startGasUsed + e.gasUsed(), e.logs() ); + } receipt.setRevertReason( strRevertReason ); m_db_ptr->addReceiptToPartials( receipt ); m_fs_ptr->commit(); @@ -1075,9 +1107,16 @@ std::pair< ExecutionResult, TransactionReceipt > State::execute( EnvInfo const& } TransactionReceipt receipt = - _envInfo.number() >= _chainParams.byzantiumForkBlock ? - TransactionReceipt( statusCode, startGasUsed + e.gasUsed(), e.logs() ) : - TransactionReceipt( EmptyTrie, startGasUsed + e.gasUsed(), e.logs() ); + TransactionReceipt( statusCode, startGasUsed + e.gasUsed(), e.logs() ); + if ( _p == Permanence::Committed && ifShouldSkipExecution( _chainParams.chainID, _t.sha3() ) ) { + receipt = TransactionReceipt( statusCode, + startGasUsed + getGasUsedForSkippedTransaction( _chainParams.chainID, _t.sha3() ), + e.logs() ); + } else { + receipt = _envInfo.number() >= _chainParams.byzantiumForkBlock ? + TransactionReceipt( statusCode, startGasUsed + e.gasUsed(), e.logs() ) : + TransactionReceipt( EmptyTrie, startGasUsed + e.gasUsed(), e.logs() ); + } receipt.setRevertReason( strRevertReason ); return make_pair( res, receipt ); diff --git a/libskale/State.h b/libskale/State.h index 94c7118ea..4e8d7b476 100644 --- a/libskale/State.h +++ b/libskale/State.h @@ -450,6 +450,10 @@ class State { } }; + static bool ifShouldSkipExecution( uint64_t _chainId, const dev::h256& _hash ); + + static uint64_t getGasUsedForSkippedTransaction( uint64_t _chainId, const dev::h256& _hash ); + public: bool checkVersion() const; @@ -508,6 +512,8 @@ class State { uint64_t _batchNumber ); #endif + static const std::map< std::pair< uint64_t, std::string >, uint64_t > txnsToSkipExecution; + public: std::shared_ptr< batched_io::db_face > db() { std::shared_ptr< batched_io::db_face > pDB; diff --git a/test/unittests/libethereum/SkaleHost.cpp b/test/unittests/libethereum/SkaleHost.cpp index f4b93ce8d..2091839dd 100644 --- a/test/unittests/libethereum/SkaleHost.cpp +++ b/test/unittests/libethereum/SkaleHost.cpp @@ -900,7 +900,7 @@ BOOST_AUTO_TEST_CASE( transactionDropReceive // 1st tx Transaction tx1 = fixture.tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number(), false ); + tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number() ); // submit it! tq->import( tx1 ); @@ -964,7 +964,7 @@ BOOST_AUTO_TEST_CASE( transactionDropQueue, // 1st tx Transaction tx1 = fixture.tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number(), false ); + tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number() ); // submit it! tq->import( tx1 ); @@ -1025,7 +1025,7 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPrice // 1st tx Transaction tx1 = fixture.tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number(), false ); + tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number() ); // submit it! tq->import( tx1 ); @@ -1094,7 +1094,7 @@ BOOST_AUTO_TEST_CASE( transactionDropByGasPriceReceive // 1st tx Transaction tx1 = fixture.tx_from_json( json ); - tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number(), false ); + tx1.checkOutExternalGas( client->chainParams(), client->latestBlock().info().timestamp(), client->number() ); // receive it! skaleHost->receiveTransaction( toJS( tx1.toBytes() ) ); diff --git a/test/unittests/libweb3jsonrpc/jsonrpc.cpp b/test/unittests/libweb3jsonrpc/jsonrpc.cpp index 09e05dced..1aa4a02a8 100644 --- a/test/unittests/libweb3jsonrpc/jsonrpc.cpp +++ b/test/unittests/libweb3jsonrpc/jsonrpc.cpp @@ -1987,6 +1987,182 @@ BOOST_AUTO_TEST_CASE( simplePoWTransaction ) { BOOST_REQUIRE_EQUAL(receipt["status"], "0x1"); } +BOOST_AUTO_TEST_CASE( recalculateExternalGas ) { + std::string _config = c_genesisConfigString; + Json::Value ret; + Json::Reader().parse( _config, ret ); + + // Set chainID = 21 + std::string chainID = "0x15"; + ret["params"]["chainID"] = chainID; + + // remove deployment control + auto accounts = ret["accounts"]; + accounts.removeMember( "0xD2002000000000000000000000000000000000D2" ); + ret["accounts"] = accounts; + + // setup patch + time_t externalGasPatchActivationTimestamp = time(nullptr) + 10; + ret["skaleConfig"]["sChain"]["ExternalGasPatchTimestamp"] = externalGasPatchActivationTimestamp; + + Json::FastWriter fastWriter; + std::string config = fastWriter.write( ret ); + JsonRpcFixture fixture( config, true, false ); + dev::eth::simulateMining( *( fixture.client ), 20 ); + + auto senderAddress = fixture.coinbase.address().hex(); + +// // SPDX-License-Identifier: GPL-3.0 + +// pragma solidity >=0.8.2 <0.9.0; + +// /** +// * @title Storage +// * @dev Store & retrieve value in a variable +// * @custom:dev-run-script ./scripts/deploy_with_ethers.ts +// */ +// contract Storage { + +// uint256 number; +// uint256 number1; +// uint256 number2; + +// /** +// * @dev Store value in variable +// * @param num value to store +// */ +// function store(uint256 num) public { +// number = num; +// number1 = num; +// number2 = num; +// } + +// /** +// * @dev Return value +// * @return value of 'number' +// */ +// function retrieve() public view returns (uint256){ +// return number; +// } +// } + std::string bytecode = "608060405234801561001057600080fd5b5061015e806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100e7565b60405180910390f35b610073600480360381019061006e91906100ab565b61007e565b005b60008054905090565b80600081905550806001819055508060028190555050565b6000813590506100a581610111565b92915050565b6000602082840312156100c1576100c061010c565b5b60006100cf84828501610096565b91505092915050565b6100e181610102565b82525050565b60006020820190506100fc60008301846100d8565b92915050565b6000819050919050565b600080fd5b61011a81610102565b811461012557600080fd5b5056fea2646970667358221220780703bb6ac2eec922a510d57edcae39b852b578e7f63a263ddb936758dc9c4264736f6c63430008070033"; + + // deploy contact + Json::Value create; + create["from"] = senderAddress; + create["code"] = bytecode; + create["gasPrice"] = fixture.rpcClient->eth_gasPrice(); + create["gas"] = 140000; + create["nonce"] = 0; + + std::string txHash = fixture.rpcClient->eth_sendTransaction( create ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + Json::Value receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash ); + BOOST_REQUIRE( receipt["status"].asString() == "0x1" ); + std::string contractAddress = receipt["contractAddress"].asString(); + + // send txn to a contract from the suspicious account + // store( 4 ) + Json::Value txn; + txn["from"] = "0x40797bb29d12FC0dFD04277D16a3Dd4FAc3a6e5B"; + txn["data"] = "0x6057361d0000000000000000000000000000000000000000000000000000000000000004"; + txn["gasPrice"] = "0xdffe55527a88d3775c23ecd3ae38ff1e90caf12b5beb4f7ea3ad998a990a895c"; + txn["gas"] = 140000; + txn["chainId"] = "0x15"; + txn["nonce"] = 0; + txn["to"] = contractAddress; + + auto ts = toTransactionSkeleton( txn ); + auto t = dev::eth::Transaction( ts, dev::Secret( "7be24de049f2d0d4ecaeaa81564aecf647fa7a4c86264243d77e01da25d859a0" ) ); + + txHash = fixture.rpcClient->eth_sendRawTransaction( dev::toHex( t.toBytes() ) ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash ); + + BOOST_REQUIRE( receipt["status"].asString() == "0x0" ); + BOOST_REQUIRE( receipt["gasUsed"].asString() == "0x61cb" ); + + sleep(10); + + // push new block to update timestamp + Json::Value refill; + refill["from"] = senderAddress; + refill["to"] = dev::Address::random().hex(); + refill["gasPrice"] = fixture.rpcClient->eth_gasPrice(); + refill["value"] = 100; + refill["nonce"] = 1; + + txHash = fixture.rpcClient->eth_sendTransaction( refill ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + + // send txn to a contract from another suspicious account + // store( 4 ) + txn["from"] = "0x5cdb7527ec85022991D4e27F254C438E8337ad7E"; + txn["data"] = "0x6057361d0000000000000000000000000000000000000000000000000000000000000004"; + txn["gasPrice"] = "0x974749a06d5cd0dba6a4e1f3d14d5f480db716dcbc9a34ec5496b8d86e99f898"; + txn["gas"] = 140000; + txn["chainId"] = "0x15"; + txn["nonce"] = 0; + txn["to"] = contractAddress; + + ts = toTransactionSkeleton( txn ); + t = dev::eth::Transaction( ts, dev::Secret( "8df08814fcfc169aad0015654114be06c28b27bdcdef286cf4dbd5e2950a3ffc" ) ); + + txHash = fixture.rpcClient->eth_sendRawTransaction( dev::toHex( t.toBytes() ) ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash ); + + BOOST_REQUIRE( receipt["status"].asString() == "0x1" ); + BOOST_REQUIRE( receipt["gasUsed"].asString() == "0x13ef4" ); +} + +BOOST_AUTO_TEST_CASE( skipTransactionExecution ) { + std::string _config = c_genesisConfigString; + Json::Value ret; + Json::Reader().parse( _config, ret ); + + // Set chainID = 21 + std::string chainID = "0x15"; + ret["params"]["chainID"] = chainID; + + Json::FastWriter fastWriter; + std::string config = fastWriter.write( ret ); + JsonRpcFixture fixture( config ); + dev::eth::simulateMining( *( fixture.client ), 20 ); + + auto senderAddress = fixture.coinbase.address().hex(); + + Json::Value refill; + refill["from"] = senderAddress; + refill["to"] = "0x5EdF1e852fdD1B0Bc47C0307EF755C76f4B9c251"; + refill["gasPrice"] = fixture.rpcClient->eth_gasPrice(); + refill["value"] = 1000000000000000; + refill["nonce"] = 0; + + std::string txHash = fixture.rpcClient->eth_sendTransaction( refill ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + + // send txn and verify that gas used is correct + // gas used value is hardcoded in State::txnsToSkipExecution + Json::Value txn; + txn["from"] = "0x5EdF1e852fdD1B0Bc47C0307EF755C76f4B9c251"; + txn["gasPrice"] = "0x4a817c800"; + txn["gas"] = 40000; + txn["chainId"] = "0x15"; + txn["nonce"] = 0; + txn["value"] = 1; + txn["to"] = "0x5cdb7527ec85022991D4e27F254C438E8337ad7E"; + + auto ts = toTransactionSkeleton( txn ); + auto t = dev::eth::Transaction( ts, dev::Secret( "08cee1f4bc8c37f88124bb3fc64566ccd35dbeeac84c62300f6b8809cab9ea2f" ) ); + + txHash = fixture.rpcClient->eth_sendRawTransaction( dev::toHex( t.toBytes() ) ); + BOOST_REQUIRE( txHash == "0x95fb5557db8cc6de0aff3a64c18a6d9378b0d312b24f5d77e8dbf5cc0612d74f" ); + dev::eth::mineTransaction( *( fixture.client ), 1 ); + Json::Value receipt = fixture.rpcClient->eth_getTransactionReceipt( txHash ); + BOOST_REQUIRE( receipt["gasUsed"].asString() == "0x5ac0" ); +} + BOOST_AUTO_TEST_CASE( transactionWithoutFunds ) { JsonRpcFixture fixture; dev::eth::simulateMining( *( fixture.client ), 1 ); @@ -2924,7 +3100,7 @@ BOOST_AUTO_TEST_CASE( powTxnGasLimit ) { txPOW2["gasPrice"] = "0xc5002ab03e1e7e196b3d0ffa9801e783fcd48d4c6d972f1389ab63f4e2d0bef0"; // gas 1m txPOW2["value"] = 100; BOOST_REQUIRE_THROW( fixture.rpcClient->eth_sendTransaction( txPOW2 ), jsonrpc::JsonRpcException ); // block gas limit reached - } +} BOOST_AUTO_TEST_CASE( EIP1898Calls ) { JsonRpcFixture fixture;