Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion silkworm/core/crypto/kzg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ static bool pairings_verify(
*/
static bool bytes_to_bls_field(Fr* out, std::span<const uint8_t, 32> b) {
blst_scalar tmp;
blst_scalar_from_lendian(&tmp, b.data());
blst_scalar_from_bendian(&tmp, b.data());
if (!blst_scalar_fr_check(&tmp)) {
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions silkworm/core/execution/precompile_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,8 @@ TEST_CASE("POINT_EVALUATION") {
Bytes in{
*from_hex(
"013c03613f6fc558fb7e61e75602241ed9a2f04e36d8670aadd286e71b5ca9cc"
"4200000000000000000000000000000000000000000000000000000000000000"
"31e5a2356cbc2ef6a733eae8d54bf48719ae3d990017ca787c419c7d369f8e3c"
"0000000000000000000000000000000000000000000000000000000000000042"
"3c8e9f367d9c417c78ca1700993dae1987f44bd5e8ea33a7f62ebc6c35a2e531"
"83fac17c3f237fc51f90e2c660eb202a438bc2025baded5cd193c1a018c5885bc9281ba704d5566082e851235c7be763"
"b2a99adff965e0a121ee972ebc472d02944a74f5c6243e14052e105124b70bf65faf85ad3a494325e269fad097842cba")};
std::optional<Bytes> out{point_evaluation_run(in)};
Expand Down
29 changes: 15 additions & 14 deletions silkworm/core/protocol/base_rule_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,18 @@ ValidationResult BaseRuleSet::pre_validate_block_body(const Block& block, const
return ValidationResult::kWrongWithdrawalsRoot;
}

size_t total_blobs{0};
for (const Transaction& tx : block.transactions) {
total_blobs += tx.blob_versioned_hashes.size();
}
if (total_blobs > kMaxDataGasPerBlock / kDataGasPerBlob) {
return ValidationResult::kTooManyBlobs;
}

const std::optional<BlockHeader> parent{get_parent_header(state, header)};
if (!parent) {
return ValidationResult::kUnknownParent;
std::optional<uint64_t> data_gas_used{std::nullopt};
if (rev >= EVMC_CANCUN) {
data_gas_used = 0;
for (const Transaction& tx : block.transactions) {
*data_gas_used += tx.total_data_gas();
}
if (data_gas_used > kMaxDataGasPerBlock) {
return ValidationResult::kTooManyBlobs;
}
}

if (header.excess_data_gas != calc_excess_data_gas(*parent, total_blobs, rev)) {
return ValidationResult::kWrongExcessDataGas;
if (header.data_gas_used != data_gas_used) {
return ValidationResult::kWrongDataGasUsed;
}

if (block.ommers.empty()) {
Expand Down Expand Up @@ -191,6 +188,10 @@ ValidationResult BaseRuleSet::validate_block_header(const BlockHeader& header, c
return ValidationResult::kMissingWithdrawals;
}

if (header.excess_data_gas != calc_excess_data_gas(*parent, rev)) {
return ValidationResult::kWrongExcessDataGas;
}

return validate_seal(header);
}

Expand Down
13 changes: 5 additions & 8 deletions silkworm/core/protocol/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ bool transaction_type_is_supported(TransactionType type, evmc_revision rev) {
EVMC_LONDON, // kEip1559
EVMC_CANCUN, // kEip4844
};
const auto n{static_cast<std::size_t>(type)};
return n < std::size(kMinRevisionByType) && rev >= kMinRevisionByType[n];
const auto i{static_cast<std::size_t>(type)};
return i < std::size(kMinRevisionByType) && rev >= kMinRevisionByType[i];
}

ValidationResult pre_validate_transaction(const Transaction& txn, const evmc_revision rev, const uint64_t chain_id,
Expand Down Expand Up @@ -96,7 +96,6 @@ ValidationResult pre_validate_transaction(const Transaction& txn, const evmc_rev
return ValidationResult::kWrongBlobCommitmentVersion;
}
}
SILKWORM_ASSERT(txn.max_fee_per_data_gas);
SILKWORM_ASSERT(data_gas_price);
if (txn.max_fee_per_data_gas < data_gas_price) {
return ValidationResult::kMaxFeePerDataGasTooLow;
Expand Down Expand Up @@ -161,15 +160,13 @@ std::optional<intx::uint256> expected_base_fee_per_gas(const BlockHeader& parent
}
}

std::optional<intx::uint256> calc_excess_data_gas(const BlockHeader& parent,
std::size_t num_blobs,
const evmc_revision rev) {
std::optional<uint64_t> calc_excess_data_gas(const BlockHeader& parent, const evmc_revision rev) {
if (rev < EVMC_CANCUN) {
return std::nullopt;
}

const uint64_t consumed_data_gas{num_blobs * kDataGasPerBlob};
const intx::uint256 parent_excess_data_gas{parent.excess_data_gas.value_or(0)};
const uint64_t parent_excess_data_gas{parent.excess_data_gas.value_or(0)};
const uint64_t consumed_data_gas{parent.data_gas_used.value_or(0)};

if (parent_excess_data_gas + consumed_data_gas < kTargetDataGasPerBlock) {
return 0;
Expand Down
4 changes: 2 additions & 2 deletions silkworm/core/protocol/validation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ enum class [[nodiscard]] ValidationResult{
kWrongWithdrawalsRoot,

// EIP-4844: Shard Blob Transactions
kWrongDataGasUsed,
kWrongExcessDataGas,
kNoBlobs,
kTooManyBlobs,
Expand All @@ -114,8 +115,7 @@ namespace protocol {
std::optional<intx::uint256> expected_base_fee_per_gas(const BlockHeader& parent, const evmc_revision);

//! \see EIP-4844: Shard Blob Transactions
std::optional<intx::uint256> calc_excess_data_gas(const BlockHeader& parent, std::size_t num_blobs,
const evmc_revision);
std::optional<uint64_t> calc_excess_data_gas(const BlockHeader& parent, const evmc_revision);

//! \brief Calculate the transaction root of a block body
evmc::bytes32 compute_transaction_root(const BlockBody& body);
Expand Down
32 changes: 20 additions & 12 deletions silkworm/core/types/block.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ namespace rlp {
if (header.withdrawals_root) {
rlp_head.payload_length += kHashLength + 1;
}
if (header.data_gas_used) {
rlp_head.payload_length += length(*header.data_gas_used);
}
if (header.excess_data_gas) {
rlp_head.payload_length += length(*header.excess_data_gas);
}
Expand Down Expand Up @@ -145,6 +148,9 @@ namespace rlp {
if (header.withdrawals_root) {
encode(to, static_cast<ByteView>(*header.withdrawals_root));
}
if (header.data_gas_used) {
encode(to, *header.data_gas_used);
}
if (header.excess_data_gas) {
encode(to, *header.excess_data_gas);
}
Expand Down Expand Up @@ -183,31 +189,33 @@ namespace rlp {
return res;
}

to.base_fee_per_gas = std::nullopt;
if (from.length() > leftover) {
intx::uint256 base_fee_per_gas;
if (DecodingResult res{decode(from, base_fee_per_gas, Leftover::kAllow)}; !res) {
to.base_fee_per_gas = 0;
if (DecodingResult res{decode(from, *to.base_fee_per_gas, Leftover::kAllow)}; !res) {
return res;
}
to.base_fee_per_gas = base_fee_per_gas;
} else {
to.base_fee_per_gas = std::nullopt;
}

to.withdrawals_root = std::nullopt;
if (from.length() > leftover) {
evmc::bytes32 withdrawals_root;
if (DecodingResult res{decode(from, withdrawals_root, Leftover::kAllow)}; !res) {
to.withdrawals_root = evmc::bytes32{};
if (DecodingResult res{decode(from, *to.withdrawals_root, Leftover::kAllow)}; !res) {
return res;
}
to.withdrawals_root = withdrawals_root;
} else {
to.withdrawals_root = std::nullopt;
}

to.excess_data_gas = std::nullopt;
if (from.length() > leftover) {
intx::uint256 excess_data_gas;
if (DecodingResult res{decode(from, excess_data_gas, Leftover::kAllow)}; !res) {
to.data_gas_used = 0;
to.excess_data_gas = 0;
if (DecodingResult res{decode_items(from, *to.data_gas_used, *to.excess_data_gas)}; !res) {
return res;
}
to.excess_data_gas = excess_data_gas;
} else {
to.data_gas_used = std::nullopt;
to.excess_data_gas = std::nullopt;
}

if (from.length() != leftover) {
Expand Down
5 changes: 4 additions & 1 deletion silkworm/core/types/block.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ struct BlockHeader {

std::optional<intx::uint256> base_fee_per_gas{std::nullopt}; // EIP-1559
std::optional<evmc::bytes32> withdrawals_root{std::nullopt}; // EIP-4895
std::optional<intx::uint256> excess_data_gas{std::nullopt}; // EIP-4844

// EIP-4844: Shard Blob Transactions
std::optional<uint64_t> data_gas_used{std::nullopt};
std::optional<uint64_t> excess_data_gas{std::nullopt};

[[nodiscard]] evmc::bytes32 hash(bool for_sealing = false, bool exclude_extra_data_sig = false) const;

Expand Down
29 changes: 26 additions & 3 deletions silkworm/core/types/block_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,32 @@ TEST_CASE("EIP-2718 Block RLP") {
}

TEST_CASE("EIP-1559 Header RLP") {
BlockHeader h;
h.number = 13'500'000;
h.base_fee_per_gas = 2'700'000'000;
BlockHeader h{
.number = 13'500'000,
.base_fee_per_gas = 2'700'000'000,
};

Bytes rlp;
rlp::encode(rlp, h);

ByteView view{rlp};
BlockHeader decoded;
REQUIRE(rlp::decode(view, decoded));

CHECK(view.empty());
CHECK(decoded == h);
}

TEST_CASE("EIP-4844 Header RLP") {
BlockHeader h{
.ommers_hash = kEmptyListHash,
.number = 17'000'000,
.prev_randao = 0xd01681d2b3acdebff0288a02a1648b3910500961982d5ecdbef064af7c34090b_bytes32,
.base_fee_per_gas = 2'700'000'000,
.withdrawals_root = 0xbac9348581b0ee244d6eb61076b63c4e4afa70430c804ab0e6a0ab69d9a9d323_bytes32,
.data_gas_used = 456,
.excess_data_gas = 789633,
};

Bytes rlp;
rlp::encode(rlp, h);
Expand Down
40 changes: 30 additions & 10 deletions silkworm/core/types/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace rlp {
}

h.payload_length += length(txn.nonce);
if (txn.type == TransactionType::kEip1559) {
if (txn.type == TransactionType::kEip1559 || txn.type == TransactionType::kEip4844) {
h.payload_length += length(txn.max_priority_fee_per_gas);
}
h.payload_length += length(txn.max_fee_per_gas);
Expand All @@ -81,8 +81,11 @@ namespace rlp {
h.payload_length += length(txn.data);

if (txn.type != TransactionType::kLegacy) {
SILKWORM_ASSERT(txn.type == TransactionType::kEip2930 || txn.type == TransactionType::kEip1559);
h.payload_length += length(txn.access_list);
if (txn.type == TransactionType::kEip4844) {
h.payload_length += length(txn.max_fee_per_data_gas);
h.payload_length += length(txn.blob_versioned_hashes);
}
}

return h;
Expand Down Expand Up @@ -134,8 +137,6 @@ namespace rlp {
}

static void eip2718_encode_for_signing(Bytes& to, const UnsignedTransaction& txn, const Header h, bool wrap_into_array) {
SILKWORM_ASSERT(txn.type == TransactionType::kEip2930 || txn.type == TransactionType::kEip1559);

if (wrap_into_array) {
auto rlp_len{static_cast<size_t>(length_of_length(h.payload_length) + h.payload_length)};
encode_header(to, {false, rlp_len + 1});
Expand All @@ -148,7 +149,7 @@ namespace rlp {
encode(to, txn.chain_id.value_or(0));

encode(to, txn.nonce);
if (txn.type == TransactionType::kEip1559) {
if (txn.type != TransactionType::kEip2930) {
encode(to, txn.max_priority_fee_per_gas);
}
encode(to, txn.max_fee_per_gas);
Expand All @@ -161,6 +162,11 @@ namespace rlp {
encode(to, txn.value);
encode(to, txn.data);
encode(to, txn.access_list);

if (txn.type == TransactionType::kEip4844) {
encode(to, txn.max_fee_per_data_gas);
encode(to, txn.blob_versioned_hashes);
}
}

void encode(Bytes& to, const Transaction& txn, bool wrap_eip2718_into_string) {
Expand Down Expand Up @@ -210,7 +216,9 @@ namespace rlp {
}

static DecodingResult eip2718_decode(ByteView& from, Transaction& to) noexcept {
if (to.type != TransactionType::kEip2930 && to.type != TransactionType::kEip1559) {
if (to.type != TransactionType::kEip2930 &&
to.type != TransactionType::kEip1559 &&
to.type != TransactionType::kEip4844) {
return tl::unexpected{DecodingError::kUnsupportedTransactionType};
}

Expand Down Expand Up @@ -252,7 +260,18 @@ namespace rlp {
}
}

return decode_items(from, to.value, to.data, to.access_list, to.odd_y_parity, to.r, to.s);
if (DecodingResult res{decode_items(from, to.value, to.data, to.access_list)}; !res) {
return res;
}

if (to.type != TransactionType::kEip4844) {
to.max_fee_per_data_gas = 0;
to.blob_versioned_hashes.clear();
} else if (DecodingResult res{decode_items(from, to.max_fee_per_data_gas, to.blob_versioned_hashes)}; !res) {
return res;
}

return decode_items(from, to.odd_y_parity, to.r, to.s);
}

DecodingResult decode_transaction(ByteView& from, Transaction& to, Eip2718Wrapping allowed,
Expand Down Expand Up @@ -282,6 +301,9 @@ namespace rlp {
if (h->list) { // Legacy transaction
to.type = TransactionType::kLegacy;
to.access_list.clear();
to.max_fee_per_data_gas = 0;
to.blob_versioned_hashes.clear();

const uint64_t leftover{from.length() - h->payload_length};
if (mode != Leftover::kAllow && leftover) {
return tl::unexpected{DecodingError::kInputTooLong};
Expand Down Expand Up @@ -390,9 +412,7 @@ intx::uint512 UnsignedTransaction::maximum_gas_cost() const {
// See https://github.com/ethereum/EIPs/pull/3594
intx::uint512 max_gas_cost{intx::umul(intx::uint256{gas_limit}, max_fee_per_gas)};
// and https://eips.ethereum.org/EIPS/eip-4844#gas-accounting
if (max_fee_per_data_gas) {
max_gas_cost += intx::umul(intx::uint256{total_data_gas()}, *max_fee_per_data_gas);
}
max_gas_cost += intx::umul(intx::uint256{total_data_gas()}, max_fee_per_data_gas);
return max_gas_cost;
}

Expand Down
2 changes: 1 addition & 1 deletion silkworm/core/types/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ struct UnsignedTransaction {
std::vector<AccessListEntry> access_list{}; // EIP-2930

// EIP-4844: Shard Blob Transactions
std::optional<intx::uint256> max_fee_per_data_gas{std::nullopt};
intx::uint256 max_fee_per_data_gas{0};
std::vector<Hash> blob_versioned_hashes{};

//! \brief Maximum possible cost of normal and data (EIP-4844) gas
Expand Down
Loading