type StateDB struct{
db Database
prefetcher *triePrefetcher
originalRoot common.Hash // The pre-state root, before any changes were made
trie Trie
hasher crypto.KeccakState
snaps *snapshot.Tree
snap snapshot.Snapshot
snapDestructs map[common.Hash]struct{}
snapAccounts map[common.Hash][]byte
snapStorage map[common.Hash]map[common.Hash][]byte// This map holds 'live' objects, which will get modified while processing a state transition.//↓下面这行存储着整一个账号状态,包括上面的图提到的所有内容
stateObjects map[common.Address]*stateObject
stateObjectsPending map[common.Address]struct{}// State objects finalized but not yet written to the trie
stateObjectsDirty map[common.Address]struct{}// State objects modified in the current execution
[core/state/state_object.go]
type stateObject struct{
address common.Address //项目地址
addrHash common.Hash
data Account // 账户状态
db *StateDB
// Account is the Ethereum consensus representation of accounts.// These objects are stored in the main account trie.type Account struct{
Nonce uint64
Balance *big.Int
Root common.Hash // merkle root of the storage trie
CodeHash []byte}
type Stack struct{
data []uint256.Int
}funcnewstack()*Stack {return stackPool.Get().(*Stack)}
[core/vm/memory.go]
// Memory implements a simple memory model for the ethereum virtual machine.type Memory struct{
store []byte
lastGasCost uint64}// NewMemory returns a new memory model.funcNewMemory()*Memory {return&Memory{}}
指令集操作
[core/vm/instruction.go]
funcopAdd(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)([]byte,error){
x, y := scope.Stack.pop(), scope.Stack.peek()
y.Add(&x, y)returnnil,nil}//...//funcopPop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)([]byte,error){
scope.Stack.pop()returnnil,nil}//...////memory operationfuncopMload(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)([]byte,error){
v := scope.Stack.peek()
offset :=int64(v.Uint64())
v.SetBytes(scope.Memory.GetPtr(offset,32))returnnil,nil}//storage operationfuncopMstore(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)([]byte,error){// pop value of the stack
mStart, val := scope.Stack.pop(), scope.Stack.pop()
scope.Memory.Set32(mStart.Uint64(),&val)returnnil,nil}//...////information flow oprationfuncopCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)([]byte,error){
stack := scope.Stack
// Pop gas. The actual gas in interpreter.evm.callGasTemp.// We can use this as a temporary value
temp := stack.pop()
gas := interpreter.evm.callGasTemp
// Pop other call parameters.
addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
toAddr := common.Address(addr.Bytes20())// Get the arguments from the memory.
args := scope.Memory.GetPtr(int64(inOffset.Uint64()),int64(inSize.Uint64()))var bigVal = big0
//TODO: use uint256.Int instead of converting with toBig()// By using big0 here, we save an alloc for the most common case (non-ether-transferring contract calls),// but it would make more sense to extend the usage of uint256.Intif!value.IsZero(){
gas += params.CallStipend
bigVal = value.ToBig()}
ret, returnGas, err := interpreter.evm.Call(scope.Contract, toAddr, args, gas, bigVal)if err !=nil{
temp.Clear()}else{
temp.SetOne()}
stack.push(&temp)if err ==nil|| err == ErrExecutionReverted {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)}
scope.Contract.Gas += returnGas
return ret,nil}
创建EVM和进行交易
[core/state_processor.go]
funcApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config)(*types.Receipt,error){
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))if err !=nil{returnnil, err
}// Create a new context to be used in the EVM environment
blockContext :=NewEVMBlockContext(header, bc, author)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)returnapplyTransaction(msg, config, bc, author, gp, statedb, header, tx, usedGas, vmenv)}