Skip to content
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
18 changes: 5 additions & 13 deletions core/state_prefetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package core
import (
"sync/atomic"

"github.com/XinFinOrg/XDPoSChain/common"
"github.com/XinFinOrg/XDPoSChain/consensus"
"github.com/XinFinOrg/XDPoSChain/core/state"
"github.com/XinFinOrg/XDPoSChain/core/types"
Expand Down Expand Up @@ -69,7 +68,11 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
return // Also invalid block, bail out
}
statedb.SetTxContext(tx.Hash(), i)
if err := precacheTransaction(msg, gaspool, evm); err != nil {
coinbaseOwner := statedb.GetOwner(evm.Context.Coinbase)

// We attempt to apply a transaction. The goal is not to execute
// the transaction successfully, rather to warm up touched data slots.
if _, err := ApplyMessage(evm, msg, gaspool, coinbaseOwner); err != nil {
return // Ugh, something went horribly wrong, bail out
}
// If we're pre-byzantium, pre-load trie nodes for the intermediate root
Expand All @@ -82,14 +85,3 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
statedb.IntermediateRoot(true)
}
}

// precacheTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. The goal is not to execute
// the transaction successfully, rather to warm up touched data slots.
func precacheTransaction(msg *Message, gaspool *GasPool, evm *vm.EVM) error {
// Update the evm with the new transaction context.
evm.SetTxContext(NewEVMTxContext(msg))
// Add addresses to access list if applicable
_, err := ApplyMessage(evm, msg, gaspool, common.Address{})
return err
}
7 changes: 3 additions & 4 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,9 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, balanceFee *big.Int, coinbaseOwner common.Address) (receipt *types.Receipt, gasUsed uint64, tokenFeeUsed bool, err error) {
if hooks := evm.Config.Tracer; hooks != nil {
if hooks.OnTxStart != nil {
// OnTxStart runs before ApplyMessage, so the execution tx context must be visible
// here too. This is XDPoS-specific because msg.GasPrice can differ from the raw tx.
evm.SetTxContext(NewEVMTxContext(msg))
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
}
if hooks.OnTxEnd != nil {
Expand Down Expand Up @@ -309,10 +312,6 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
return ApplyEmptyTransaction(msg, config, statedb, blockNumber, blockHash, tx, usedGas, evm)
}

// Create a new context to be used in the EVM environment
txContext := NewEVMTxContext(msg)
evm.SetTxContext(txContext)

// Bypass denylist address
maxBlockNumber := new(big.Int).SetInt64(9147459)
if blockNumber.Cmp(maxBlockNumber) <= 0 {
Expand Down
95 changes: 95 additions & 0 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,6 +598,101 @@ func TestApplyTransactionWithEVMStateChangeHooks(t *testing.T) {
}
}

func TestApplyTransactionWithEVMOnTxStartUsesExecutionGasPrice(t *testing.T) {
var (
config = &params.ChainConfig{
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
Eip1559Block: big.NewInt(0),
Ethash: new(params.EthashConfig),
}
signer = types.LatestSigner(config)
testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
sender = crypto.PubkeyToAddress(testKey.PublicKey)
recipient = common.HexToAddress("0x1234567890123456789012345678901234567890")
rawGasPrice = big.NewInt(20000000000)
executionGasPrice = big.NewInt(7)
)

db := rawdb.NewMemoryDatabase()
gspec := &Genesis{
Config: config,
Alloc: types.GenesisAlloc{
sender: {
Balance: big.NewInt(1000000000000000000),
Nonce: 0,
},
},
}
genesis := gspec.MustCommit(db)
blockchain, err := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{})
if err != nil {
t.Fatalf("Failed to create blockchain: %v", err)
}
defer blockchain.Stop()

statedb, err := blockchain.State()
if err != nil {
t.Fatalf("Failed to get state: %v", err)
}

tx := types.NewTransaction(0, recipient, big.NewInt(1), 21000, rawGasPrice, nil)
signedTx, err := types.SignTx(tx, signer, testKey)
if err != nil {
t.Fatalf("Failed to sign tx: %v", err)
}

var seenGasPrice *big.Int
hooks := &tracing.Hooks{
OnTxStart: func(vmContext *tracing.VMContext, tx *types.Transaction, from common.Address) {
if tx == nil {
t.Fatal("OnTxStart called with nil transaction")
}
if from != sender {
t.Fatalf("OnTxStart called with wrong from address: got %v want %v", from, sender)
}
if vmContext.GasPrice == nil {
t.Fatal("OnTxStart saw nil gas price")
}
seenGasPrice = new(big.Int).Set(vmContext.GasPrice)
},
}

msg, err := TransactionToMessage(signedTx, signer, nil, big.NewInt(1), nil)
if err != nil {
t.Fatalf("Failed to build message: %v", err)
}
msg.GasPrice = new(big.Int).Set(executionGasPrice)

gasPool := new(GasPool).AddGas(1000000)
vmContext := NewEVMBlockContext(blockchain.CurrentBlock(), blockchain, nil)
evmenv := vm.NewEVM(vmContext, statedb, nil, blockchain.Config(), vm.Config{Tracer: hooks})

var usedGas uint64
_, _, _, err = ApplyTransactionWithEVM(msg, gasPool, statedb, big.NewInt(1), genesis.Hash(), signedTx, &usedGas, evmenv, nil, common.Address{})
if err != nil {
t.Fatalf("ApplyTransactionWithEVM failed: %v", err)
}
if seenGasPrice == nil {
t.Fatal("expected OnTxStart to observe gas price")
}
if seenGasPrice.Cmp(executionGasPrice) != 0 {
t.Fatalf("OnTxStart saw wrong execution gas price: got %v want %v", seenGasPrice, executionGasPrice)
}
if seenGasPrice.Cmp(rawGasPrice) == 0 {
t.Fatalf("OnTxStart unexpectedly saw raw tx gas price: %v", seenGasPrice)
}
}

func TestProcessParentBlockHash(t *testing.T) {
var (
chainConfig = params.MergedTestChainConfig
Expand Down
46 changes: 22 additions & 24 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,11 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, balanceFee, blo
// indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block.
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool, owner common.Address) (*ExecutionResult, error) {
return NewStateTransition(evm, msg, gp).TransitionDb(owner)
evm.SetTxContext(NewEVMTxContext(msg))
return newStateTransition(evm, msg, gp).execute(owner)
}

// StateTransition represents a state transition.
// stateTransition represents a state transition.
//
// == The State Transitioning Model
//
Expand All @@ -231,7 +232,7 @@ func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool, owner common.Address)
//
// 5. Run Script section
// 6. Derive new state root
type StateTransition struct {
type stateTransition struct {
gp *GasPool
msg *Message
gasRemaining uint64
Expand All @@ -240,25 +241,25 @@ type StateTransition struct {
evm *vm.EVM
}

Comment thread
gzliudan marked this conversation as resolved.
// NewStateTransition initialises and returns a new state transition object.
func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition {
return &StateTransition{
// newStateTransition initialises and returns a new state transition object.
func newStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *stateTransition {
return &stateTransition{
Comment thread
gzliudan marked this conversation as resolved.
gp: gp,
evm: evm,
msg: msg,
state: evm.StateDB,
}
}

func (st *StateTransition) from() common.Address {
func (st *stateTransition) from() common.Address {
f := st.msg.From
if !st.state.Exist(f) {
st.state.CreateAccount(f)
}
return f
}

func (st *StateTransition) to() common.Address {
func (st *stateTransition) to() common.Address {
if st.msg == nil {
return common.Address{}
}
Expand All @@ -272,7 +273,7 @@ func (st *StateTransition) to() common.Address {
return *to
}

func (st *StateTransition) buyGas() error {
func (st *stateTransition) buyGas() error {
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
mgval = mgval.Mul(mgval, st.msg.GasPrice)
if st.msg.BalanceTokenFee == nil {
Expand Down Expand Up @@ -304,7 +305,7 @@ func (st *StateTransition) buyGas() error {
return nil
}

func (st *StateTransition) preCheck() error {
func (st *stateTransition) preCheck() error {
// Only check transactions that are not fake
msg := st.msg
if !msg.SkipNonceChecks {
Expand Down Expand Up @@ -371,20 +372,17 @@ func (st *StateTransition) preCheck() error {
return st.buyGas()
}

// TransitionDb will transition the state by applying the current message and
// execute will transition the state by applying the current message and
// returning the evm execution result with following fields.
//
// - used gas:
// total gas used (including gas being refunded)
// - returndata:
// the returned data from evm
// - concrete execution error:
// various **EVM** error which aborts the execution,
// e.g. ErrOutOfGas, ErrExecutionReverted
// - used gas: total gas used (including gas being refunded)
// - returndata: the returned data from evm
// - concrete execution error: various EVM errors which abort the execution, e.g.
// ErrOutOfGas, ErrExecutionReverted
//
// However if any consensus issue encountered, return the error directly with
// nil evm execution result.
func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult, error) {
func (st *stateTransition) execute(owner common.Address) (*ExecutionResult, error) {
// First check this message satisfies all consensus rules before
// applying the message. The rules include these clauses
//
Expand Down Expand Up @@ -523,7 +521,7 @@ func (st *StateTransition) TransitionDb(owner common.Address) (*ExecutionResult,
}

// validateAuthorization validates an EIP-7702 authorization against the state.
func (st *StateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) {
func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) {
// Verify chain ID is null or equal to current chain ID.
if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 {
return authority, ErrAuthorizationWrongChainID
Expand Down Expand Up @@ -554,7 +552,7 @@ func (st *StateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio
}

// applyAuthorization applies an EIP-7702 code delegation to the state.
func (st *StateTransition) applyAuthorization(msg *Message, auth *types.SetCodeAuthorization) error {
func (st *stateTransition) applyAuthorization(msg *Message, auth *types.SetCodeAuthorization) error {
authority, err := st.validateAuthorization(auth)
if err != nil {
return err
Expand All @@ -581,7 +579,7 @@ func (st *StateTransition) applyAuthorization(msg *Message, auth *types.SetCodeA
}

// calcRefund computes refund counter, capped to a refund quotient.
func (st *StateTransition) calcRefund() uint64 {
func (st *stateTransition) calcRefund() uint64 {
var refund uint64
if !st.evm.ChainConfig().IsEIP1559(st.evm.Context.BlockNumber) {
// Before EIP-3529: refunds were capped to gasUsed / 2
Expand All @@ -601,7 +599,7 @@ func (st *StateTransition) calcRefund() uint64 {

// returnGas returns ETH for remaining gas,
// exchanged at the original rate.
func (st *StateTransition) returnGas() {
func (st *stateTransition) returnGas() {
if st.msg.BalanceTokenFee == nil {
remaining := new(big.Int).SetUint64(st.gasRemaining)
remaining.Mul(remaining, st.msg.GasPrice)
Expand All @@ -618,6 +616,6 @@ func (st *StateTransition) returnGas() {
}

// gasUsed returns the amount of gas used up by the state transition.
func (st *StateTransition) gasUsed() uint64 {
func (st *stateTransition) gasUsed() uint64 {
return st.initialGas - st.gasRemaining
}
4 changes: 1 addition & 3 deletions core/token_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,10 @@ func CallContractWithState(call ethereum.CallMsg, chain consensus.ChainContext,

// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
txContext := NewEVMTxContext(msg)
evmContext := NewEVMBlockContext(chain.CurrentHeader(), chain, nil)
evm := vm.NewEVM(evmContext, statedb, nil, chain.Config(), vm.Config{})
evm.SetTxContext(txContext)
gaspool := new(GasPool).AddGas(1000000)
result, err := NewStateTransition(evm, msg, gaspool).TransitionDb(common.Address{})
result, err := ApplyMessage(evm, msg, gaspool, common.Address{})
if err != nil {
return nil, err
}
Expand Down
7 changes: 5 additions & 2 deletions core/tracing/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ type VMContext struct {
BlockNumber *big.Int
Time uint64
Random *common.Hash
// Effective tx gas price
BaseFee *big.Int
StateDB StateDB

// XDPoS tracers need the execution-time gas price because TransactionToMessage
// may rewrite it for TRC21 and fixed-price fee paths.
GasPrice *big.Int
StateDB StateDB
}

// BlockEvent is emitted upon tracing an incoming block.
Expand Down
5 changes: 4 additions & 1 deletion core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,10 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
BlockNumber: evm.Context.BlockNumber,
Time: evm.Context.Time,
Random: evm.Context.Random,
GasPrice: evm.TxContext.GasPrice,
BaseFee: evm.Context.BaseFee,
StateDB: evm.StateDB,

// Keep GasPrice in the tracer context for XDPoS-specific execution pricing.
GasPrice: evm.TxContext.GasPrice,
}
}
4 changes: 1 addition & 3 deletions eth/gasestimator/gasestimator.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,17 +174,15 @@ func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit ui
func run(ctx context.Context, call *core.Message, opts *Options) (*core.ExecutionResult, error) {
// Assemble the call and the call context
var (
msgContext = core.NewEVMTxContext(call)
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
dirtyState = opts.State.Copy()
)
// Lower the basefee to 0 to avoid breaking EVM
// invariants (basefee < feecap).
if msgContext.GasPrice.Sign() == 0 {
if call.GasPrice.Sign() == 0 {
evmContext.BaseFee = new(big.Int)
}
evm := vm.NewEVM(evmContext, dirtyState, nil, opts.Config, vm.Config{NoBaseFee: true})
evm.SetTxContext(msgContext)

// Monitor the outer context and interrupt the EVM upon cancellation. To avoid
// a dangling goroutine until the outer estimation finishes, create an internal
Expand Down
2 changes: 0 additions & 2 deletions eth/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,6 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
}
// Assemble the transaction call message and return if the requested offset
msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee())
txContext := core.NewEVMTxContext(msg)
evm.SetTxContext(txContext)

// Not yet the searched for transaction, execute on top of the current state
statedb.SetTxContext(tx.Hash(), idx)
Expand Down
8 changes: 1 addition & 7 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,11 +539,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
balance = value
}
}
var (
msg, _ = core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee())
txContext = core.NewEVMTxContext(msg)
)
evm.SetTxContext(txContext)
msg, _ := core.TransactionToMessage(tx, signer, balance, block.Number(), block.BaseFee())
statedb.SetTxContext(tx.Hash(), i)
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil {
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
Expand Down Expand Up @@ -724,7 +720,6 @@ txloop:
header := block.Header()
msg, _ := core.TransactionToMessage(tx, signer, balance, header.Number, header.BaseFee)
statedb.SetTxContext(tx.Hash(), i)
evm.SetTxContext(core.NewEVMTxContext(msg))
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit), common.Address{}); err != nil {
failed = err
break txloop
Expand Down Expand Up @@ -902,7 +897,6 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
}
tracingStateDB := state.NewHookedState(statedb, tracer.Hooks)
evm := vm.NewEVM(vmctx, tracingStateDB, nil, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
evm.SetTxContext(vm.TxContext{GasPrice: message.GasPrice})

// Define a meaningful timeout of a single transaction trace
if config.Timeout != nil {
Expand Down
Loading
Loading