mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 02:40:45 +00:00
all: implement EIP-1153 transient storage (#26003)
This commit is contained in:
parent
1c5e564433
commit
ed242b4763
18 changed files with 446 additions and 67 deletions
|
|
@ -381,7 +381,7 @@ func createBlockFromHeader(bc *core.BlockChain, customHeader *types.Header, txs
|
||||||
var gasUsed = new(uint64)
|
var gasUsed = new(uint64)
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
statedb.Prepare(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
receipt, _, err, _ := core.ApplyTransaction(bc.Config(), nil, bc, &header.Coinbase, gp, statedb, nil, &header, tx, gasUsed, vm.Config{})
|
receipt, _, err, _ := core.ApplyTransaction(bc.Config(), nil, bc, &header.Coinbase, gp, statedb, nil, &header, tx, gasUsed, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%v when applying transaction", err)
|
return nil, fmt.Errorf("%v when applying transaction", err)
|
||||||
|
|
|
||||||
|
|
@ -698,7 +698,7 @@ func createBlockFromHeader(bc *core.BlockChain, customHeader *types.Header, txs
|
||||||
var gasUsed = new(uint64)
|
var gasUsed = new(uint64)
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
statedb.Prepare(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
receipt, _, err, _ := core.ApplyTransaction(bc.Config(), nil, bc, &header.Coinbase, gp, statedb, nil, &header, tx, gasUsed, vm.Config{})
|
receipt, _, err, _ := core.ApplyTransaction(bc.Config(), nil, bc, &header.Coinbase, gp, statedb, nil, &header, tx, gasUsed, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%v when applying transaction", err)
|
return nil, fmt.Errorf("%v when applying transaction", err)
|
||||||
|
|
|
||||||
|
|
@ -1512,3 +1512,100 @@ func TestEIP2718Transition(t *testing.T) {
|
||||||
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expected, block.GasUsed())
|
t.Fatalf("incorrect amount of gas spent: expected %d, got %d", expected, block.GasUsed())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestTransientStorageReset ensures the transient storage is wiped correctly
|
||||||
|
// between transactions.
|
||||||
|
func TestTransientStorageReset(t *testing.T) {
|
||||||
|
var (
|
||||||
|
engine = ethash.NewFaker()
|
||||||
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
destAddress = crypto.CreateAddress(address, 0)
|
||||||
|
funds = big.NewInt(1000000000000000)
|
||||||
|
vmConfig = vm.Config{
|
||||||
|
ExtraEips: []int{1153}, // Enable transient storage EIP
|
||||||
|
}
|
||||||
|
)
|
||||||
|
code := append([]byte{
|
||||||
|
// TLoad value with location 1
|
||||||
|
byte(vm.PUSH1), 0x1,
|
||||||
|
byte(vm.TLOAD),
|
||||||
|
|
||||||
|
// PUSH location
|
||||||
|
byte(vm.PUSH1), 0x1,
|
||||||
|
|
||||||
|
// SStore location:value
|
||||||
|
byte(vm.SSTORE),
|
||||||
|
}, make([]byte, 32-6)...)
|
||||||
|
initCode := []byte{
|
||||||
|
// TSTORE 1:1
|
||||||
|
byte(vm.PUSH1), 0x1,
|
||||||
|
byte(vm.PUSH1), 0x1,
|
||||||
|
byte(vm.TSTORE),
|
||||||
|
|
||||||
|
// Get the runtime-code on the stack
|
||||||
|
byte(vm.PUSH32)}
|
||||||
|
initCode = append(initCode, code...)
|
||||||
|
initCode = append(initCode, []byte{
|
||||||
|
byte(vm.PUSH1), 0x0, // offset
|
||||||
|
byte(vm.MSTORE),
|
||||||
|
byte(vm.PUSH1), 0x6, // size
|
||||||
|
byte(vm.PUSH1), 0x0, // offset
|
||||||
|
byte(vm.RETURN), // return 6 bytes of zero-code
|
||||||
|
}...)
|
||||||
|
gspec := &Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: GenesisAlloc{
|
||||||
|
address: {Balance: funds},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
nonce := uint64(0)
|
||||||
|
signer := types.HomesteadSigner{}
|
||||||
|
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
|
||||||
|
fee := big.NewInt(1)
|
||||||
|
if b.header.BaseFee != nil {
|
||||||
|
fee = b.header.BaseFee
|
||||||
|
}
|
||||||
|
b.SetCoinbase(common.Address{1})
|
||||||
|
tx, _ := types.SignNewTx(key, signer, &types.LegacyTx{
|
||||||
|
Nonce: nonce,
|
||||||
|
GasPrice: new(big.Int).Set(fee),
|
||||||
|
Gas: 100000,
|
||||||
|
Data: initCode,
|
||||||
|
})
|
||||||
|
nonce++
|
||||||
|
b.AddTxWithVMConfig(tx, vmConfig)
|
||||||
|
|
||||||
|
tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{
|
||||||
|
Nonce: nonce,
|
||||||
|
GasPrice: new(big.Int).Set(fee),
|
||||||
|
Gas: 100000,
|
||||||
|
To: &destAddress,
|
||||||
|
})
|
||||||
|
b.AddTxWithVMConfig(tx, vmConfig)
|
||||||
|
nonce++
|
||||||
|
})
|
||||||
|
|
||||||
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
|
// Initialize the blockchain with 1153 enabled.
|
||||||
|
chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vmConfig)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
// Import the blocks
|
||||||
|
if _, err := chain.InsertChain(blocks); err != nil {
|
||||||
|
t.Fatalf("failed to insert into chain: %v", err)
|
||||||
|
}
|
||||||
|
// Check the storage
|
||||||
|
state, err := chain.StateAt(chain.CurrentHeader().Root)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to load state %v", err)
|
||||||
|
}
|
||||||
|
loc := common.BytesToHash([]byte{1})
|
||||||
|
slot := state.GetState(destAddress, loc)
|
||||||
|
if slot != (common.Hash{}) {
|
||||||
|
t.Fatalf("Unexpected dirty storage slot")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,31 @@ func (b *BlockGen) SetExtra(data []byte) {
|
||||||
b.header.Extra = data
|
b.header.Extra = data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addTx adds a transaction to the generated block. If no coinbase has
|
||||||
|
// been set, the block's coinbase is set to the zero address.
|
||||||
|
//
|
||||||
|
// There are a few options can be passed as well in order to run some
|
||||||
|
// customized rules.
|
||||||
|
// - bc: enables the ability to query historical block hashes for BLOCKHASH
|
||||||
|
// - vmConfig: extends the flexibility for customizing evm rules, e.g. enable extra EIPs
|
||||||
|
func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transaction) {
|
||||||
|
if b.gasPool == nil {
|
||||||
|
b.SetCoinbase(common.Address{})
|
||||||
|
}
|
||||||
|
feeCapacity := state.GetTRC21FeeCapacityFromState(b.statedb)
|
||||||
|
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
|
||||||
|
receipt, gas, err, tokenFeeUsed := ApplyTransaction(b.config, feeCapacity, bc, &b.header.Coinbase, b.gasPool, b.statedb, nil, b.header, tx, &b.header.GasUsed, vmConfig)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
b.txs = append(b.txs, tx)
|
||||||
|
b.receipts = append(b.receipts, receipt)
|
||||||
|
if tokenFeeUsed {
|
||||||
|
fee := common.GetGasFee(b.header.Number.Uint64(), gas)
|
||||||
|
state.UpdateTRC21Fee(b.statedb, map[common.Address]*big.Int{*tx.To(): new(big.Int).Sub(feeCapacity[*tx.To()], new(big.Int).SetUint64(gas))}, fee)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// AddTx adds a transaction to the generated block. If no coinbase has
|
// AddTx adds a transaction to the generated block. If no coinbase has
|
||||||
// been set, the block's coinbase is set to the zero address.
|
// been set, the block's coinbase is set to the zero address.
|
||||||
//
|
//
|
||||||
|
|
@ -84,7 +109,7 @@ func (b *BlockGen) SetExtra(data []byte) {
|
||||||
// added. Notably, contract code relying on the BLOCKHASH instruction
|
// added. Notably, contract code relying on the BLOCKHASH instruction
|
||||||
// will panic during execution.
|
// will panic during execution.
|
||||||
func (b *BlockGen) AddTx(tx *types.Transaction) {
|
func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||||
b.AddTxWithChain(nil, tx)
|
b.addTx(nil, vm.Config{}, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTxWithChain adds a transaction to the generated block. If no coinbase has
|
// AddTxWithChain adds a transaction to the generated block. If no coinbase has
|
||||||
|
|
@ -96,21 +121,14 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||||
// added. If contract code relies on the BLOCKHASH instruction,
|
// added. If contract code relies on the BLOCKHASH instruction,
|
||||||
// the block in chain will be returned.
|
// the block in chain will be returned.
|
||||||
func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
|
func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
|
||||||
if b.gasPool == nil {
|
b.addTx(bc, vm.Config{}, tx)
|
||||||
b.SetCoinbase(common.Address{})
|
}
|
||||||
}
|
|
||||||
feeCapacity := state.GetTRC21FeeCapacityFromState(b.statedb)
|
// AddTxWithVMConfig adds a transaction to the generated block. If no coinbase has
|
||||||
b.statedb.Prepare(tx.Hash(), len(b.txs))
|
// been set, the block's coinbase is set to the zero address.
|
||||||
receipt, gas, err, tokenFeeUsed := ApplyTransaction(b.config, feeCapacity, bc, &b.header.Coinbase, b.gasPool, b.statedb, nil, b.header, tx, &b.header.GasUsed, vm.Config{})
|
// The evm interpreter can be customized with the provided vm config.
|
||||||
if err != nil {
|
func (b *BlockGen) AddTxWithVMConfig(tx *types.Transaction, config vm.Config) {
|
||||||
panic(err)
|
b.addTx(nil, config, tx)
|
||||||
}
|
|
||||||
b.txs = append(b.txs, tx)
|
|
||||||
b.receipts = append(b.receipts, receipt)
|
|
||||||
if tokenFeeUsed {
|
|
||||||
fee := common.GetGasFee(b.header.Number.Uint64(), gas)
|
|
||||||
state.UpdateTRC21Fee(b.statedb, map[common.Address]*big.Int{*tx.To(): new(big.Int).Sub(feeCapacity[*tx.To()], new(big.Int).SetUint64(gas))}, fee)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddUncheckedTx forcefully adds a transaction to the block without any
|
// AddUncheckedTx forcefully adds a transaction to the block without any
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,11 @@ type (
|
||||||
address *common.Address
|
address *common.Address
|
||||||
slot *common.Hash
|
slot *common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transientStorageChange struct {
|
||||||
|
account *common.Address
|
||||||
|
key, prevalue common.Hash
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ch createObjectChange) undo(s *StateDB) {
|
func (ch createObjectChange) undo(s *StateDB) {
|
||||||
|
|
@ -134,6 +139,10 @@ func (ch storageChange) undo(s *StateDB) {
|
||||||
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ch transientStorageChange) undo(s *StateDB) {
|
||||||
|
s.setTransientState(*ch.account, ch.key, ch.prevalue)
|
||||||
|
}
|
||||||
|
|
||||||
func (ch refundChange) undo(s *StateDB) {
|
func (ch refundChange) undo(s *StateDB) {
|
||||||
s.refund = ch.prev
|
s.refund = ch.prev
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||||
"github.com/XinFinOrg/XDPoSChain/log"
|
"github.com/XinFinOrg/XDPoSChain/log"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||||
"github.com/XinFinOrg/XDPoSChain/trie"
|
"github.com/XinFinOrg/XDPoSChain/trie"
|
||||||
)
|
)
|
||||||
|
|
@ -69,6 +70,9 @@ type StateDB struct {
|
||||||
// Per-transaction access list
|
// Per-transaction access list
|
||||||
accessList *accessList
|
accessList *accessList
|
||||||
|
|
||||||
|
// Transient storage
|
||||||
|
transientStorage transientStorage
|
||||||
|
|
||||||
// Journal of state modifications. This is the backbone of
|
// Journal of state modifications. This is the backbone of
|
||||||
// Snapshot and RevertToSnapshot.
|
// Snapshot and RevertToSnapshot.
|
||||||
journal journal
|
journal journal
|
||||||
|
|
@ -117,6 +121,7 @@ func New(root common.Hash, db Database) (*StateDB, error) {
|
||||||
logs: make(map[common.Hash][]*types.Log),
|
logs: make(map[common.Hash][]*types.Log),
|
||||||
preimages: make(map[common.Hash][]byte),
|
preimages: make(map[common.Hash][]byte),
|
||||||
accessList: newAccessList(),
|
accessList: newAccessList(),
|
||||||
|
transientStorage: newTransientStorage(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,6 +411,35 @@ func (s *StateDB) Suicide(addr common.Address) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTransientState sets transient storage for a given account. It
|
||||||
|
// adds the change to the journal so that it can be rolled back
|
||||||
|
// to its previous value if there is a revert.
|
||||||
|
func (s *StateDB) SetTransientState(addr common.Address, key, value common.Hash) {
|
||||||
|
prev := s.GetTransientState(addr, key)
|
||||||
|
if prev == value {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s.journal = append(s.journal, transientStorageChange{
|
||||||
|
account: &addr,
|
||||||
|
key: key,
|
||||||
|
prevalue: prev,
|
||||||
|
})
|
||||||
|
|
||||||
|
s.setTransientState(addr, key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setTransientState is a lower level setter for transient storage. It
|
||||||
|
// is called during a revert to prevent modifications to the journal.
|
||||||
|
func (s *StateDB) setTransientState(addr common.Address, key, value common.Hash) {
|
||||||
|
s.transientStorage.Set(addr, key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransientState gets transient storage for a given account.
|
||||||
|
func (s *StateDB) GetTransientState(addr common.Address, key common.Hash) common.Hash {
|
||||||
|
return s.transientStorage.Get(addr, key)
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Setting, updating & deleting state object methods.
|
// Setting, updating & deleting state object methods.
|
||||||
//
|
//
|
||||||
|
|
@ -577,6 +611,9 @@ func (s *StateDB) Copy() *StateDB {
|
||||||
// However, it doesn't cost us much to copy an empty list, so we do it anyway
|
// However, it doesn't cost us much to copy an empty list, so we do it anyway
|
||||||
// to not blow up if we ever decide copy it in the middle of a transaction
|
// to not blow up if we ever decide copy it in the middle of a transaction
|
||||||
state.accessList = s.accessList.Copy()
|
state.accessList = s.accessList.Copy()
|
||||||
|
|
||||||
|
state.transientStorage = s.transientStorage.Copy()
|
||||||
|
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -638,9 +675,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
return s.trie.Hash()
|
return s.trie.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare sets the current transaction hash and index and block hash which is
|
// SetTxContext sets the current transaction hash and index which are
|
||||||
// used when the EVM emits new state logs.
|
// used when the EVM emits new state logs. It should be invoked before
|
||||||
func (s *StateDB) Prepare(thash common.Hash, ti int) {
|
// transaction execution.
|
||||||
|
func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
|
||||||
s.thash = thash
|
s.thash = thash
|
||||||
s.txIndex = ti
|
s.txIndex = ti
|
||||||
}
|
}
|
||||||
|
|
@ -717,33 +755,39 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
|
||||||
return root, err
|
return root, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrepareAccessList handles the preparatory steps for executing a state transition with
|
// Prepare handles the preparatory steps for executing a state transition with.
|
||||||
// regards to both EIP-2929 and EIP-2930:
|
// This method must be invoked before state transition.
|
||||||
//
|
//
|
||||||
|
// Berlin fork:
|
||||||
// - Add sender to access list (2929)
|
// - Add sender to access list (2929)
|
||||||
// - Add destination to access list (2929)
|
// - Add destination to access list (2929)
|
||||||
// - Add precompiles to access list (2929)
|
// - Add precompiles to access list (2929)
|
||||||
// - Add the contents of the optional tx access list (2930)
|
// - Add the contents of the optional tx access list (2930)
|
||||||
//
|
//
|
||||||
// This method should only be called if Yolov3/Berlin/2929+2930 is applicable at the current number.
|
// Potential EIPs:
|
||||||
func (s *StateDB) PrepareAccessList(sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
|
// - Reset transient storage(1153)
|
||||||
// Clear out any leftover from previous executions
|
func (s *StateDB) Prepare(rules params.Rules, sender common.Address, dst *common.Address, precompiles []common.Address, list types.AccessList) {
|
||||||
s.accessList = newAccessList()
|
if rules.IsEIP1559 {
|
||||||
|
// Clear out any leftover from previous executions
|
||||||
|
s.accessList = newAccessList()
|
||||||
|
|
||||||
s.AddAddressToAccessList(sender)
|
s.AddAddressToAccessList(sender)
|
||||||
if dst != nil {
|
if dst != nil {
|
||||||
s.AddAddressToAccessList(*dst)
|
s.AddAddressToAccessList(*dst)
|
||||||
// If it's a create-tx, the destination will be added inside evm.create
|
// If it's a create-tx, the destination will be added inside evm.create
|
||||||
}
|
}
|
||||||
for _, addr := range precompiles {
|
for _, addr := range precompiles {
|
||||||
s.AddAddressToAccessList(addr)
|
s.AddAddressToAccessList(addr)
|
||||||
}
|
}
|
||||||
for _, el := range list {
|
for _, el := range list {
|
||||||
s.AddAddressToAccessList(el.Address)
|
s.AddAddressToAccessList(el.Address)
|
||||||
for _, key := range el.StorageKeys {
|
for _, key := range el.StorageKeys {
|
||||||
s.AddSlotToAccessList(el.Address, key)
|
s.AddSlotToAccessList(el.Address, key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Reset transient storage at the beginning of transaction execution
|
||||||
|
s.transientStorage = newTransientStorage()
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddAddressToAccessList adds the given address to the access list
|
// AddAddressToAccessList adds the given address to the access list
|
||||||
|
|
|
||||||
|
|
@ -297,6 +297,16 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
|
||||||
},
|
},
|
||||||
args: make([]int64, 1),
|
args: make([]int64, 1),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "SetTransientState",
|
||||||
|
fn: func(a testAction, s *StateDB) {
|
||||||
|
var key, val common.Hash
|
||||||
|
binary.BigEndian.PutUint16(key[:], uint16(a.args[0]))
|
||||||
|
binary.BigEndian.PutUint16(val[:], uint16(a.args[1]))
|
||||||
|
s.SetTransientState(addr, key, val)
|
||||||
|
},
|
||||||
|
args: make([]int64, 2),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
action := actions[r.Intn(len(actions))]
|
action := actions[r.Intn(len(actions))]
|
||||||
var nameargs []string
|
var nameargs []string
|
||||||
|
|
@ -615,3 +625,37 @@ func TestStateDBAccessList(t *testing.T) {
|
||||||
t.Fatalf("expected empty, got %d", got)
|
t.Fatalf("expected empty, got %d", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStateDBTransientStorage(t *testing.T) {
|
||||||
|
memDb := rawdb.NewMemoryDatabase()
|
||||||
|
db := NewDatabase(memDb)
|
||||||
|
state, _ := New(common.Hash{}, db)
|
||||||
|
|
||||||
|
key := common.Hash{0x01}
|
||||||
|
value := common.Hash{0x02}
|
||||||
|
addr := common.Address{}
|
||||||
|
|
||||||
|
state.SetTransientState(addr, key, value)
|
||||||
|
if exp, got := 1, state.journal.length(); exp != got {
|
||||||
|
t.Fatalf("journal length mismatch: have %d, want %d", got, exp)
|
||||||
|
}
|
||||||
|
// the retrieved value should equal what was set
|
||||||
|
if got := state.GetTransientState(addr, key); got != value {
|
||||||
|
t.Fatalf("transient storage mismatch: have %x, want %x", got, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// revert the transient state being set and then check that the
|
||||||
|
// value is now the empty hash
|
||||||
|
state.journal[0].undo(state)
|
||||||
|
if got, exp := state.GetTransientState(addr, key), (common.Hash{}); exp != got {
|
||||||
|
t.Fatalf("transient storage mismatch: have %x, want %x", got, exp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set transient state and then copy the statedb and ensure that
|
||||||
|
// the transient state is copied
|
||||||
|
state.SetTransientState(addr, key, value)
|
||||||
|
cpy := state.Copy()
|
||||||
|
if got := cpy.GetTransientState(addr, key); got != value {
|
||||||
|
t.Fatalf("transient storage mismatch: have %x, want %x", got, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
55
core/state/transient_storage.go
Normal file
55
core/state/transient_storage.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2022 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
// transientStorage is a representation of EIP-1153 "Transient Storage".
|
||||||
|
type transientStorage map[common.Address]Storage
|
||||||
|
|
||||||
|
// newTransientStorage creates a new instance of a transientStorage.
|
||||||
|
func newTransientStorage() transientStorage {
|
||||||
|
return make(transientStorage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the transient-storage `value` for `key` at the given `addr`.
|
||||||
|
func (t transientStorage) Set(addr common.Address, key, value common.Hash) {
|
||||||
|
if _, ok := t[addr]; !ok {
|
||||||
|
t[addr] = make(Storage)
|
||||||
|
}
|
||||||
|
t[addr][key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get gets the transient storage for `key` at the given `addr`.
|
||||||
|
func (t transientStorage) Get(addr common.Address, key common.Hash) common.Hash {
|
||||||
|
val, ok := t[addr]
|
||||||
|
if !ok {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
return val[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy does a deep copy of the transientStorage
|
||||||
|
func (t transientStorage) Copy() transientStorage {
|
||||||
|
storage := make(transientStorage)
|
||||||
|
for key, value := range t {
|
||||||
|
storage[key] = value.Copy()
|
||||||
|
}
|
||||||
|
return storage
|
||||||
|
}
|
||||||
|
|
@ -117,7 +117,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, tra
|
||||||
return nil, nil, 0, err
|
return nil, nil, 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statedb.Prepare(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, gp, statedb, coinbaseOwner, blockNumber, header.BaseFee, blockHash, tx, usedGas, vmenv)
|
receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, gp, statedb, coinbaseOwner, blockNumber, header.BaseFee, blockHash, tx, usedGas, vmenv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, err
|
return nil, nil, 0, err
|
||||||
|
|
@ -197,7 +197,7 @@ func (p *StateProcessor) ProcessBlockNoValidator(cBlock *CalculatedBlock, stated
|
||||||
return nil, nil, 0, err
|
return nil, nil, 0, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statedb.Prepare(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, gp, statedb, coinbaseOwner, blockNumber, header.BaseFee, blockHash, tx, usedGas, vmenv)
|
receipt, gas, err, tokenFeeUsed := applyTransaction(p.config, balanceFee, gp, statedb, coinbaseOwner, blockNumber, header.BaseFee, blockHash, tx, usedGas, vmenv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, 0, err
|
return nil, nil, 0, err
|
||||||
|
|
@ -466,6 +466,7 @@ func ApplyTransaction(config *params.ChainConfig, tokensFee map[common.Address]*
|
||||||
blockContext := NewEVMBlockContext(header, bc, author)
|
blockContext := NewEVMBlockContext(header, bc, author)
|
||||||
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, XDCxState, config, cfg)
|
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, XDCxState, config, cfg)
|
||||||
coinbaseOwner := getCoinbaseOwner(bc, statedb, header, author)
|
coinbaseOwner := getCoinbaseOwner(bc, statedb, header, author)
|
||||||
|
// return applyTransaction(config, tokensFee, gp, statedb, coinbaseOwner, header.Number, header.BaseFee, header.Hash(), tx, usedGas, vmenv)
|
||||||
return applyTransaction(config, tokensFee, gp, statedb, coinbaseOwner, header.Number, header.BaseFee, header.Hash(), tx, usedGas, vmenv)
|
return applyTransaction(config, tokensFee, gp, statedb, coinbaseOwner, header.Number, header.BaseFee, header.Hash(), tx, usedGas, vmenv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -329,9 +329,10 @@ func (st *StateTransition) TransitionDb(owner common.Address) (ret []byte, usedG
|
||||||
return nil, 0, false, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize), nil
|
return nil, 0, false, fmt.Errorf("%w: code size %v limit %v", ErrMaxInitCodeSizeExceeded, len(st.data), params.MaxInitCodeSize), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if rules.IsEIP1559 {
|
// Execute the preparatory steps for state transition which includes:
|
||||||
st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
// - prepare accessList(post-berlin)
|
||||||
}
|
// - reset transient storage(eip 1153)
|
||||||
|
st.state.Prepare(rules, msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
|
||||||
|
|
||||||
var (
|
var (
|
||||||
evm = st.evm
|
evm = st.evm
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ var activators = map[int]func(*JumpTable){
|
||||||
2200: enable2200,
|
2200: enable2200,
|
||||||
1884: enable1884,
|
1884: enable1884,
|
||||||
1344: enable1344,
|
1344: enable1344,
|
||||||
|
1153: enable1153,
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableEIP enables the given EIP on the config.
|
// EnableEIP enables the given EIP on the config.
|
||||||
|
|
@ -157,6 +158,45 @@ func enable3198(jt *JumpTable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enable1153 applies EIP-1153 "Transient Storage"
|
||||||
|
// - Adds TLOAD that reads from transient storage
|
||||||
|
// - Adds TSTORE that writes to transient storage
|
||||||
|
func enable1153(jt *JumpTable) {
|
||||||
|
jt[TLOAD] = &operation{
|
||||||
|
execute: opTload,
|
||||||
|
constantGas: params.WarmStorageReadCostEIP2929,
|
||||||
|
minStack: minStack(1, 1),
|
||||||
|
maxStack: maxStack(1, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
jt[TSTORE] = &operation{
|
||||||
|
execute: opTstore,
|
||||||
|
constantGas: params.WarmStorageReadCostEIP2929,
|
||||||
|
minStack: minStack(2, 0),
|
||||||
|
maxStack: maxStack(2, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// opTload implements TLOAD opcode
|
||||||
|
func opTload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
loc := scope.Stack.peek()
|
||||||
|
hash := common.Hash(loc.Bytes32())
|
||||||
|
val := interpreter.evm.StateDB.GetTransientState(scope.Contract.Address(), hash)
|
||||||
|
loc.SetBytes(val.Bytes())
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// opTstore implements TSTORE opcode
|
||||||
|
func opTstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
|
||||||
|
if interpreter.readOnly {
|
||||||
|
return nil, ErrWriteProtection
|
||||||
|
}
|
||||||
|
loc := scope.Stack.pop()
|
||||||
|
val := scope.Stack.pop()
|
||||||
|
interpreter.evm.StateDB.SetTransientState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// opBaseFee implements BASEFEE opcode
|
// opBaseFee implements BASEFEE opcode
|
||||||
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) {
|
func opBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error) {
|
||||||
baseFee, _ := uint256.FromBig(common.BaseFee)
|
baseFee, _ := uint256.FromBig(common.BaseFee)
|
||||||
|
|
|
||||||
|
|
@ -539,8 +539,7 @@ func opSstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
||||||
}
|
}
|
||||||
loc := scope.Stack.pop()
|
loc := scope.Stack.pop()
|
||||||
val := scope.Stack.pop()
|
val := scope.Stack.pop()
|
||||||
interpreter.evm.StateDB.SetState(scope.Contract.Address(),
|
interpreter.evm.StateDB.SetState(scope.Contract.Address(), loc.Bytes32(), val.Bytes32())
|
||||||
loc.Bytes32(), val.Bytes32())
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/rawdb"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/state"
|
||||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||||
"github.com/XinFinOrg/XDPoSChain/params"
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
|
|
@ -46,6 +48,14 @@ var alphabetSoup = "ABCDEF090807060504030201ffffffffffffffffffffffffffffffffffff
|
||||||
var commonParams []*twoOperandParams
|
var commonParams []*twoOperandParams
|
||||||
var twoOpMethods map[string]executionFunc
|
var twoOpMethods map[string]executionFunc
|
||||||
|
|
||||||
|
type contractRef struct {
|
||||||
|
addr common.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c contractRef) Address() common.Address {
|
||||||
|
return c.addr
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Params is a list of common edgecases that should be used for some common tests
|
// Params is a list of common edgecases that should be used for some common tests
|
||||||
params := []string{
|
params := []string{
|
||||||
|
|
@ -574,6 +584,49 @@ func BenchmarkOpMstore(bench *testing.B) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOpTstore(t *testing.T) {
|
||||||
|
var (
|
||||||
|
statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()))
|
||||||
|
env = NewEVM(BlockContext{}, TxContext{}, statedb, nil, params.TestChainConfig, Config{})
|
||||||
|
stack = newstack()
|
||||||
|
mem = NewMemory()
|
||||||
|
evmInterpreter = NewEVMInterpreter(env, env.Config)
|
||||||
|
caller = common.Address{}
|
||||||
|
to = common.Address{1}
|
||||||
|
contractRef = contractRef{caller}
|
||||||
|
contract = NewContract(contractRef, AccountRef(to), new(big.Int), 0)
|
||||||
|
scopeContext = ScopeContext{mem, stack, contract}
|
||||||
|
value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add a stateObject for the caller and the contract being called
|
||||||
|
statedb.CreateAccount(caller)
|
||||||
|
statedb.CreateAccount(to)
|
||||||
|
|
||||||
|
env.interpreter = evmInterpreter
|
||||||
|
pc := uint64(0)
|
||||||
|
// push the value to the stack
|
||||||
|
stack.push(new(uint256.Int).SetBytes(value))
|
||||||
|
// push the location to the stack
|
||||||
|
stack.push(new(uint256.Int))
|
||||||
|
opTstore(&pc, evmInterpreter, &scopeContext)
|
||||||
|
// there should be no elements on the stack after TSTORE
|
||||||
|
if stack.len() != 0 {
|
||||||
|
t.Fatal("stack wrong size")
|
||||||
|
}
|
||||||
|
// push the location to the stack
|
||||||
|
stack.push(new(uint256.Int))
|
||||||
|
opTload(&pc, evmInterpreter, &scopeContext)
|
||||||
|
// there should be one element on the stack after TLOAD
|
||||||
|
if stack.len() != 1 {
|
||||||
|
t.Fatal("stack wrong size")
|
||||||
|
}
|
||||||
|
val := stack.peek()
|
||||||
|
if !bytes.Equal(val.Bytes(), value) {
|
||||||
|
t.Fatal("incorrect element read from transient storage")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func BenchmarkOpKeccak256(bench *testing.B) {
|
func BenchmarkOpKeccak256(bench *testing.B) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
env = NewEVM(BlockContext{}, TxContext{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
|
|
||||||
"github.com/XinFinOrg/XDPoSChain/common"
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StateDB is an EVM database for full state querying.
|
// StateDB is an EVM database for full state querying.
|
||||||
|
|
@ -47,6 +48,9 @@ type StateDB interface {
|
||||||
GetState(common.Address, common.Hash) common.Hash
|
GetState(common.Address, common.Hash) common.Hash
|
||||||
SetState(common.Address, common.Hash, common.Hash)
|
SetState(common.Address, common.Hash, common.Hash)
|
||||||
|
|
||||||
|
GetTransientState(addr common.Address, key common.Hash) common.Hash
|
||||||
|
SetTransientState(addr common.Address, key, value common.Hash)
|
||||||
|
|
||||||
Suicide(common.Address) bool
|
Suicide(common.Address) bool
|
||||||
HasSuicided(common.Address) bool
|
HasSuicided(common.Address) bool
|
||||||
|
|
||||||
|
|
@ -57,7 +61,6 @@ type StateDB interface {
|
||||||
// is defined according to EIP161 (balance = nonce = code = 0).
|
// is defined according to EIP161 (balance = nonce = code = 0).
|
||||||
Empty(common.Address) bool
|
Empty(common.Address) bool
|
||||||
|
|
||||||
PrepareAccessList(sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
|
|
||||||
AddressInAccessList(addr common.Address) bool
|
AddressInAccessList(addr common.Address) bool
|
||||||
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
|
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
|
||||||
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
|
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
|
||||||
|
|
@ -66,6 +69,7 @@ type StateDB interface {
|
||||||
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
|
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
|
||||||
// even if the feature/fork is not active yet
|
// even if the feature/fork is not active yet
|
||||||
AddSlotToAccessList(addr common.Address, slot common.Hash)
|
AddSlotToAccessList(addr common.Address, slot common.Hash)
|
||||||
|
Prepare(rules params.Rules, sender common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
|
||||||
|
|
||||||
RevertToSnapshot(int)
|
RevertToSnapshot(int)
|
||||||
Snapshot() int
|
Snapshot() int
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,8 @@ const (
|
||||||
MSIZE OpCode = 0x59
|
MSIZE OpCode = 0x59
|
||||||
GAS OpCode = 0x5a
|
GAS OpCode = 0x5a
|
||||||
JUMPDEST OpCode = 0x5b
|
JUMPDEST OpCode = 0x5b
|
||||||
|
TLOAD OpCode = 0x5c
|
||||||
|
TSTORE OpCode = 0x5d
|
||||||
PUSH0 OpCode = 0x5f
|
PUSH0 OpCode = 0x5f
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -297,6 +299,8 @@ var opCodeToString = [256]string{
|
||||||
MSIZE: "MSIZE",
|
MSIZE: "MSIZE",
|
||||||
GAS: "GAS",
|
GAS: "GAS",
|
||||||
JUMPDEST: "JUMPDEST",
|
JUMPDEST: "JUMPDEST",
|
||||||
|
TLOAD: "TLOAD",
|
||||||
|
TSTORE: "TSTORE",
|
||||||
PUSH0: "PUSH0",
|
PUSH0: "PUSH0",
|
||||||
|
|
||||||
// 0x60 range - push.
|
// 0x60 range - push.
|
||||||
|
|
@ -460,6 +464,8 @@ var stringToOp = map[string]OpCode{
|
||||||
"MSIZE": MSIZE,
|
"MSIZE": MSIZE,
|
||||||
"GAS": GAS,
|
"GAS": GAS,
|
||||||
"JUMPDEST": JUMPDEST,
|
"JUMPDEST": JUMPDEST,
|
||||||
|
"TLOAD": TLOAD,
|
||||||
|
"TSTORE": TSTORE,
|
||||||
"PUSH0": PUSH0,
|
"PUSH0": PUSH0,
|
||||||
"PUSH1": PUSH1,
|
"PUSH1": PUSH1,
|
||||||
"PUSH2": PUSH2,
|
"PUSH2": PUSH2,
|
||||||
|
|
|
||||||
|
|
@ -120,10 +120,13 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
||||||
address = common.BytesToAddress([]byte("contract"))
|
address = common.BytesToAddress([]byte("contract"))
|
||||||
vmenv = NewEnv(cfg)
|
vmenv = NewEnv(cfg)
|
||||||
sender = vm.AccountRef(cfg.Origin)
|
sender = vm.AccountRef(cfg.Origin)
|
||||||
|
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
|
||||||
)
|
)
|
||||||
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsEIP1559 {
|
// Execute the preparatory steps for state transition which includes:
|
||||||
cfg.State.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
|
// - prepare accessList(post-berlin)
|
||||||
}
|
// - reset transient storage(eip 1153)
|
||||||
|
cfg.State.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
|
||||||
|
|
||||||
cfg.State.CreateAccount(address)
|
cfg.State.CreateAccount(address)
|
||||||
// set the receiver's (the executing contract) code for execution.
|
// set the receiver's (the executing contract) code for execution.
|
||||||
cfg.State.SetCode(address, code)
|
cfg.State.SetCode(address, code)
|
||||||
|
|
@ -135,7 +138,6 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
||||||
cfg.GasLimit,
|
cfg.GasLimit,
|
||||||
cfg.Value,
|
cfg.Value,
|
||||||
)
|
)
|
||||||
|
|
||||||
return ret, cfg.State, err
|
return ret, cfg.State, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,10 +155,13 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
||||||
var (
|
var (
|
||||||
vmenv = NewEnv(cfg)
|
vmenv = NewEnv(cfg)
|
||||||
sender = vm.AccountRef(cfg.Origin)
|
sender = vm.AccountRef(cfg.Origin)
|
||||||
|
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
|
||||||
)
|
)
|
||||||
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsEIP1559 {
|
// Execute the preparatory steps for state transition which includes:
|
||||||
cfg.State.PrepareAccessList(cfg.Origin, nil, vm.ActivePrecompiles(rules), nil)
|
// - prepare accessList(post-berlin)
|
||||||
}
|
// - reset transient storage(eip 1153)
|
||||||
|
cfg.State.Prepare(rules, cfg.Origin, nil, vm.ActivePrecompiles(rules), nil)
|
||||||
|
|
||||||
// Call the code with the given configuration.
|
// Call the code with the given configuration.
|
||||||
code, address, leftOverGas, err := vmenv.Create(
|
code, address, leftOverGas, err := vmenv.Create(
|
||||||
sender,
|
sender,
|
||||||
|
|
@ -175,13 +180,16 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
||||||
func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {
|
func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) {
|
||||||
setDefaults(cfg)
|
setDefaults(cfg)
|
||||||
|
|
||||||
vmenv := NewEnv(cfg)
|
var (
|
||||||
|
vmenv = NewEnv(cfg)
|
||||||
sender := cfg.State.GetOrNewStateObject(cfg.Origin)
|
sender = cfg.State.GetOrNewStateObject(cfg.Origin)
|
||||||
statedb := cfg.State
|
statedb = cfg.State
|
||||||
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsEIP1559 {
|
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
|
||||||
statedb.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
|
)
|
||||||
}
|
// Execute the preparatory steps for state transition which includes:
|
||||||
|
// - prepare accessList(post-berlin)
|
||||||
|
// - reset transient storage(eip 1153)
|
||||||
|
statedb.Prepare(rules, cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
|
||||||
|
|
||||||
// Call the code with the given configuration.
|
// Call the code with the given configuration.
|
||||||
ret, leftOverGas, err := vmenv.Call(
|
ret, leftOverGas, err := vmenv.Call(
|
||||||
|
|
|
||||||
|
|
@ -522,7 +522,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block,
|
||||||
header := block.Header()
|
header := block.Header()
|
||||||
msg, _ := tx.AsMessage(signer, balance, header.Number, header.BaseFee)
|
msg, _ := tx.AsMessage(signer, balance, header.Number, header.BaseFee)
|
||||||
txContext := core.NewEVMTxContext(msg)
|
txContext := core.NewEVMTxContext(msg)
|
||||||
statedb.Prepare(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
|
|
||||||
vmenv := vm.NewEVM(blockCtx, txContext, statedb, XDCxState, api.config, vm.Config{})
|
vmenv := vm.NewEVM(blockCtx, txContext, statedb, XDCxState, api.config, vm.Config{})
|
||||||
owner := common.Address{}
|
owner := common.Address{}
|
||||||
|
|
@ -746,8 +746,8 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, t
|
||||||
// Run the transaction with tracing enabled.
|
// Run the transaction with tracing enabled.
|
||||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, nil, api.config, vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
|
vmenv := vm.NewEVM(vmctx, txContext, statedb, nil, api.config, vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
|
||||||
|
|
||||||
// Call Prepare to clear out the statedb access list
|
// Call SetTxContext to clear out the statedb access list
|
||||||
statedb.Prepare(txctx.TxHash, txctx.TxIndex)
|
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||||
|
|
||||||
owner := common.Address{}
|
owner := common.Address{}
|
||||||
ret, gas, failed, err, _ := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), owner)
|
ret, gas, failed, err, _ := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()), owner)
|
||||||
|
|
@ -799,7 +799,7 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int, ree
|
||||||
usedGas := new(uint64)
|
usedGas := new(uint64)
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
statedb.Prepare(tx.Hash(), idx)
|
statedb.SetTxContext(tx.Hash(), idx)
|
||||||
if idx == txIndex {
|
if idx == txIndex {
|
||||||
var balanceFee *big.Int
|
var balanceFee *big.Int
|
||||||
if tx.To() != nil {
|
if tx.To() != nil {
|
||||||
|
|
|
||||||
|
|
@ -911,7 +911,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Start executing the transaction
|
// Start executing the transaction
|
||||||
w.state.Prepare(hash, w.tcount)
|
w.state.SetTxContext(hash, w.tcount)
|
||||||
|
|
||||||
nonce := w.state.GetNonce(from)
|
nonce := w.state.GetNonce(from)
|
||||||
if nonce != tx.Nonce() && !tx.IsSkipNonceTransaction() {
|
if nonce != tx.Nonce() && !tx.IsSkipNonceTransaction() {
|
||||||
|
|
@ -1012,7 +1012,7 @@ func (w *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Addr
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Start executing the transaction
|
// Start executing the transaction
|
||||||
w.state.Prepare(hash, w.tcount)
|
w.state.SetTxContext(hash, w.tcount)
|
||||||
nonce := w.state.GetNonce(from)
|
nonce := w.state.GetNonce(from)
|
||||||
if nonce > tx.Nonce() {
|
if nonce > tx.Nonce() {
|
||||||
// New head notification data race between the transaction pool and miner, shift
|
// New head notification data race between the transaction pool and miner, shift
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue