Skip to content

Commit

Permalink
core: implement bor_transfer (#2284)
Browse files Browse the repository at this point in the history
* core: implement bor_transfer

* restore current bailout logic
  • Loading branch information
yperbasis authored Sep 3, 2024
1 parent 970a420 commit 43d436d
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 34 deletions.
10 changes: 2 additions & 8 deletions silkworm/core/execution/evm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,7 @@ evmc::Result EVM::create(const evmc_message& message) noexcept {
state_.set_nonce(contract_addr, 1);
}

if (!gas_bailout_ || have >= value) {
state_.subtract_from_balance(message.sender, value);
}
state_.add_to_balance(contract_addr, value);
transfer(state_, message.sender, contract_addr, value, gas_bailout_);

const evmc_message deploy_message{
.kind = message.depth > 0 ? message.kind : EVMC_CALL,
Expand Down Expand Up @@ -221,10 +218,7 @@ evmc::Result EVM::call(const evmc_message& message) noexcept {
// https://github.com/ethereum/go-ethereum/blob/v1.9.25/core/vm/evm.go#L391
state_.touch(message.recipient);
} else {
if (!gas_bailout_ || have >= value) {
state_.subtract_from_balance(message.sender, value);
}
state_.add_to_balance(message.recipient, value);
transfer(state_, message.sender, message.recipient, value, gas_bailout_);
}
}

Expand Down
16 changes: 16 additions & 0 deletions silkworm/core/execution/evm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <evmone/baseline.hpp>
#include <evmone/execution_state.hpp>
#include <evmone/vm.hpp>
#include <gsl/pointers>
#include <intx/intx.hpp>

#include <silkworm/core/chain/config.hpp>
Expand Down Expand Up @@ -72,6 +73,19 @@ using EvmTracers = std::vector<std::reference_wrapper<EvmTracer>>;

using AnalysisCache = LruCache<evmc::bytes32, std::shared_ptr<evmone::baseline::CodeAnalysis>>;

using TransferFunc = void(IntraBlockState& state, const evmc::address& sender, const evmc::address& recipient,
const intx::uint256& amount, bool bailout);

// See consensus.Transfer in Erigon
inline void standard_transfer(IntraBlockState& state, const evmc::address& sender, const evmc::address& recipient,
const intx::uint256& amount, bool bailout) {
// TODO(yperbasis) why is the bailout condition different from Erigon?
if (!bailout || state.get_balance(sender) >= amount) {
state.subtract_from_balance(sender, amount);
}
state.add_to_balance(recipient, amount);
}

class EVM {
public:
// Not copyable nor movable
Expand Down Expand Up @@ -104,6 +118,8 @@ class EVM {

evmc::address beneficiary; // see IRuleSet::get_beneficiary

gsl::not_null<TransferFunc*> transfer{standard_transfer};

private:
friend class EvmHost;

Expand Down
1 change: 1 addition & 0 deletions silkworm/core/execution/processor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ ExecutionProcessor::ExecutionProcessor(const Block& block, protocol::RuleSet& ru
const ChainConfig& config)
: state_{state}, rule_set_{rule_set}, evm_{block, state_, config} {
evm_.beneficiary = rule_set.get_beneficiary(block.header);
evm_.transfer = rule_set.transfer_func();
}

void ExecutionProcessor::execute_transaction(const Transaction& txn, Receipt& receipt) noexcept {
Expand Down
85 changes: 59 additions & 26 deletions silkworm/core/protocol/bor_rule_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,37 +141,70 @@ evmc::address BorRuleSet::get_beneficiary(const BlockHeader& header) {
return *ecrecover(header, config().jaipur_block);
}

// See https://github.com/maticnetwork/bor/blob/v1.0.6/core/bor_fee_log.go
namespace {
// See https://github.com/maticnetwork/bor/blob/v1.3.7/core/bor_fee_log.go
void add_transfer_log(IntraBlockState& state, const evmc::bytes32& event_sig, const evmc::address& sender,
const evmc::address& recipient, const intx::uint256& amount,
const intx::uint256& input1, const intx::uint256& input2,
const intx::uint256& output1, const intx::uint256& output2) {
if (amount == 0) {
return;
}
static constexpr evmc::address kFeeAddress{0x0000000000000000000000000000000000001010_address};
SILKWORM_THREAD_LOCAL Log log{
.address = kFeeAddress,
.topics = {
{},
to_bytes32(kFeeAddress.bytes),
{},
{},
},
.data = Bytes(32 * 5, 0),
};
log.topics[0] = event_sig;
log.topics[2] = to_bytes32(sender.bytes);
log.topics[3] = to_bytes32(recipient.bytes);

intx::be::unsafe::store(&log.data[32 * 0], amount);
intx::be::unsafe::store(&log.data[32 * 1], input1);
intx::be::unsafe::store(&log.data[32 * 2], input2);
intx::be::unsafe::store(&log.data[32 * 3], output1);
intx::be::unsafe::store(&log.data[32 * 4], output2);

state.add_log(log);
}

void bor_transfer(IntraBlockState& state, const evmc::address& sender, const evmc::address& recipient,
const intx::uint256& amount, bool bailout) {
static constexpr auto kTransferLogSig{
0xe6497e3ee548a3372136af2fcb0696db31fc6cf20260707645068bd3fe97f3c4_bytes32};
intx::uint256 sender_initial_balance{state.get_balance(sender)};
intx::uint256 recipient_initial_balance{state.get_balance(recipient)};
// TODO(yperbasis) why is the bailout condition different from that of Erigon?
if (!bailout || sender_initial_balance >= amount) {
state.subtract_from_balance(sender, amount);
}
state.add_to_balance(recipient, amount);
intx::uint256 output1{state.get_balance(sender)};
intx::uint256 output2{state.get_balance(recipient)};
add_transfer_log(state, kTransferLogSig, sender, recipient, amount, sender_initial_balance,
recipient_initial_balance, output1, output2);
}
} // namespace

void BorRuleSet::add_fee_transfer_log(IntraBlockState& state, const intx::uint256& amount, const evmc::address& sender,
const intx::uint256& sender_initial_balance, const evmc::address& recipient,
const intx::uint256& recipient_initial_balance) {
SILKWORM_ASSERT(amount <= sender_initial_balance);

static constexpr evmc::address kFeeAddress{0x0000000000000000000000000000000000001010_address};
static constexpr evmc::bytes32 kTransferFeeLogSig{
static constexpr auto kTransferFeeLogSig{
0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63_bytes32};
SILKWORM_ASSERT(amount <= sender_initial_balance);
add_transfer_log(state, kTransferFeeLogSig, sender, recipient, amount,
sender_initial_balance, recipient_initial_balance,
sender_initial_balance - amount, recipient_initial_balance + amount);
}

SILKWORM_THREAD_LOCAL Log log{
.address = kFeeAddress,
.topics = {
kTransferFeeLogSig,
to_bytes32(kFeeAddress.bytes),
{},
{},
},
.data = Bytes(32 * 5, 0),
};

log.topics[2] = to_bytes32(sender.bytes);
log.topics[3] = to_bytes32(recipient.bytes);

intx::be::unsafe::store(&log.data[32 * 0], amount);
intx::be::unsafe::store(&log.data[32 * 1], sender_initial_balance);
intx::be::unsafe::store(&log.data[32 * 2], recipient_initial_balance);
intx::be::unsafe::store(&log.data[32 * 3], sender_initial_balance - amount);
intx::be::unsafe::store(&log.data[32 * 4], recipient_initial_balance + amount);

state.add_log(log);
TransferFunc* BorRuleSet::transfer_func() const {
return bor_transfer;
}

const bor::Config& BorRuleSet::config() const {
Expand Down
2 changes: 2 additions & 0 deletions silkworm/core/protocol/bor_rule_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ class BorRuleSet : public RuleSet {
const intx::uint256& sender_initial_balance, const evmc::address& recipient,
const intx::uint256& recipient_initial_balance) override;

TransferFunc* transfer_func() const override;

protected:
ValidationResult validate_extra_data(const BlockHeader& header) const override;

Expand Down
2 changes: 2 additions & 0 deletions silkworm/core/protocol/rule_set.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class RuleSet {
const intx::uint256& sender_initial_balance, const evmc::address& recipient,
const intx::uint256& recipient_initial_balance);

virtual TransferFunc* transfer_func() const { return standard_transfer; }

protected:
explicit RuleSet(const ChainConfig& chain_config, bool prohibit_ommers)
: chain_config_{&chain_config}, prohibit_ommers_{prohibit_ommers} {}
Expand Down
1 change: 1 addition & 0 deletions silkworm/rpc/core/evm_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ ExecutionResult EVMExecutor::call(
evm.analysis_cache = svc.get_analysis_cache();
evm.state_pool = svc.get_object_pool();
evm.beneficiary = rule_set_->get_beneficiary(block.header);
evm.transfer = rule_set_->transfer_func();

for (auto& tracer : tracers) {
evm.add_tracer(*tracer);
Expand Down

0 comments on commit 43d436d

Please sign in to comment.