// MsgEthermint implements a cosmos equivalent structure for Ethereum transactions
typeMsgEthermintstruct{AccountNonceuint64`json:"nonce"`Pricesdk.Int`json:"gasPrice"`GasLimituint64`json:"gas"`Recipient*sdk.AccAddress`json:"to" rlp:"nil"`// nil means contract creation
Amountsdk.Int`json:"value"`Payload[]byte`json:"input"`// From address (formerly derived from signature)
Fromsdk.AccAddress`json:"from"`}
// MsgEthereumTx encapsulates an Ethereum transaction as an SDK message.
typeMsgEthereumTxstruct{DataTxData// caches
sizeatomic.Valuefromatomic.Value}// TxData implements the Ethereum transaction data structure. It is used
// solely as intended in Ethereum abiding by the protocol.
typeTxDatastruct{AccountNonceuint64`json:"nonce"`Price*big.Int`json:"gasPrice"`GasLimituint64`json:"gas"`Recipient*ethcmn.Address`json:"to" rlp:"nil"`// nil means contract creation
Amount*big.Int`json:"value"`Payload[]byte`json:"input"`// signature values
V*big.Int`json:"v"`R*big.Int`json:"r"`S*big.Int`json:"s"`// hash is only used when marshaling to JSON
Hash*ethcmn.Hash`json:"hash" rlp:"-"`}
// https://github.com/ethereum/go-ethereum/blob/v1.9.25/core/vm/evm.go#L161
// NewEVM returns a new EVM. The returned EVM is not thread safe and should
// only ever be used *once*.
funcNewEVM(blockCtxBlockContext,txCtxTxContext,statedbStateDB,chainConfig*params.ChainConfig,vmConfigConfig)*EVM{evm:=&EVM{Context:blockCtx,TxContext:txCtx,StateDB:statedb,vmConfig:vmConfig,chainConfig:chainConfig,chainRules:chainConfig.Rules(blockCtx.BlockNumber),interpreters:make([]Interpreter,0,1),}// ...
// vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here
// as we always want to have the built-in EVM as the failover option.
evm.interpreters=append(evm.interpreters,NewEVMInterpreter(evm,vmConfig))evm.interpreter=evm.interpreters[0]returnevm}
// StateDB is an EVM database for full state querying.
typeStateDBinterface{CreateAccount(common.Address)SubBalance(common.Address,*big.Int)AddBalance(common.Address,*big.Int)GetBalance(common.Address)*big.IntGetNonce(common.Address)uint64SetNonce(common.Address,uint64)GetCodeHash(common.Address)common.HashGetCode(common.Address)[]byteSetCode(common.Address,[]byte)GetCodeSize(common.Address)intAddRefund(uint64)SubRefund(uint64)GetRefund()uint64GetCommittedState(common.Address,common.Hash)common.HashGetState(common.Address,common.Hash)common.HashSetState(common.Address,common.Hash,common.Hash)Suicide(common.Address)boolHasSuicided(common.Address)bool// Exist reports whether the given account exists in state.
// Notably this should also return true for suicided accounts.
Exist(common.Address)bool// Empty returns whether the given account is empty. Empty
// is defined according to EIP161 (balance = nonce = code = 0).
Empty(common.Address)boolAddressInAccessList(addrcommon.Address)boolSlotInAccessList(addrcommon.Address,slotcommon.Hash)(addressOkbool,slotOkbool)// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddAddressToAccessList(addrcommon.Address)// 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
AddSlotToAccessList(addrcommon.Address,slotcommon.Hash)RevertToSnapshot(int)Snapshot()intAddLog(*types.Log)AddPreimage(common.Hash,[]byte)ForEachStorage(common.Address,func(common.Hash,common.Hash)bool)error}
https://github.com/cosmos/cosmos-sdk/blob/v0.39.2/store/types/store.go#L175-L205
// KVStore is a simple interface to get/set data
typeKVStoreinterface{Store// Get returns nil iff key doesn't exist. Panics on nil key.
Get(key[]byte)[]byte// Has checks if a key exists. Panics on nil key.
Has(key[]byte)bool// Set sets the key. Panics on nil key or value.
Set(key,value[]byte)// Delete deletes the key. Panics on nil key.
Delete(key[]byte)// Iterator over a domain of keys in ascending order. End is exclusive.
// Start must be less than end, or the Iterator is invalid.
// Iterator must be closed by caller.
// To iterate over entire domain, use store.Iterator(nil, nil)
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
// Exceptionally allowed for cachekv.Store, safe to write in the modules.
Iterator(start,end[]byte)Iterator// Iterator over a domain of keys in descending order. End is exclusive.
// Start must be less than end, or the Iterator is invalid.
// Iterator must be closed by caller.
// CONTRACT: No writes may happen within a domain while an iterator exists over it.
// Exceptionally allowed for cachekv.Store, safe to write in the modules.
ReverseIterator(start,end[]byte)Iterator}
这里我们以KeyPrefixHeightHash 为例来展示下 Prefix Store 是如何使用的:
1
2
3
4
5
6
7
// https://github.com/cosmos/ethermint/blob/v0.4.0/x/evm/types/statedb.go#L120-L125
// SetHeightHash sets the block header hash associated with a given height.
func(csdb*CommitStateDB)SetHeightHash(heightuint64,hashethcmn.Hash){store:=prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey),KeyPrefixHeightHash)key:=HeightHashKey(height)store.Set(key,hash.Bytes())}
// GetCode returns the code for a given account.
func(csdb*CommitStateDB)GetCode(addrethcmn.Address)[]byte{so:=csdb.getStateObject(addr)ifso!=nil{returnso.Code(nil)}returnnil}
// Code returns the contract code associated with this object, if any.
func(so*stateObject)Code(_ethstate.Database)[]byte{iflen(so.code)>0{returnso.code}ifbytes.Equal(so.CodeHash(),emptyCodeHash){returnnil}ctx:=so.stateDB.ctxstore:=prefix.NewStore(ctx.KVStore(so.stateDB.storeKey),KeyPrefixCode)code:=store.Get(so.CodeHash())iflen(code)==0{so.setError(fmt.Errorf("failed to get code hash %x for address %s",so.CodeHash(),so.Address().String()))}returncode}
// GetState retrieves a value from the account storage trie. Note, the key will
// be prefixed with the address of the state object.
func(so*stateObject)GetState(dbethstate.Database,keyethcmn.Hash)ethcmn.Hash{prefixKey:=so.GetStorageByAddressKey(key.Bytes())// if we have a dirty value for this state entry, return it
idx,dirty:=so.keyToDirtyStorageIndex[prefixKey]ifdirty{returnso.dirtyStorage[idx].Value}// otherwise return the entry's original value
value:=so.GetCommittedState(db,key)returnvalue}// GetCommittedState retrieves a value from the committed account storage trie.
//
// NOTE: the key will be prefixed with the address of the state object.
func(so*stateObject)GetCommittedState(_ethstate.Database,keyethcmn.Hash)ethcmn.Hash{prefixKey:=so.GetStorageByAddressKey(key.Bytes())// if we have the original value cached, return that
idx,cached:=so.keyToOriginStorageIndex[prefixKey]ifcached{returnso.originStorage[idx].Value}// otherwise load the value from the KVStore
state:=NewState(prefixKey,ethcmn.Hash{})ctx:=so.stateDB.ctxstore:=prefix.NewStore(ctx.KVStore(so.stateDB.storeKey),AddressStoragePrefix(so.Address()))rawValue:=store.Get(prefixKey.Bytes())iflen(rawValue)>0{state.Value.SetBytes(rawValue)}so.originStorage=append(so.originStorage,state)so.keyToOriginStorageIndex[prefixKey]=len(so.originStorage)-1returnstate.Value}
// https://github.com/cosmos/cosmos-sdk/blob/v0.39.2/x/auth/types/stdtx.go#L23-L30
// StdTx is a standard way to wrap a Msg with Fee and Signatures.
// NOTE: the first signature is the fee payer (Signatures must not be nil).
typeStdTxstruct{Msgs[]sdk.Msg`json:"msg" yaml:"msg"`FeeStdFee`json:"fee" yaml:"fee"`Signatures[]StdSignature`json:"signatures" yaml:"signatures"`Memostring`json:"memo" yaml:"memo"`}
func(app*BaseApp)runMsgs(ctxsdk.Context,msgs[]sdk.Msg,moderunTxMode)(*sdk.Result,error){msgLogs:=make(sdk.ABCIMessageLogs,0,len(msgs))data:=make([]byte,0,len(msgs))events:=sdk.EmptyEvents()// NOTE: GasWanted is determined by the AnteHandler and GasUsed by the GasMeter.
fori,msg:=rangemsgs{// skip actual execution for (Re)CheckTx mode
ifmode==runTxModeCheck||mode==runTxModeReCheck{break}msgRoute:=msg.Route()handler:=app.router.Route(ctx,msgRoute)ifhandler==nil{returnnil,sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest,"unrecognized message route: %s; message index: %d",msgRoute,i)}msgResult,err:=handler(ctx,msg)iferr!=nil{returnnil,sdkerrors.Wrapf(err,"failed to execute message; message index: %d",i)}// ...
}return&sdk.Result{Data:data,Log:strings.TrimSpace(msgLogs.String()),Events:events,},nil}
typeBaseAppstruct{// ...
cmssdk.CommitMultiStore// Main (uncached) state
// ...
checkState*state// for CheckTx
deliverState*state// for DeliverTx
// ...
}