Skip to content

Commit

Permalink
rpcdaemon: extract receipts out from chain (#2100)
Browse files Browse the repository at this point in the history
  • Loading branch information
canepat authored Jun 13, 2024
1 parent ef79536 commit 1cf47e7
Show file tree
Hide file tree
Showing 6 changed files with 502 additions and 484 deletions.
132 changes: 0 additions & 132 deletions silkworm/rpc/core/rawdb/chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,11 @@
#include <silkworm/db/util.hpp>
#include <silkworm/infra/common/decoding_exception.hpp>
#include <silkworm/infra/common/log.hpp>
#include <silkworm/rpc/common/util.hpp>
#include <silkworm/rpc/core/blocks.hpp>
#include <silkworm/rpc/ethdb/cbor.hpp>
#include <silkworm/rpc/ethdb/walk.hpp>
#include <silkworm/rpc/json/types.hpp>
#include <silkworm/rpc/types/receipt.hpp>

namespace silkworm::rpc::core::rawdb {

/* Local Routines */
static Task<silkworm::BlockHeader> read_header_by_hash(ethdb::Transaction& tx, const evmc::bytes32& block_hash);
static Task<silkworm::BlockHeader> read_header(ethdb::Transaction& tx, const evmc::bytes32& block_hash, BlockNum block_number);
static Task<silkworm::Bytes> read_header_rlp(ethdb::Transaction& tx, const evmc::bytes32& block_hash, BlockNum block_number);
static Task<silkworm::Bytes> read_body_rlp(ethdb::Transaction& tx, const evmc::bytes32& block_hash, BlockNum block_number);

Task<uint64_t> read_header_number(ethdb::Transaction& tx, const evmc::bytes32& block_hash) {
Expand Down Expand Up @@ -104,31 +96,6 @@ Task<intx::uint256> read_total_difficulty(ethdb::Transaction& tx, const evmc::by
co_return total_difficulty;
}

Task<silkworm::BlockHeader> read_header_by_hash(ethdb::Transaction& tx, const evmc::bytes32& block_hash) {
const auto block_number = co_await read_header_number(tx, block_hash);
co_return co_await read_header(tx, block_hash, block_number);
}

Task<silkworm::BlockHeader> read_header(ethdb::Transaction& tx, const evmc::bytes32& block_hash, BlockNum block_number) {
auto data = co_await read_header_rlp(tx, block_hash, block_number);
if (data.empty()) {
throw std::runtime_error{"empty block header RLP in read_header"};
}
SILK_TRACE << "data: " << silkworm::to_hex(data);
silkworm::ByteView data_view{data};
silkworm::BlockHeader header{};
const auto error = silkworm::rlp::decode(data_view, header);
if (!error) {
throw std::runtime_error{"invalid RLP decoding for block header"};
}
co_return header;
}

Task<silkworm::BlockHeader> read_current_header(ethdb::Transaction& tx) {
const auto head_header_hash = co_await read_head_header_hash(tx);
co_return co_await read_header_by_hash(tx, head_header_hash);
}

Task<evmc::bytes32> read_head_header_hash(ethdb::Transaction& tx) {
const silkworm::Bytes kHeadHeaderKey = silkworm::bytes_of_string(db::table::kHeadHeaderName);
const auto value = co_await tx.get_one(db::table::kHeadHeaderName, kHeadHeaderKey);
Expand Down Expand Up @@ -160,110 +127,11 @@ Task<uint64_t> read_cumulative_transaction_count(ethdb::Transaction& tx, uint64_
}
}

Task<silkworm::Bytes> read_header_rlp(ethdb::Transaction& tx, const evmc::bytes32& block_hash, BlockNum block_number) {
const auto block_key = silkworm::db::block_key(block_number, block_hash.bytes);
co_return co_await tx.get_one(db::table::kHeadersName, block_key);
}

Task<silkworm::Bytes> read_body_rlp(ethdb::Transaction& tx, const evmc::bytes32& block_hash, BlockNum block_number) {
const auto block_key = silkworm::db::block_key(block_number, block_hash.bytes);
co_return co_await tx.get_one(db::table::kBlockBodiesName, block_key);
}

Task<std::optional<Receipts>> read_raw_receipts(ethdb::Transaction& tx, BlockNum block_number) {
const auto block_key = silkworm::db::block_key(block_number);
const auto data = co_await tx.get_one(db::table::kBlockReceiptsName, block_key);
SILK_TRACE << "read_raw_receipts data: " << silkworm::to_hex(data);
if (data.empty()) {
co_return std::nullopt;
}

Receipts receipts{};
const bool decoding_ok{cbor_decode(data, receipts)};
if (!decoding_ok) {
throw std::runtime_error("cannot decode raw receipts in block: " + std::to_string(block_number));
}
SILK_TRACE << "#receipts: " << receipts.size();
if (receipts.empty()) {
co_return receipts;
}

auto log_key = silkworm::db::log_key(block_number, 0);
SILK_DEBUG << "log_key: " << silkworm::to_hex(log_key);
auto walker = [&](const silkworm::Bytes& k, const silkworm::Bytes& v) {
if (k.size() != sizeof(uint64_t) + sizeof(uint32_t)) {
return false;
}
auto tx_id = endian::load_big_u32(&k[sizeof(uint64_t)]);
const bool decode_ok{cbor_decode(v, receipts[tx_id].logs)};
if (!decode_ok) {
SILK_WARN << "cannot decode logs for receipt: " << tx_id << " in block: " << block_number;
return false;
}
receipts[tx_id].bloom = bloom_from_logs(receipts[tx_id].logs);
SILK_DEBUG << "#receipts[" << tx_id << "].logs: " << receipts[tx_id].logs.size();
return true;
};
co_await walk(tx, db::table::kLogsName, log_key, 8 * CHAR_BIT, walker);

co_return receipts;
}

Task<std::optional<Receipts>> read_receipts(ethdb::Transaction& tx, const silkworm::BlockWithHash& block_with_hash) {
const evmc::bytes32 block_hash = block_with_hash.hash;
uint64_t block_number = block_with_hash.block.header.number;
const auto raw_receipts = co_await read_raw_receipts(tx, block_number);
if (!raw_receipts || raw_receipts->empty()) {
co_return raw_receipts;
}
auto receipts = *raw_receipts;

// Add derived fields to the receipts
auto transactions = block_with_hash.block.transactions;
SILK_DEBUG << "#transactions=" << block_with_hash.block.transactions.size() << " #receipts=" << receipts.size();
if (transactions.size() != receipts.size()) {
throw std::runtime_error{"#transactions and #receipts do not match in read_receipts"};
}
uint32_t log_index{0};
for (size_t i{0}; i < receipts.size(); i++) {
// The tx hash can be calculated by the tx content itself
auto tx_hash{transactions[i].hash()};
receipts[i].tx_hash = silkworm::to_bytes32(full_view(tx_hash.bytes));
receipts[i].tx_index = uint32_t(i);

receipts[i].block_hash = block_hash;
receipts[i].block_number = block_number;

// When tx receiver is not set, create a contract with address depending on tx sender and its nonce
if (!transactions[i].to.has_value()) {
receipts[i].contract_address = create_address(*transactions[i].sender(), transactions[i].nonce);
}

// The gas used can be calculated by the previous receipt
if (i == 0) {
receipts[i].gas_used = receipts[i].cumulative_gas_used;
} else {
receipts[i].gas_used = receipts[i].cumulative_gas_used - receipts[i - 1].cumulative_gas_used;
}

receipts[i].from = transactions[i].sender();
receipts[i].to = transactions[i].to;
receipts[i].type = static_cast<uint8_t>(transactions[i].type);

// The derived fields of receipt are taken from block and transaction
for (size_t j{0}; j < receipts[i].logs.size(); j++) {
receipts[i].logs[j].block_number = block_number;
receipts[i].logs[j].block_hash = block_hash;
receipts[i].logs[j].tx_hash = receipts[i].tx_hash;
receipts[i].logs[j].tx_index = uint32_t(i);
receipts[i].logs[j].index = log_index++;
receipts[i].logs[j].removed = false;
}
}

co_return receipts;
}

Task<intx::uint256> read_total_issued(ethdb::Transaction& tx, BlockNum block_number) {
const auto block_key = silkworm::db::block_key(block_number);
const auto value = co_await tx.get_one(db::table::kIssuanceName, block_key);
Expand Down
10 changes: 0 additions & 10 deletions silkworm/rpc/core/rawdb/chain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,8 @@
#include <intx/intx.hpp>
#include <nlohmann/json.hpp>

#include <silkworm/core/types/block.hpp>
#include <silkworm/core/types/transaction.hpp>
#include <silkworm/rpc/ethdb/transaction.hpp>
#include <silkworm/rpc/types/block.hpp>
#include <silkworm/rpc/types/chain_config.hpp>
#include <silkworm/rpc/types/receipt.hpp>

namespace silkworm::rpc::core::rawdb {

Expand All @@ -47,16 +43,10 @@ Task<evmc::bytes32> read_canonical_block_hash(ethdb::Transaction& tx, BlockNum b

Task<intx::uint256> read_total_difficulty(ethdb::Transaction& tx, const evmc::bytes32& block_hash, BlockNum block_number);

Task<silkworm::BlockHeader> read_current_header(ethdb::Transaction& tx);

Task<evmc::bytes32> read_head_header_hash(ethdb::Transaction& tx);

Task<uint64_t> read_cumulative_transaction_count(ethdb::Transaction& tx, BlockNum block_number);

Task<std::optional<Receipts>> read_raw_receipts(ethdb::Transaction& tx, BlockNum block_number);

Task<std::optional<Receipts>> read_receipts(ethdb::Transaction& tx, const silkworm::BlockWithHash& block_with_hash);

Task<intx::uint256> read_total_issued(ethdb::Transaction& tx, BlockNum block_number);

Task<intx::uint256> read_total_burnt(ethdb::Transaction& tx, BlockNum block_number);
Expand Down
Loading

0 comments on commit 1cf47e7

Please sign in to comment.