Skip to content

Commit

Permalink
SKALED-1600 Use correct fork in gas estimation
Browse files Browse the repository at this point in the history
  • Loading branch information
dimalit authored Dec 12, 2023
2 parents 2fcb104 + 885fb52 commit f7c560a
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 20 deletions.
3 changes: 2 additions & 1 deletion libethereum/ClientBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ std::pair< u256, ExecutionResult > ClientBase::estimateGas( Address const& _from
int64_t upperBound = _maxGas;
if ( upperBound == Invalid256 || upperBound > c_maxGasEstimate )
upperBound = c_maxGasEstimate;
int64_t lowerBound = Transaction::baseGasRequired( !_dest, &_data, EVMSchedule() );
int64_t lowerBound = Transaction::baseGasRequired( !_dest, &_data,
bc().sealEngine()->chainParams().scheduleForBlockNumber( bc().number() ) );
Block bk = latestBlock();
if ( upperBound > bk.info().gasLimit() ) {
upperBound = bk.info().gasLimit().convert_to< int64_t >();
Expand Down
5 changes: 4 additions & 1 deletion libweb3jsonrpc/EthFace.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class EthFace : public ServerInterface< EthFace > {
jsonrpc::JSON_OBJECT, NULL ),
&dev::rpc::EthFace::eth_syncingI );
this->bindAndAddMethod( jsonrpc::Procedure( "eth_estimateGas", jsonrpc::PARAMS_BY_POSITION,
jsonrpc::JSON_STRING, "param1", jsonrpc::JSON_OBJECT, NULL ),
jsonrpc::JSON_STRING, NULL ),
&dev::rpc::EthFace::eth_estimateGasI );
this->bindAndAddMethod( jsonrpc::Procedure( "eth_chainId", jsonrpc::PARAMS_BY_POSITION,
jsonrpc::JSON_STRING, NULL ),
Expand Down Expand Up @@ -419,6 +419,9 @@ class EthFace : public ServerInterface< EthFace > {
response = this->eth_syncing();
}
inline virtual void eth_estimateGasI( const Json::Value& request, Json::Value& response ) {
if ( !request.isArray() || request.empty() )
BOOST_THROW_EXCEPTION(
jsonrpc::JsonRpcException( jsonrpc::Errors::ERROR_RPC_INVALID_PARAMS ) );
response = this->eth_estimateGas( request[0u] );
}
inline virtual void eth_chainIdI( const Json::Value& request, Json::Value& response ) {
Expand Down
42 changes: 36 additions & 6 deletions test/unittests/libethereum/ClientTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,11 @@ static std::string const c_configString = R"(
"allowFutureBlocks": true,
"homesteadForkBlock": "0x00",
"EIP150ForkBlock": "0x00",
"EIP158ForkBlock": "0x00"
"EIP158ForkBlock": "0x00",
"byzantiumForkBlock": "0x00",
"constantinopleForkBlock": "0x00",
"constantinopleFixForkBlock": "0x00",
"istanbulForkBlock": "0x00"
},
"genesis": {
"nonce": "0x0000000000000042",
Expand Down Expand Up @@ -375,6 +379,7 @@ static std::string const c_genesisInfoSkaleTest = std::string() +
"byzantiumForkBlock": "0x00",
"constantinopleForkBlock": "0x00",
"constantinopleFixForkBlock": "0x00",
"istanbulForkBlock": "0x00",
"networkID" : "12313219",
"chainID": "0x01",
"maximumExtraDataSize": "0x20",
Expand Down Expand Up @@ -439,6 +444,25 @@ static std::string const c_genesisInfoSkaleTest = std::string() +

BOOST_AUTO_TEST_SUITE( EstimateGas )

BOOST_AUTO_TEST_CASE( transactionWithData ) {
TestClientFixture fixture( c_genesisInfoSkaleTest );
ClientTest* testClient = asClientTest( fixture.ethereum() );

dev::eth::simulateMining( *( fixture.ethereum() ), 10 );

Address addr( "0xca4409573a5129a72edf85d6c51e26760fc9c903" );

bytes data =
jsToBytes( "0x11223344556600770000" );

u256 estimate = testClient
->estimateGas( addr, 0, addr, data, 10000000, 1000000,
GasEstimationCallback() )
.first;

BOOST_CHECK_EQUAL( estimate, u256( 21000+7*16+3*4 ) );
}

BOOST_AUTO_TEST_CASE( constantConsumption ) {
TestClientFixture fixture( c_genesisInfoSkaleTest );
ClientTest* testClient = asClientTest( fixture.ethereum() );
Expand Down Expand Up @@ -475,7 +499,8 @@ BOOST_AUTO_TEST_CASE( constantConsumption ) {
GasEstimationCallback() )
.first;

BOOST_CHECK_EQUAL( estimate, u256( 71800 ) );
// 71488 checked in reall call under Istanbul fork
BOOST_CHECK_EQUAL( estimate, u256( 71488 ) );
}

BOOST_AUTO_TEST_CASE( linearConsumption ) {
Expand Down Expand Up @@ -513,7 +538,7 @@ BOOST_AUTO_TEST_CASE( linearConsumption ) {
GasEstimationCallback() )
.first;

BOOST_CHECK_EQUAL( estimate, u256( 2367016 ) );
BOOST_CHECK_EQUAL( estimate, u256( 2366934 ) );
}

BOOST_AUTO_TEST_CASE( exceedsGasLimit ) {
Expand Down Expand Up @@ -589,7 +614,7 @@ BOOST_AUTO_TEST_CASE( runsInterference ) {
GasEstimationCallback() )
.first;

BOOST_CHECK_EQUAL( estimate, u256( 41684 ) );
BOOST_CHECK_EQUAL( estimate, u256( 41424 ) );
}

BOOST_AUTO_TEST_CASE( consumptionWithRefunds ) {
Expand Down Expand Up @@ -810,7 +835,7 @@ BOOST_AUTO_TEST_CASE( consumptionWithReverts ) {
GasEstimationCallback() )
.first;

BOOST_CHECK_EQUAL( estimate, u256( 121944 ) );
BOOST_CHECK_EQUAL( estimate, u256( 121632 ) );
}

BOOST_AUTO_TEST_SUITE_END()
Expand All @@ -829,6 +854,7 @@ static std::string const c_genesisInfoSkaleIMABLSPublicKeyTest = std::string() +
"byzantiumForkBlock": "0x00",
"constantinopleForkBlock": "0x00",
"constantinopleFixForkBlock": "0x00",
"istanbulForkBlock": "0x00",
"networkID" : "12313219",
"chainID": "0x01",
"maximumExtraDataSize": "0x20",
Expand Down Expand Up @@ -953,7 +979,11 @@ static std::string const c_skaleConfigString = R"E(
"allowFutureBlocks": true,
"homesteadForkBlock": "0x00",
"EIP150ForkBlock": "0x00",
"EIP158ForkBlock": "0x00"
"EIP158ForkBlock": "0x00",
"byzantiumForkBlock": "0x00",
"constantinopleForkBlock": "0x00",
"constantinopleFixForkBlock": "0x00",
"istanbulForkBlock": "0x00"
},
"genesis": {
"nonce": "0x0000000000000042",
Expand Down
4 changes: 3 additions & 1 deletion test/unittests/libweb3jsonrpc/WebThreeStubClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,9 +396,11 @@ std::string WebThreeStubClient::eth_sendTransaction( const Json::Value& param1 )
jsonrpc::Errors::ERROR_CLIENT_INVALID_RESPONSE, result.toStyledString() );
}

std::string WebThreeStubClient::eth_estimateGas( const Json::Value& param1 ) {
std::string WebThreeStubClient::eth_estimateGas( const Json::Value& param1, const std::string& param2 ) {
Json::Value p;
p.append( param1 );
if(!param2.empty())
p.append( param2 );
Json::Value result = this->CallMethod( "eth_estimateGas", p );
if ( result.isString() )
return result.asString();
Expand Down
2 changes: 1 addition & 1 deletion test/unittests/libweb3jsonrpc/WebThreeStubClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class WebThreeStubClient : public jsonrpc::Client {
std::string eth_call( const Json::Value& param1, const std::string& param2 ) noexcept( false );
std::string eth_callEIP1898( const Json::Value& param1, const Json::Value& param2 ) noexcept( false );
bool eth_flush() noexcept( false );
std::string eth_estimateGas( const Json::Value& param1 ) noexcept( false );
std::string eth_estimateGas( const Json::Value& param1, const std::string& param2 = "" ) noexcept( false );
Json::Value eth_getBlockByHash( const std::string& param1, bool param2 ) noexcept( false );
Json::Value eth_getBlockByNumber( const std::string& param1, bool param2 ) noexcept( false );
Json::Value eth_getTransactionByHash( const std::string& param1 ) noexcept( false );
Expand Down
45 changes: 35 additions & 10 deletions test/unittests/libweb3jsonrpc/jsonrpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ static std::string const c_genesisConfigString =
"EIP158ForkBlock": "0x00",
"byzantiumForkBlock": "0x00",
"constantinopleForkBlock": "0x00",
"istanbulForkBlock": "0x00",
"skaleDisableChainIdCheck": true,
"externalGasDifficulty": "0x1"
},
Expand Down Expand Up @@ -280,6 +281,7 @@ struct JsonRpcFixture : public TestOutputHelperFixture {
chainParams.byzantiumForkBlock = 0;
chainParams.EIP158ForkBlock = 0;
chainParams.constantinopleForkBlock = 0;
chainParams.istanbulForkBlock = 0;
chainParams.externalGasDifficulty = 1;
chainParams.sChain.contractStorageLimit = 128;
// 615 + 1430 is experimentally-derived block size + average extras size
Expand Down Expand Up @@ -1263,7 +1265,11 @@ BOOST_AUTO_TEST_CASE( eth_estimateGas ) {
testPositive["to"] = "0xD2001300000000000000000000000000000000D4";
testPositive["data"] = "0xfdde8d66000000000000000000000000000000000000000000000000000000000000c350";
response = fixture.rpcClient->eth_estimateGas( testPositive );
BOOST_CHECK( response == "0x1dc58" );
string response2 = fixture.rpcClient->eth_estimateGas( testPositive, "latest" );
string response3 = fixture.rpcClient->eth_estimateGas( testPositive, "1" );
BOOST_CHECK_EQUAL( response, "0x1db20" );
BOOST_CHECK_EQUAL( response2, "0x1db20" );
BOOST_CHECK_EQUAL( response3, "0x1db20" );
}

BOOST_AUTO_TEST_CASE( eth_sendRawTransaction_gasLimitExceeded ) {
Expand Down Expand Up @@ -1596,22 +1602,26 @@ BOOST_AUTO_TEST_CASE( transactionWithoutFunds ) {
string balanceString = fixture.rpcClient->eth_getBalance( toJS( address2 ), "latest" );
BOOST_REQUIRE_EQUAL( toJS( 0 ), balanceString );

Json::Value transact;
transact["from"] = toJS( address2 );
transact["to"] = contractAddress;
transact["data"] = "0x15b2eec30000000000000000000000000000000000000000000000000000000000000003";

string gasEstimateStr = fixture.rpcClient->eth_estimateGas(transact);
u256 gasEstimate = jsToU256(gasEstimateStr);

u256 powGasPrice = 0;
do {
const u256 GAS_PER_HASH = 1;
u256 candidate = h256::random();
h256 hash = dev::sha3( address2 ) ^ dev::sha3( u256( 0 ) ) ^ dev::sha3( candidate );
u256 externalGas = ~u256( 0 ) / u256( hash ) * GAS_PER_HASH;
if ( externalGas >= 21000 + 21000 ) {
if ( externalGas >= gasEstimate && externalGas < gasEstimate + gasEstimate/10 ) {
powGasPrice = candidate;
}
} while ( !powGasPrice );

Json::Value transact;
transact["from"] = toJS( address2 );
transact["to"] = contractAddress;
transact["gasPrice"] = toJS( powGasPrice );
transact["data"] = "0x15b2eec30000000000000000000000000000000000000000000000000000000000000003";

fixture.rpcClient->eth_sendTransaction( transact );
dev::eth::mineTransaction( *( fixture.client ), 1 );

Expand Down Expand Up @@ -1865,7 +1875,8 @@ contract TestEstimateGas {
txStore1["data"] = "0x6057361d0000000000000000000000000000000000000000000000000000000000000001";
txStore1["from"] = toJS( senderAddress );
txStore1["gasPrice"] = fixture.rpcClient->eth_gasPrice();
string txHash = fixture.rpcClient->eth_call( txStore1, "latest" );
fixture.rpcClient->eth_sendTransaction( txStore1 );
dev::eth::mineTransaction( *( fixture.client ), 1 );

Json::Value estimateGasCall; // call clear(0)
estimateGasCall["to"] = contractAddress;
Expand All @@ -1875,11 +1886,25 @@ contract TestEstimateGas {
string estimatedGas = fixture.rpcClient->eth_estimateGas( estimateGasCall );

dev::bytes data = dev::jsToBytes( estimateGasCall["data"].asString() );

BOOST_REQUIRE( dev::jsToU256( estimatedGas ) > dev::eth::TransactionBase::baseGasRequired(
false, &data, fixture.client->chainParams().scheduleForBlockNumber(
fixture.client->number() ) ) );
BOOST_REQUIRE( dev::jsToU256( estimatedGas ) == 21871 );

// try to send with this gas
estimateGasCall["gas"] = toJS( jsToInt( estimatedGas ) );
string clearHash = fixture.rpcClient->eth_sendTransaction( estimateGasCall );
dev::eth::mineTransaction( *( fixture.client ), 1 );
Json::Value clearReceipt = fixture.rpcClient->eth_getTransactionReceipt( clearHash );
BOOST_REQUIRE_EQUAL(clearReceipt["status"], "0x1");
BOOST_REQUIRE_LT(jsToInt(clearReceipt["gasUsed"].asString()), 21000);

// try to lower gas
estimateGasCall["gas"] = toJS( jsToInt( estimatedGas ) - 1 );
clearHash = fixture.rpcClient->eth_sendTransaction( estimateGasCall );
dev::eth::mineTransaction( *( fixture.client ), 1 );
clearReceipt = fixture.rpcClient->eth_getTransactionReceipt( clearHash );
BOOST_REQUIRE_EQUAL(clearReceipt["status"], "0x0");
BOOST_REQUIRE_GT(jsToInt(clearReceipt["gasUsed"].asString()), 21000);
}

BOOST_AUTO_TEST_CASE( storage_limit_contract ) {
Expand Down

0 comments on commit f7c560a

Please sign in to comment.