Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpcdaemon: eth_feeHistory for e3 #2455

Merged
merged 15 commits into from
Oct 30, 2024
2 changes: 1 addition & 1 deletion .github/workflows/rpc-integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
- name: Checkout RPC Tests Repository & Install Requirements
run: |
rm -rf ${{runner.workspace}}/rpc-tests
git -c advice.detachedHead=false clone --depth 1 --branch v1.4.0 https://github.com/erigontech/rpc-tests ${{runner.workspace}}/rpc-tests
git -c advice.detachedHead=false clone --depth 1 --branch v1.5.0 https://github.com/erigontech/rpc-tests ${{runner.workspace}}/rpc-tests
cd ${{runner.workspace}}/rpc-tests
pip3 install -r requirements.txt

Expand Down
25 changes: 16 additions & 9 deletions .github/workflows/run_integration_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,24 @@ set +e # Disable exit on error
cd "$1" || exit 1
rm -rf ./mainnet/results/


# debug_traceTransaction: modify expected response according erigon and makes silkworm fix
# trace_filter/test_16.json: modify expected response according erigon and makes silkworm fix
# debug_traceCall/test_02.json: modify expected response according erigon and makes silkworm fix
# eth_feeHistory: modify expected response according erigon and makes silkworm fix
# trace_replayTransaction/trace_replyBlockTransaction: have differente response with silkworm but should be rpcdaemon problems (to be analized)
# debug_accountRange: new algo using TKV
# debug_getModifiedAccounts: new algo using TKV
# debug_storageRangeAt: new algo using TKV
# debug_traceCall/test_02.json: requested is_latest fix to support ethbackend
# debug_traceTransaction: change expected response according erigon (report evm error) and make silkworm fix
# erigon_getBalanceChangesInBlock: new algo using TKV
# erigon_getLatestLogs: new algo using TKV
# eth_getLogs: new algo using TKV
# ots_getTransactionBySenderAndNonce: new algo using TKV
# ots_getContractCreator: new algo using TKV
# ots_hasCode: new algo using TKV
# ots_searchTransactionsAfter: new algo using TKV
# ots_searchTransactionsBefore: new algo using TKV
# parity_listStorageKeys/test_12.json: fix required
# trace_rawTransaction: different implementation

# trace_replayTransaction/trace_replyBlockTransaction: silkworm has different response wrt e3 but should be e3 problem (to be analyzed)

python3 ./run_tests.py --continue --blockchain mainnet --jwt "$2" --display-only-fail --port 51515 -x \
debug_accountRange,\
debug_getModifiedAccounts,\
Expand All @@ -37,7 +47,6 @@ debug_traceTransaction/test_96.json,\
engine_,\
erigon_getBalanceChangesInBlock,\
erigon_getLatestLogs,\
eth_feeHistory,\
eth_getLogs,\
ots_getTransactionBySenderAndNonce,\
ots_getContractCreator,\
Expand All @@ -62,5 +71,3 @@ else
fi

exit $failed_test


12 changes: 8 additions & 4 deletions silkworm/core/types/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,19 @@ static intx::uint256 fake_exponential(const intx::uint256& factor,
return output / denominator;
}

intx::uint256 calc_blob_gas_price(uint64_t excess_blob_gas) {
return fake_exponential(
protocol::kMinBlobGasPrice,
excess_blob_gas,
protocol::kBlobGasPriceUpdateFraction);
}

std::optional<intx::uint256> BlockHeader::blob_gas_price() const {
if (!excess_blob_gas) {
return std::nullopt;
}

return fake_exponential(
protocol::kMinBlobGasPrice,
*excess_blob_gas,
protocol::kBlobGasPriceUpdateFraction);
return calc_blob_gas_price(*excess_blob_gas);
}

namespace rlp {
Expand Down
2 changes: 2 additions & 0 deletions silkworm/core/types/block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ namespace silkworm {

using TotalDifficulty = intx::uint256;

intx::uint256 calc_blob_gas_price(uint64_t excess_blob_gas);

struct BlockHeader {
using NonceType = std::array<uint8_t, 8>;

Expand Down
6 changes: 5 additions & 1 deletion silkworm/rpc/commands/debug_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,11 @@ Task<void> DebugRpcApi::handle_debug_trace_call(const nlohmann::json& request, j
} catch (const std::exception& e) {
SILK_ERROR << "exception: " << e.what() << " processing request: " << request.dump();
std::ostringstream oss;
oss << "block " << block_number_or_hash.number() << "(" << silkworm::to_hex(block_number_or_hash.hash()) << ") not found";
if (block_number_or_hash.hash())
oss << "block " << silkworm::to_hex(block_number_or_hash.hash()) << " not found";
else {
oss << "block " << block_number_or_hash.number() << " not found";
}
const Error error{kServerError, oss.str()};
stream.write_json_field("error", error);
} catch (...) {
Expand Down
4 changes: 3 additions & 1 deletion silkworm/rpc/commands/eth_api_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ TEST_CASE_METHOD(test_util::RpcApiE2ETest, "unit: eth_feeHistory succeeds if req
CHECK(nlohmann::json::parse(reply) == R"({
"jsonrpc":"2.0",
"id":1,
"result":{"gasUsedRatio":null,"oldestBlock":"0x0"}
"result":{"gasUsedRatio":null,"oldestBlock":"0x0", "blobGasUsedRatio":null}
})"_json);
}

Expand Down Expand Up @@ -135,7 +135,9 @@ TEST_CASE_METHOD(test_util::RpcApiE2ETest, "fuzzy: eth_feeHistory sigsegv valid
"jsonrpc":"2.0",
"id":1,
"result":{
"baseFeePerBlobGas":["0x0","0x0","0x0","0x0"],
"baseFeePerGas":["0x3b9aca00","0x342770c0","0x2db08786","0x2806be9d"],
"blobGasUsedRatio":[0.0,0.0,0.0],
"gasUsedRatio":[0.0,0.0042,0.0042],
"oldestBlock":"0x0",
"reward":[["0x0","0x0"],["0x1","0x1"],["0x1","0x1"]]}
Expand Down
2 changes: 1 addition & 1 deletion silkworm/rpc/commands/ots_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Task<void> OtsRpcApi::handle_ots_has_code(const nlohmann::json& request, nlohman
}
} catch (const std::exception& e) {
SILK_ERROR << "exception: " << e.what() << " processing request: " << request.dump();
reply = make_json_error(request, kInternalError, e.what());
reply = make_json_content(request, false);
} catch (...) {
SILK_ERROR << "unexpected exception processing request: " << request.dump();
reply = make_json_error(request, kServerError, "unexpected exception");
Expand Down
8 changes: 1 addition & 7 deletions silkworm/rpc/core/evm_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1731,13 +1731,7 @@ Task<void> TraceCallExecutor::trace_filter(const TraceFilter& trace_filter, cons
}

while (block_number <= trace_filter.to_block.number()) {
if (!block_with_hash) {
stream.open_object();
const std::string error_msg = "could not find block " + std::to_string(block_number);
const Error error{-32000, error_msg};
stream.write_json_field("error", error);
stream.close_object();
} else {
if (block_with_hash) {
const Block block{block_with_hash, false};
SILK_TRACE << "TraceCallExecutor::trace_filter: processing "
<< " block_number: " << block_number - 1
Expand Down
54 changes: 51 additions & 3 deletions silkworm/rpc/core/fee_history_oracle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include <algorithm>

#include <silkworm/core/protocol/param.hpp>
#include <silkworm/core/protocol/validation.hpp>
#include <silkworm/infra/common/ensure.hpp>
#include <silkworm/infra/common/log.hpp>
Expand All @@ -40,6 +41,20 @@ void to_json(nlohmann::json& json, const FeeHistory& fh) {
} else {
json["gasUsedRatio"] = fh.gas_used_ratio;
}
if (fh.blob_gas_used_ratio.empty()) {
json["blobGasUsedRatio"] = nullptr;
} else {
auto json1 = nlohmann::json::array();
for (size_t k{0}; k < fh.blob_gas_used_ratio.size(); ++k) {
auto& value{fh.blob_gas_used_ratio[k]};
if (value == 0) {
json1.push_back(0);
} else {
json1.push_back(value);
}
}
json["blobGasUsedRatio"] = json1;
}
json["oldestBlock"] = to_quantity(fh.oldest_block);

if (!fh.base_fees_per_gas.empty()) {
Expand All @@ -51,6 +66,15 @@ void to_json(nlohmann::json& json, const FeeHistory& fh) {
json["baseFeePerGas"] = fee_string_list;
}

if (!fh.blob_base_fees_per_gas.empty()) {
std::vector<std::string> blob_fee_string_list;
blob_fee_string_list.reserve(fh.blob_base_fees_per_gas.size());
for (const auto& fee : fh.blob_base_fees_per_gas) {
blob_fee_string_list.push_back(to_quantity(fee));
}
json["baseFeePerBlobGas"] = blob_fee_string_list;
}

if (!fh.rewards.empty()) {
// Don't call reserve here to preallocate vector - since json value is dynamic it doesn't know yet how much it should allocate!
// -> Don't uncomment this line json_list.reserve(fh.rewards.size());
Expand Down Expand Up @@ -102,7 +126,9 @@ Task<FeeHistory> FeeHistoryOracle::fee_history(BlockNum newest_block,
}
fee_history.rewards.resize(block_range.num_blocks);
fee_history.base_fees_per_gas.resize(block_range.num_blocks + 1);
fee_history.blob_base_fees_per_gas.resize(block_range.num_blocks + 1);
fee_history.gas_used_ratio.resize(block_range.num_blocks);
fee_history.blob_gas_used_ratio.resize(block_range.num_blocks);

const auto oldest_block_number = block_range.last_block_number + 1 - block_range.num_blocks;
auto first_missing = block_range.num_blocks;
Expand Down Expand Up @@ -143,8 +169,11 @@ Task<FeeHistory> FeeHistoryOracle::fee_history(BlockNum newest_block,
if (block_fees.block_header) {
fee_history.rewards[index] = block_fees.rewards;
fee_history.base_fees_per_gas[index] = block_fees.base_fee;
fee_history.blob_base_fees_per_gas[index] = block_fees.blob_base_fee;
fee_history.base_fees_per_gas[index + 1] = block_fees.next_base_fee;
fee_history.blob_base_fees_per_gas[index + 1] = block_fees.next_blob_base_fee;
fee_history.gas_used_ratio[index] = block_fees.gas_used_ratio;
fee_history.blob_gas_used_ratio[index] = block_fees.blob_gas_used_ratio;
} else {
// Getting no block and no error means we are requesting into the future (might happen because of a reorg)
first_missing = std::min(first_missing, index);
Expand All @@ -159,7 +188,9 @@ Task<FeeHistory> FeeHistoryOracle::fee_history(BlockNum newest_block,
fee_history.rewards.clear();
}
fee_history.base_fees_per_gas.resize(first_missing + 1);
fee_history.blob_base_fees_per_gas.resize(first_missing + 1);
fee_history.gas_used_ratio.resize(first_missing);
fee_history.blob_gas_used_ratio.resize(first_missing);
fee_history.oldest_block = oldest_block_number;

co_return fee_history;
Expand Down Expand Up @@ -202,17 +233,34 @@ Task<void> FeeHistoryOracle::process_block(BlockFees& block_fees, const std::vec
auto next_block_number = header.number + 1;
block_fees.base_fee = header.base_fee_per_gas.value_or(0);

block_fees.gas_used_ratio = static_cast<double>(header.gas_used) / static_cast<double>(header.gas_limit);

if (config_.is_london(next_block_number)) {
block_fees.next_base_fee = protocol::expected_base_fee_per_gas(header);
} else {
block_fees.next_base_fee = 0;
block_fees.next_base_fee = 0; // EIP-4844 blob gas cost (calc_data_fee)block_fees.next_blob_base_fee
}

block_fees.blob_base_fee = header.blob_gas_price().value_or(0);

if (header.excess_blob_gas) {
block_fees.next_blob_base_fee = calc_blob_gas_price(protocol::calc_excess_blob_gas(header));

} else {
block_fees.next_blob_base_fee = 0;
}

block_fees.gas_used_ratio = static_cast<double>(header.gas_used) / static_cast<double>(header.gas_limit);

if (reward_percentiles.empty()) {
co_return; // rewards were not requested, return
}

/*
// TODO: waiting fix on erigon to evalute MaxBlobGasPerBlock
if (header.blob_gas_used && protocol::kMaxBlobGasPerBlock) {
block_fees.blob_gas_used_ratio = static_cast<double>(*(header.blob_gas_used)) / static_cast<double>(protocol::kMaxBlobGasPerBlock);
}
*/

if (block_fees.receipts.size() != block_fees.block->block.transactions.size()) {
co_return;
}
Expand Down
5 changes: 5 additions & 0 deletions silkworm/rpc/core/fee_history_oracle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ struct FeeHistory {
std::vector<intx::uint256> base_fees_per_gas;
std::vector<double> gas_used_ratio;
std::vector<Rewards> rewards;
std::vector<double> blob_gas_used_ratio;
std::vector<intx::uint256> blob_base_fees_per_gas;
std::optional<std::string> error{std::nullopt};
};

Expand All @@ -62,7 +64,10 @@ struct BlockFees {
Rewards rewards;
intx::uint256 base_fee;
intx::uint256 next_base_fee;
intx::uint256 blob_base_fee;
intx::uint256 next_blob_base_fee;
double gas_used_ratio{0};
double blob_gas_used_ratio{0};
};

class FeeHistoryOracle {
Expand Down
3 changes: 3 additions & 0 deletions silkworm/rpc/core/fee_history_oracle_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ TEST_CASE("FeeHistory: json serialization") {

CHECK(nlohmann::json(fh) == R"({
"gasUsedRatio":null,
"blobGasUsedRatio":null,
"oldestBlock":"0x0"
})"_json);
}
Expand All @@ -44,6 +45,8 @@ TEST_CASE("FeeHistory: json serialization") {

CHECK(nlohmann::json(fh) == R"({
"baseFeePerGas":["0x13c723946e","0x163fe26534"],
"blobGasUsedRatio":null,
"blobGasUsedRatio":null,
"gasUsedRatio":[0.9998838666666666],
"oldestBlock":"0x867a80",
"reward":[
Expand Down
Loading