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

split vm.Context into BlockContext and TxContext #638

Merged
merged 1 commit into from
Sep 21, 2024
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
6 changes: 4 additions & 2 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,10 +379,12 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call XDPoSChain.Cal
msg.CallMsg.BalanceTokenFee = value
}
}
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil)

txContext := core.NewEVMTxContext(msg)
evmContext := core.NewEVMBlockContext(block.Header(), b.blockchain, nil)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, statedb, nil, b.config, vm.Config{})
vmenv := vm.NewEVM(evmContext, txContext, statedb, nil, b.config, vm.Config{})
gaspool := new(core.GasPool).AddGas(math.MaxUint64)
owner := common.Address{}
ret, usedGas, failed, err, _ = core.NewStateTransition(vmenv, msg, gaspool).TransitionDb(owner)
Expand Down
16 changes: 11 additions & 5 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import (
"github.com/XinFinOrg/XDPoSChain/crypto"
)

// NewEVMContext creates a new context for use in the EVM.
func NewEVMContext(msg Message, header *types.Header, chain consensus.ChainContext, author *common.Address) vm.Context {
// NewEVMBlockContext creates a new context for use in the EVM.
func NewEVMBlockContext(header *types.Header, chain consensus.ChainContext, author *common.Address) vm.BlockContext {
// If we don't have an explicit author (i.e. not mining), extract from the header
var (
beneficiary common.Address
Expand All @@ -40,21 +40,27 @@ func NewEVMContext(msg Message, header *types.Header, chain consensus.ChainConte
}
// since xdpos chain do not use difficulty and mixdigest, we use hash of the block number as random
random = crypto.Keccak256Hash(header.Number.Bytes())
return vm.Context{
return vm.BlockContext{
CanTransfer: CanTransfer,
Transfer: Transfer,
GetHash: GetHashFn(header, chain),
Origin: msg.From(),
Coinbase: beneficiary,
BlockNumber: new(big.Int).Set(header.Number),
Time: new(big.Int).Set(header.Time),
Difficulty: new(big.Int).Set(header.Difficulty),
GasLimit: header.GasLimit,
GasPrice: new(big.Int).Set(msg.GasPrice()),
Random: &random,
}
}

// NewEVMTxContext creates a new transaction context for a single transaction.
func NewEVMTxContext(msg Message) vm.TxContext {
return vm.TxContext{
Origin: msg.From(),
GasPrice: new(big.Int).Set(msg.GasPrice()),
}
}

// GetHashFn returns a GetHashFunc which retrieves header hashes by number
func GetHashFn(ref *types.Header, chain consensus.ChainContext) func(n uint64) common.Hash {
// Cache will initially contain [refHash.parent],
Expand Down
41 changes: 27 additions & 14 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra
InitSignerInTransactions(p.config, header, block.Transactions())
balanceUpdated := map[common.Address]*big.Int{}
totalFeeUsed := big.NewInt(0)
blockContext := NewEVMBlockContext(header, p.bc, nil)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, tradingState, p.config, cfg)
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() {
// check black-list txs after hf
if (block.Number().Uint64() >= common.BlackListHFNumber) && !common.IsTestnet {
Expand Down Expand Up @@ -113,7 +116,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra
}
}
statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, gas, err, tokenFeeUsed := ApplyTransaction(p.config, balanceFee, p.bc, nil, gp, statedb, tradingState, header, tx, usedGas, cfg)
receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, p.bc, nil, gp, statedb, tradingState, header, tx, usedGas, vmenv)
if err != nil {
return nil, nil, 0, err
}
Expand Down Expand Up @@ -159,6 +162,8 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
if cBlock.stop {
return nil, nil, 0, ErrStopPreparingBlock
}
blockContext := NewEVMBlockContext(header, p.bc, nil)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, tradingState, p.config, cfg)
// Iterate over and process the individual transactions
receipts = make([]*types.Receipt, block.Transactions().Len())
for i, tx := range block.Transactions() {
Expand Down Expand Up @@ -188,7 +193,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
}
}
statedb.Prepare(tx.Hash(), block.Hash(), i)
receipt, gas, err, tokenFeeUsed := ApplyTransaction(p.config, balanceFee, p.bc, nil, gp, statedb, tradingState, header, tx, usedGas, cfg)
receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, p.bc, nil, gp, statedb, tradingState, header, tx, usedGas, vmenv)
if err != nil {
return nil, nil, 0, err
}
Expand All @@ -210,11 +215,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
return receipts, allLogs, *usedGas, nil
}

// ApplyTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*big.Int, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error, bool) {
func applyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*big.Int, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, uint64, error, bool) {
to := tx.To()
if to != nil && *to == common.BlockSignersBinary && config.IsTIPSigning(header.Number) {
return ApplySignTransaction(config, statedb, header, tx, usedGas)
Expand Down Expand Up @@ -243,11 +244,12 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
if err != nil {
return nil, 0, err, false
}
// Create a new context to be used in the EVM environment.
context := NewEVMContext(msg, header, bc, author)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(context, statedb, XDCxState, config, cfg)

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

// Update the evm with the new transaction context.
evm.Reset(txContext, statedb)

// If we don't have an explicit author (i.e. not mining), extract from the header
var beneficiary common.Address
Expand Down Expand Up @@ -404,7 +406,7 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
// End Bypass blacklist address

// Apply the transaction to the current state (included in the env)
_, gas, failed, err, _ := ApplyMessage(vmenv, msg, gp, coinbaseOwner)
_, gas, failed, err, _ := ApplyMessage(evm, msg, gp, coinbaseOwner)

if err != nil {
return nil, 0, err, false
Expand Down Expand Up @@ -432,7 +434,7 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*

// If the transaction created a contract, store the creation address in the receipt.
if msg.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
}

// Set the receipt logs and create the bloom filter.
Expand All @@ -447,6 +449,17 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
return receipt, gas, err, balanceFee != nil
}

// ApplyTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. It returns the receipt
// for the transaction, gas used and an error if the transaction failed,
// indicating the block was invalid.
func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*big.Int, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, XDCxState *tradingstate.TradingStateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error, bool) {
// Create a new context to be used in the EVM environment
blockContext := NewEVMBlockContext(header, bc, author)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, XDCxState, config, cfg)
return applyTransaction(config, tokensFee, bc, author, gp, statedb, XDCxState, header, tx , usedGas, vmenv)
}

func ApplySignTransaction(config *params.ChainConfig, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64) (*types.Receipt, uint64, error, bool) {
// Update the state with pending changes
var root []byte
Expand Down
31 changes: 26 additions & 5 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,16 +216,37 @@ func (st *StateTransition) preCheck() error {
}

// TransitionDb will transition the state by applying the current message and
// returning the result including the the used gas. It returns an error if it
// failed. An error indicates a consensus issue.
// 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
//
// However if any consensus issue encountered, return the error directly with
// nil evm execution result.
func (st *StateTransition) TransitionDb(owner common.Address) (ret []byte, usedGas uint64, failed bool, err error, vmErr error) {
// First check this message satisfies all consensus rules before
// applying the message. The rules include these clauses
//
// 1. the nonce of the message caller is correct
// 2. caller has enough balance to cover transaction fee(gaslimit * gasprice)
// 3. the amount of gas required is available in the block
// 4. the purchased gas is enough to cover intrinsic usage
// 5. there is no overflow when calculating intrinsic gas
// 6. caller has enough balance to cover asset transfer for **topmost** call

// Check clauses 1-3, buy gas if everything is correct
if err = st.preCheck(); err != nil {
return
}
msg := st.msg
sender := st.from() // err checked in preCheck

homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)
homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber)
contractCreation := msg.To() == nil

// Pay intrinsic gas
Expand Down Expand Up @@ -274,12 +295,12 @@ func (st *StateTransition) TransitionDb(owner common.Address) (ret []byte, usedG
}
st.refundGas()

if st.evm.BlockNumber.Cmp(common.TIPTRC21Fee) > 0 {
if st.evm.Context.BlockNumber.Cmp(common.TIPTRC21Fee) > 0 {
if (owner != common.Address{}) {
st.state.AddBalance(owner, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
}
} else {
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
st.state.AddBalance(st.evm.Context.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
}

return ret, st.gasUsed(), vmerr != nil, nil, vmerr
Expand Down
5 changes: 3 additions & 2 deletions core/token_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,11 @@ func CallContractWithState(call ethereum.CallMsg, chain consensus.ChainContext,
msg.CallMsg.BalanceTokenFee = value
}
}
evmContext := NewEVMContext(msg, chain.CurrentHeader(), chain, nil)
txContext := NewEVMTxContext(msg)
evmContext := NewEVMBlockContext(chain.CurrentHeader(), chain, nil)
// Create a new environment which holds all relevant information
// about the transaction and calling mechanisms.
vmenv := vm.NewEVM(evmContext, statedb, nil, chain.Config(), vm.Config{})
vmenv := vm.NewEVM(evmContext, txContext, statedb, nil, chain.Config(), vm.Config{})
gaspool := new(GasPool).AddGas(1000000)
owner := common.Address{}
rval, _, _, err, _ := NewStateTransition(vmenv, msg, gaspool).TransitionDb(owner)
Expand Down
4 changes: 2 additions & 2 deletions core/vm/contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ func testXDCxPrecompiled(addr string, test precompiledTest, t *testing.T) {
tradingStateDB.SetLastPrice(tradingstate.GetTradingOrderBookHash(common.HexToAddress(BTCAddress), common.HexToAddress(USDTAddress)), BTCUSDTLastPrice)
tradingStateDB.SetMediumPriceBeforeEpoch(tradingstate.GetTradingOrderBookHash(common.HexToAddress(BTCAddress), common.HexToAddress(USDTAddress)), BTCUSDTEpochPrice)

evm := NewEVM(Context{BlockNumber: common.Big1}, nil, tradingStateDB, &params.ChainConfig{ByzantiumBlock: common.Big0}, Config{})
evm := NewEVM(BlockContext{BlockNumber: common.Big1}, TxContext{}, nil, tradingStateDB, &params.ChainConfig{ByzantiumBlock: common.Big0}, Config{})
contractAddr := common.HexToAddress(addr)
p := PrecompiledContractsByzantium[contractAddr]
in := common.Hex2Bytes(test.input)
Expand All @@ -536,7 +536,7 @@ func testXDCxPrecompiled(addr string, test precompiledTest, t *testing.T) {
}

func testPrecompiledWithEmptyTradingState(addr string, test precompiledTest, t *testing.T) {
evm := NewEVM(Context{BlockNumber: common.Big1}, nil, nil, &params.ChainConfig{ByzantiumBlock: common.Big0}, Config{})
evm := NewEVM(BlockContext{BlockNumber: common.Big1}, TxContext{}, nil, nil, &params.ChainConfig{ByzantiumBlock: common.Big0}, Config{})

contractAddr := common.HexToAddress(addr)
p := PrecompiledContractsByzantium[contractAddr]
Expand Down
Loading