Finish and clean up module queries and txs (#152)

* Basic transactions set up (to be separated)

* Change transaction command to not include create operation (to include other command in next commit)

* set up create command and made minor changes

* wip implements module queries

* Added tests for query address decoding

* Added ambiguous encoding of to address in transaction and added tests

* Fix linting issue

* Move registering key types to application level to allow module usage to ignore

* Move genaccounts code to be reused

* Switches nonce increase to always happen in ante handler

* change SetNonce from keeper to point to actual nonce operation

* Remove no op nonce switch (not needed with clearing cache)

* Changes to update all accounts pre state transition and clear cache at end of block

* Update accounts before end of block commit (edge case where necessary)

* Fix nonce of sender going into evm in case it's checked, and let evm set contract starting nonce
This commit is contained in:
Austin Abell
2019-11-15 12:02:13 -05:00
committed by GitHub
parent 9311f9efd0
commit 6eef37b0c6
15 changed files with 341 additions and 119 deletions
-1
View File
@@ -10,7 +10,6 @@ var ModuleCdc = codec.New()
func init() {
cdc := codec.New()
RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
ModuleCdc = cdc.Seal()
+1 -1
View File
@@ -2,7 +2,7 @@ package types
const (
// ModuleName string name of module
ModuleName = "ethermint"
ModuleName = "evm"
// EvmStoreKey key for ethereum storage data
EvmStoreKey = "evmstore"
+15 -21
View File
@@ -30,11 +30,8 @@ type StateTransition struct {
// TransitionCSDB performs an evm state transition from a transaction
func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result) {
contractCreation := st.Recipient == nil
if res := st.checkNonce(); !res.IsOK() {
return nil, res
}
contractCreation := st.Recipient == nil
cost, err := core.IntrinsicGas(st.Payload, contractCreation, true)
if err != nil {
@@ -44,7 +41,7 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
// This gas limit the the transaction gas limit with intrinsic gas subtracted
gasLimit := st.GasLimit - ctx.GasMeter().GasConsumed()
csdb := st.Csdb
csdb := st.Csdb.WithContext(ctx)
if st.Simulate {
// gasLimit is set here because stdTxs incur gaskv charges in the ante handler, but for eth_call
// the cost needs to be the same as an Ethereum transaction sent through the web3 API
@@ -59,6 +56,9 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
csdb = st.Csdb.Copy()
}
// Clear cache of accounts to handle changes outside of the EVM
csdb.UpdateAccounts()
// Create context for evm
context := vm.Context{
CanTransfer: core.CanTransfer,
@@ -88,14 +88,23 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
senderRef = vm.AccountRef(st.Sender)
)
// Get nonce of account outside of the EVM
currentNonce := st.Csdb.GetNonce(st.Sender)
// Set nonce of sender account before evm state transition for usage in generating Create address
st.Csdb.SetNonce(st.Sender, st.AccountNonce)
if contractCreation {
ret, addr, leftOverGas, vmerr = vmenv.Create(senderRef, st.Payload, gasLimit, st.Amount)
} else {
// Increment the nonce for the next transaction
// Increment the nonce for the next transaction (just for evm state transition)
csdb.SetNonce(st.Sender, csdb.GetNonce(st.Sender)+1)
ret, leftOverGas, vmerr = vmenv.Call(senderRef, *st.Recipient, st.Payload, gasLimit, st.Amount)
}
// Resets nonce to value pre state transition
st.Csdb.SetNonce(st.Sender, currentNonce)
// Generate bloom filter to be saved in tx receipt data
bloomInt := big.NewInt(0)
var bloomFilter ethtypes.Bloom
@@ -132,18 +141,3 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
return bloomInt, sdk.Result{Data: returnData, GasUsed: st.GasLimit - leftOverGas}
}
func (st *StateTransition) checkNonce() sdk.Result {
// If simulated transaction, don't verify nonce
if !st.Simulate {
// Make sure this transaction's nonce is correct.
nonce := st.Csdb.GetNonce(st.Sender)
if nonce < st.AccountNonce {
return emint.ErrInvalidNonce("nonce too high").Result()
} else if nonce > st.AccountNonce {
return emint.ErrInvalidNonce("nonce too low").Result()
}
}
return sdk.Result{}
}
+24 -1
View File
@@ -9,6 +9,8 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
emint "github.com/cosmos/ethermint/types"
ethcmn "github.com/ethereum/go-ethereum/common"
ethstate "github.com/ethereum/go-ethereum/core/state"
ethtypes "github.com/ethereum/go-ethereum/core/types"
@@ -523,7 +525,7 @@ func (csdb *CommitStateDB) Suicide(addr ethcmn.Address) bool {
// Reset clears out all ephemeral state objects from the state db, but keeps
// the underlying account mapper and store keys to avoid reloading data for the
// next operations.
func (csdb *CommitStateDB) Reset(root ethcmn.Hash) error {
func (csdb *CommitStateDB) Reset(_ ethcmn.Hash) error {
csdb.stateObjects = make(map[ethcmn.Address]*stateObject)
csdb.stateObjectsDirty = make(map[ethcmn.Address]struct{})
csdb.thash = ethcmn.Hash{}
@@ -537,6 +539,27 @@ func (csdb *CommitStateDB) Reset(root ethcmn.Hash) error {
return nil
}
// UpdateAccounts updates the nonce and coin balances of accounts
func (csdb *CommitStateDB) UpdateAccounts() {
for addr, so := range csdb.stateObjects {
currAcc := csdb.ak.GetAccount(csdb.ctx, sdk.AccAddress(addr.Bytes()))
emintAcc, ok := currAcc.(*emint.Account)
if ok {
if (so.Balance() != emintAcc.Balance().BigInt()) || (so.Nonce() != emintAcc.GetSequence()) {
// If queried account's balance or nonce are invalid, update the account pointer
so.account = emintAcc
}
}
}
}
// ClearStateObjects clears cache of state objects to handle account changes outside of the EVM
func (csdb *CommitStateDB) ClearStateObjects() {
csdb.stateObjects = make(map[ethcmn.Address]*stateObject)
csdb.stateObjectsDirty = make(map[ethcmn.Address]struct{})
}
func (csdb *CommitStateDB) clearJournalAndRefund() {
csdb.journal = newJournal()
csdb.validRevisions = csdb.validRevisions[:0]