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

Add final refund in processor #215

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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 cmd/dev/check_changes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ int main(int argc, char* argv[]) {

db::Buffer buffer{txn, /*prune_history_threshold=*/0, /*historical_block=*/block_num};

ExecutionProcessor processor{block, *rule_set, buffer, *chain_config, {}};
ExecutionProcessor processor{block, *rule_set, buffer, *chain_config, {}, {}};
processor.evm().analysis_cache = &analysis_cache;
processor.evm().state_pool = &state_pool;

Expand Down
2 changes: 1 addition & 1 deletion cmd/dev/scan_txs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ int main(int argc, char* argv[]) {

db::Buffer buffer{txn, /*prune_history_threshold=*/0, /*historical_block=*/block_num};

ExecutionProcessor processor{block, *rule_set, buffer, *chain_config, {}};
ExecutionProcessor processor{block, *rule_set, buffer, *chain_config, {}, {}};
processor.evm().analysis_cache = &analysis_cache;
processor.evm().state_pool = &state_pool;

Expand Down
2 changes: 1 addition & 1 deletion cmd/state-transition/state_transition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ void StateTransition::run() {
auto block = get_block(*state, config);
auto txn = get_transaction(expectedSubState);

ExecutionProcessor processor{block, *ruleSet, *state, config, {}};
ExecutionProcessor processor{block, *ruleSet, *state, config, {}, {}};
Receipt receipt;

const evmc_revision rev{config.revision(block.header)};
Expand Down
2 changes: 1 addition & 1 deletion cmd/test/ethereum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ RunResults blockchain_test(const nlohmann::json& json_test) {
InMemoryState state;
init_pre_state(json_test["pre"], state);

Blockchain blockchain{state, config, genesis_block, {}};
Blockchain blockchain{state, config, genesis_block, {}, {}};
blockchain.state_pool = &execution_state_pool;
blockchain.exo_evm = exo_evm;

Expand Down
10 changes: 9 additions & 1 deletion silkworm/core/execution/evm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
#include <silkworm/core/types/block.hpp>

namespace silkworm {
struct ExecutionResult {
// inclusion_fee+overhead_fee+storage_fee == receipt.cumulative_gas_used*effective_price
uint64_t discounted_storage_gas_consumed{0};
uint64_t cpu_gas_consumed{0};
intx::uint256 overhead_fee; //approx. => cpu_gas_consumed * overhead_price
intx::uint256 inclusion_fee; //approx. => cpu_gas_consumed * inclusion_price
intx::uint256 storage_fee; //exactly => discounted_storage_gas_consumed * effective_price
};

struct CallResult {
evmc_status_code status{EVMC_SUCCESS};
Expand Down Expand Up @@ -112,7 +120,7 @@ class EVM {
gas_params_ = gas_params;
}

const evmone::gas_parameters& get_gas_params() {
const evmone::gas_parameters get_gas_params() {
return gas_params_;
}

Expand Down
4 changes: 2 additions & 2 deletions silkworm/core/execution/execution.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ namespace silkworm {
* @param state The Ethereum state at the beginning of the block.
*/
[[nodiscard]] inline ValidationResult execute_block(const Block& block, State& state,
const ChainConfig& chain_config, const evmone::gas_parameters& gas_params) noexcept {
const ChainConfig& chain_config, const evmone::gas_parameters& gas_params, const gas_prices_t& gas_prices) noexcept {
auto rule_set{protocol::rule_set_factory(chain_config)};
if (!rule_set) {
return ValidationResult::kUnknownProtocolRuleSet;
}
ExecutionProcessor processor{block, *rule_set, state, chain_config, gas_params};
ExecutionProcessor processor{block, *rule_set, state, chain_config, gas_params, gas_prices};
std::vector<Receipt> receipts;
return processor.execute_and_write_block(receipts);
}
Expand Down
4 changes: 2 additions & 2 deletions silkworm/core/execution/execution_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ TEST_CASE("Execute two blocks") {
// Execute first block
// ---------------------------------------

REQUIRE(execute_block(block, state, test::kLondonConfig, {}) == ValidationResult::kOk);
REQUIRE(execute_block(block, state, test::kLondonConfig, {}, {}) == ValidationResult::kOk);

auto contract_address{create_address(sender, /*nonce=*/0)};
std::optional<Account> contract_account{state.read_account(contract_address)};
Expand Down Expand Up @@ -114,7 +114,7 @@ TEST_CASE("Execute two blocks") {
block.transactions[0].data = *from_hex(new_val);
block.transactions[0].max_priority_fee_per_gas = 20 * kGiga;

REQUIRE(execute_block(block, state, test::kLondonConfig, {}) == ValidationResult::kOk);
REQUIRE(execute_block(block, state, test::kLondonConfig, {}, {}) == ValidationResult::kOk);

storage0 = state.read_storage(contract_address, kDefaultIncarnation, storage_key0);
CHECK(to_hex(storage0) == new_val);
Expand Down
62 changes: 49 additions & 13 deletions silkworm/core/execution/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@
namespace silkworm {

ExecutionProcessor::ExecutionProcessor(const Block& block, protocol::IRuleSet& rule_set, State& state,
const ChainConfig& config, const evmone::gas_parameters& gas_params)
: state_{state}, rule_set_{rule_set}, evm_{block, state_, config, gas_params} {
const ChainConfig& config, const evmone::gas_parameters& gas_params, const gas_prices_t& gas_prices)
: state_{state}, rule_set_{rule_set}, evm_{block, state_, config, gas_params}, gas_params_{gas_params}, gas_prices_{gas_prices} {
evm_.beneficiary = rule_set.get_beneficiary(block.header);
}

void ExecutionProcessor::execute_transaction(const Transaction& txn, Receipt& receipt) noexcept {
ExecutionResult ExecutionProcessor::execute_transaction(const Transaction& txn, Receipt& receipt) noexcept {
assert(protocol::validate_transaction(txn, state_, available_gas()) == ValidationResult::kOk);

ExecutionResult res;

// Optimization: since receipt.logs might have some capacity, let's reuse it.
std::swap(receipt.logs, state_.logs());

Expand Down Expand Up @@ -71,9 +73,10 @@ void ExecutionProcessor::execute_transaction(const Transaction& txn, Receipt& re
state_.subtract_from_balance(*txn.from, txn.total_data_gas() * data_gas_price);

const auto eos_evm_version = evm_.get_eos_evm_version();
const auto& gas_params = evm_.get_gas_params();
intx::uint256 inclusion_price;
if( eos_evm_version >= 3 ) inclusion_price = std::min(txn.max_priority_fee_per_gas, txn.max_fee_per_gas - base_fee_per_gas);

const intx::uint128 g0{protocol::intrinsic_gas(txn, rev, eos_evm_version, gas_params)};
const intx::uint128 g0{protocol::intrinsic_gas(txn, rev, eos_evm_version, gas_params_)};
assert(g0 <= UINT64_MAX); // true due to the precondition (transaction must be valid)

const CallResult vm_res{evm_.execute(txn, txn.gas_limit - static_cast<uint64_t>(g0))};
Expand All @@ -90,9 +93,9 @@ void ExecutionProcessor::execute_transaction(const Transaction& txn, Receipt& re
auto gas_left = vm_res.gas_left;
if(contract_creation) {
if( vm_res.status == EVMC_SUCCESS ) {
storage_gas_consumed += gas_params.G_txcreate; //correct storage gas consumed to account for initial G_txcreate storage gas
storage_gas_consumed += gas_params_.G_txcreate; //correct storage gas consumed to account for initial G_txcreate storage gas
} else {
gas_left += gas_params.G_txcreate;
gas_left += gas_params_.G_txcreate;
}
}

Expand All @@ -102,14 +105,46 @@ void ExecutionProcessor::execute_transaction(const Transaction& txn, Receipt& re
gas_left += static_cast<uint64_t>(vm_res_gas_state.collapse());
gas_used = txn.gas_limit - gas_left;
assert(vm_res_gas_state.cpu_gas_refund() == 0);
const auto total_storage_gas_consumed = vm_res_gas_state.storage_gas_consumed();
assert(gas_used > static_cast<uint64_t>(total_storage_gas_consumed));
const auto total_cpu_gas_consumed = gas_used - static_cast<uint64_t>(total_storage_gas_consumed);
(void)total_cpu_gas_consumed;
const auto total_storage_gas_consumed = static_cast<uint64_t>(vm_res_gas_state.storage_gas_consumed());
assert(gas_used > total_storage_gas_consumed);
const auto total_cpu_gas_consumed = gas_used - total_storage_gas_consumed;

// award the fee recipient
const intx::uint256 price{evm_.config().protocol_rule_set == protocol::RuleSetType::kTrust ? effective_gas_price : txn.priority_fee_per_gas(base_fee_per_gas)};
state_.add_to_balance(evm_.beneficiary, price * gas_used);

res.cpu_gas_consumed = total_cpu_gas_consumed;
res.discounted_storage_gas_consumed = static_cast<uint64_t>(total_storage_gas_consumed);
res.inclusion_fee = intx::uint256(total_cpu_gas_consumed)*inclusion_price;
res.storage_fee = intx::uint256(total_storage_gas_consumed)*price;

auto final_fee = price * gas_used;
if(gas_prices_.storage_price >= gas_prices_.overhead_price) {
intx::uint256 gas_refund = intx::uint256(total_cpu_gas_consumed);
gas_refund *= intx::uint256(gas_prices_.storage_price-gas_prices_.overhead_price);
gas_refund /= price;

SILKWORM_ASSERT(gas_refund <= gas_used);
gas_left += static_cast<uint64_t>(gas_refund);
assert(txn.gas_limit >= gas_left);
gas_used = txn.gas_limit - gas_left;
SILKWORM_ASSERT(gas_used >= total_storage_gas_consumed);
final_fee = price * gas_used;

assert(final_fee >= res.storage_fee);
const auto overhead_and_inclusion_fee = final_fee - res.storage_fee;
if( overhead_and_inclusion_fee >= res.inclusion_fee ) {
res.overhead_fee = overhead_and_inclusion_fee - res.inclusion_fee;
} else {
res.inclusion_fee = overhead_and_inclusion_fee;
res.overhead_fee = 0;
}
} else {
res.overhead_fee = final_fee - res.inclusion_fee - res.storage_fee;
}

assert(final_fee == res.inclusion_fee + res.storage_fee + res.overhead_fee);

// award the fee recipient
state_.add_to_balance(evm_.beneficiary, final_fee);
state_.add_to_balance(*txn.from, price * gas_left);
}

Expand All @@ -127,6 +162,7 @@ void ExecutionProcessor::execute_transaction(const Transaction& txn, Receipt& re
receipt.cumulative_gas_used = cumulative_gas_used_;
receipt.bloom = logs_bloom(state_.logs());
std::swap(receipt.logs, state_.logs());
return res;
}

uint64_t ExecutionProcessor::available_gas() const noexcept {
Expand Down
7 changes: 5 additions & 2 deletions silkworm/core/execution/processor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <silkworm/core/types/block.hpp>
#include <silkworm/core/types/receipt.hpp>
#include <silkworm/core/types/transaction.hpp>
#include <silkworm/core/types/gas_prices.hpp>

namespace silkworm {

Expand All @@ -33,13 +34,13 @@ class ExecutionProcessor {
ExecutionProcessor(const ExecutionProcessor&) = delete;
ExecutionProcessor& operator=(const ExecutionProcessor&) = delete;

ExecutionProcessor(const Block& block, protocol::IRuleSet& rule_set, State& state, const ChainConfig& config, const evmone::gas_parameters& gas_params);
ExecutionProcessor(const Block& block, protocol::IRuleSet& rule_set, State& state, const ChainConfig& config, const evmone::gas_parameters& gas_params, const gas_prices_t& gas_prices);

/**
* Execute a transaction, but do not write to the DB yet.
* Precondition: transaction must be valid.
*/
void execute_transaction(const Transaction& txn, Receipt& receipt) noexcept;
ExecutionResult execute_transaction(const Transaction& txn, Receipt& receipt) noexcept;

//! \brief Execute the block and write the result to the DB.
//! \remarks Warning: This method does not verify state root; pre-Byzantium receipt root isn't validated either.
Expand Down Expand Up @@ -71,6 +72,8 @@ class ExecutionProcessor {
IntraBlockState state_;
protocol::IRuleSet& rule_set_;
EVM evm_;
evmone::gas_parameters gas_params_;
gas_prices_t gas_prices_;
};

} // namespace silkworm
Loading
Loading