evm: params (#458)
* evm: params * setup * bump commit * fixes * increase gas usage * tests * evm denom param * more config updates * update genesis * update ante handler * csdb param test * more tests and fixes * update statedb.Copy * lint * additional test * fix importer tests * fix AnteHandler test * minor update * revert * undo gas update * stringer test * changelog * fix csdb index error (#493) * attempt to fix * cleanup * add idx check * update csdb.Copy * update default hash * update querier * update rpc tests * fix estimate gas test Co-authored-by: noot <36753753+noot@users.noreply.github.com> Co-authored-by: noot <elizabethjbinks@gmail.com>
This commit is contained in:
parent
26816e2648
commit
792c1ff756
@ -40,6 +40,9 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
|||||||
### Improvements
|
### Improvements
|
||||||
|
|
||||||
* (app) [\#471](https://github.com/ChainSafe/ethermint/pull/471) Add `x/upgrade` module for managing software updates.
|
* (app) [\#471](https://github.com/ChainSafe/ethermint/pull/471) Add `x/upgrade` module for managing software updates.
|
||||||
|
* (`x/evm`) [\#458](https://github.com/ChainSafe/ethermint/pull/458) Define parameter for token denomination used for the EVM module.
|
||||||
|
* (`x/evm`) [\#443](https://github.com/ChainSafe/ethermint/issues/443) Support custom Ethereum `ChainConfig` params.
|
||||||
|
* (types) [\#434](https://github.com/ChainSafe/ethermint/issues/434) Update default denomination to Atto Photon (`aphoton`).
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
|
2
Makefile
2
Makefile
@ -211,7 +211,7 @@ test-race:
|
|||||||
|
|
||||||
test-import:
|
test-import:
|
||||||
@go test ./importer -v --vet=off --run=TestImportBlocks --datadir tmp \
|
@go test ./importer -v --vet=off --run=TestImportBlocks --datadir tmp \
|
||||||
--blockchain blockchain --timeout=10m
|
--blockchain blockchain
|
||||||
rm -rf importer/tmp
|
rm -rf importer/tmp
|
||||||
|
|
||||||
test-rpc:
|
test-rpc:
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
|
||||||
|
|
||||||
"github.com/cosmos/ethermint/crypto"
|
"github.com/cosmos/ethermint/crypto"
|
||||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||||
@ -29,7 +28,7 @@ const (
|
|||||||
// Ethereum or SDK transaction to an internal ante handler for performing
|
// Ethereum or SDK transaction to an internal ante handler for performing
|
||||||
// transaction-level processing (e.g. fee payment, signature verification) before
|
// transaction-level processing (e.g. fee payment, signature verification) before
|
||||||
// being passed onto it's respective handler.
|
// being passed onto it's respective handler.
|
||||||
func NewAnteHandler(ak auth.AccountKeeper, bk bank.Keeper, sk types.SupplyKeeper) sdk.AnteHandler {
|
func NewAnteHandler(ak auth.AccountKeeper, evmKeeper EVMKeeper, sk types.SupplyKeeper) sdk.AnteHandler {
|
||||||
return func(
|
return func(
|
||||||
ctx sdk.Context, tx sdk.Tx, sim bool,
|
ctx sdk.Context, tx sdk.Tx, sim bool,
|
||||||
) (newCtx sdk.Context, err error) {
|
) (newCtx sdk.Context, err error) {
|
||||||
@ -53,11 +52,11 @@ func NewAnteHandler(ak auth.AccountKeeper, bk bank.Keeper, sk types.SupplyKeeper
|
|||||||
case evmtypes.MsgEthereumTx:
|
case evmtypes.MsgEthereumTx:
|
||||||
anteHandler = sdk.ChainAnteDecorators(
|
anteHandler = sdk.ChainAnteDecorators(
|
||||||
NewEthSetupContextDecorator(), // outermost AnteDecorator. EthSetUpContext must be called first
|
NewEthSetupContextDecorator(), // outermost AnteDecorator. EthSetUpContext must be called first
|
||||||
NewEthMempoolFeeDecorator(),
|
NewEthMempoolFeeDecorator(evmKeeper),
|
||||||
NewEthSigVerificationDecorator(),
|
NewEthSigVerificationDecorator(),
|
||||||
NewAccountVerificationDecorator(ak, bk),
|
NewAccountVerificationDecorator(ak, evmKeeper),
|
||||||
NewNonceVerificationDecorator(ak),
|
NewNonceVerificationDecorator(ak),
|
||||||
NewEthGasConsumeDecorator(ak, sk),
|
NewEthGasConsumeDecorator(ak, sk, evmKeeper),
|
||||||
NewIncrementSenderSequenceDecorator(ak), // innermost AnteDecorator.
|
NewIncrementSenderSequenceDecorator(ak), // innermost AnteDecorator.
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
|
@ -254,8 +254,9 @@ func (suite *AnteTestSuite) TestEthInvalidMempoolFees() {
|
|||||||
// setup app with checkTx = true
|
// setup app with checkTx = true
|
||||||
suite.app = app.Setup(true)
|
suite.app = app.Setup(true)
|
||||||
suite.ctx = suite.app.BaseApp.NewContext(true, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()})
|
suite.ctx = suite.app.BaseApp.NewContext(true, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()})
|
||||||
suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.SupplyKeeper)
|
suite.app.EvmKeeper.SetParams(suite.ctx, evmtypes.DefaultParams())
|
||||||
|
|
||||||
|
suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper)
|
||||||
suite.ctx = suite.ctx.WithMinGasPrices(sdk.NewDecCoins(sdk.NewDecCoin(types.DenomDefault, sdk.NewInt(500000))))
|
suite.ctx = suite.ctx.WithMinGasPrices(sdk.NewDecCoins(sdk.NewDecCoin(types.DenomDefault, sdk.NewInt(500000))))
|
||||||
addr1, priv1 := newTestAddrKey()
|
addr1, priv1 := newTestAddrKey()
|
||||||
addr2, _ := newTestAddrKey()
|
addr2, _ := newTestAddrKey()
|
||||||
|
@ -9,7 +9,6 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
|
||||||
|
|
||||||
emint "github.com/cosmos/ethermint/types"
|
emint "github.com/cosmos/ethermint/types"
|
||||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||||
@ -18,6 +17,11 @@ import (
|
|||||||
ethcore "github.com/ethereum/go-ethereum/core"
|
ethcore "github.com/ethereum/go-ethereum/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EVMKeeper defines the expected keeper interface used on the Eth AnteHandler
|
||||||
|
type EVMKeeper interface {
|
||||||
|
GetParams(ctx sdk.Context) evmtypes.Params
|
||||||
|
}
|
||||||
|
|
||||||
// EthSetupContextDecorator sets the infinite GasMeter in the Context and wraps
|
// EthSetupContextDecorator sets the infinite GasMeter in the Context and wraps
|
||||||
// the next AnteHandler with a defer clause to recover from any downstream
|
// the next AnteHandler with a defer clause to recover from any downstream
|
||||||
// OutOfGas panics in the AnteHandler chain to return an error with information
|
// OutOfGas panics in the AnteHandler chain to return an error with information
|
||||||
@ -68,11 +72,15 @@ func (escd EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu
|
|||||||
|
|
||||||
// EthMempoolFeeDecorator validates that sufficient fees have been provided that
|
// EthMempoolFeeDecorator validates that sufficient fees have been provided that
|
||||||
// meet a minimum threshold defined by the proposer (for mempool purposes during CheckTx).
|
// meet a minimum threshold defined by the proposer (for mempool purposes during CheckTx).
|
||||||
type EthMempoolFeeDecorator struct{}
|
type EthMempoolFeeDecorator struct {
|
||||||
|
evmKeeper EVMKeeper
|
||||||
|
}
|
||||||
|
|
||||||
// NewEthMempoolFeeDecorator creates a new EthMempoolFeeDecorator
|
// NewEthMempoolFeeDecorator creates a new EthMempoolFeeDecorator
|
||||||
func NewEthMempoolFeeDecorator() EthMempoolFeeDecorator {
|
func NewEthMempoolFeeDecorator(ek EVMKeeper) EthMempoolFeeDecorator {
|
||||||
return EthMempoolFeeDecorator{}
|
return EthMempoolFeeDecorator{
|
||||||
|
evmKeeper: ek,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnteHandle verifies that enough fees have been provided by the
|
// AnteHandle verifies that enough fees have been provided by the
|
||||||
@ -90,8 +98,10 @@ func (emfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
|||||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evmDenom := emfd.evmKeeper.GetParams(ctx).EvmDenom
|
||||||
|
|
||||||
// fee = GP * GL
|
// fee = GP * GL
|
||||||
fee := sdk.NewInt64DecCoin(emint.DenomDefault, msgEthTx.Fee().Int64())
|
fee := sdk.NewInt64DecCoin(evmDenom, msgEthTx.Fee().Int64())
|
||||||
|
|
||||||
minGasPrices := ctx.MinGasPrices()
|
minGasPrices := ctx.MinGasPrices()
|
||||||
|
|
||||||
@ -99,7 +109,7 @@ func (emfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
|||||||
// NOTE: we only check if aphotons are present in min gas prices. It is up to the
|
// NOTE: we only check if aphotons are present in min gas prices. It is up to the
|
||||||
// sender if they want to send additional fees in other denominations.
|
// sender if they want to send additional fees in other denominations.
|
||||||
var hasEnoughFees bool
|
var hasEnoughFees bool
|
||||||
if fee.Amount.GTE(minGasPrices.AmountOf(emint.DenomDefault)) {
|
if fee.Amount.GTE(minGasPrices.AmountOf(evmDenom)) {
|
||||||
hasEnoughFees = true
|
hasEnoughFees = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,15 +160,15 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
|
|||||||
|
|
||||||
// AccountVerificationDecorator validates an account balance checks
|
// AccountVerificationDecorator validates an account balance checks
|
||||||
type AccountVerificationDecorator struct {
|
type AccountVerificationDecorator struct {
|
||||||
ak auth.AccountKeeper
|
ak auth.AccountKeeper
|
||||||
bk bank.Keeper
|
evmKeeper EVMKeeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAccountVerificationDecorator creates a new AccountVerificationDecorator
|
// NewAccountVerificationDecorator creates a new AccountVerificationDecorator
|
||||||
func NewAccountVerificationDecorator(ak auth.AccountKeeper, bk bank.Keeper) AccountVerificationDecorator {
|
func NewAccountVerificationDecorator(ak auth.AccountKeeper, ek EVMKeeper) AccountVerificationDecorator {
|
||||||
return AccountVerificationDecorator{
|
return AccountVerificationDecorator{
|
||||||
ak: ak,
|
ak: ak,
|
||||||
bk: bk,
|
evmKeeper: ek,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,12 +202,14 @@ func (avd AccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evmDenom := avd.evmKeeper.GetParams(ctx).EvmDenom
|
||||||
|
|
||||||
// validate sender has enough funds to pay for gas cost
|
// validate sender has enough funds to pay for gas cost
|
||||||
balance := sdk.Coin{Denom: emint.DenomDefault, Amount: acc.GetCoins().AmountOf(emint.DenomDefault)}
|
balance := acc.GetCoins().AmountOf(evmDenom)
|
||||||
if balance.Amount.BigInt().Cmp(msgEthTx.Cost()) < 0 {
|
if balance.BigInt().Cmp(msgEthTx.Cost()) < 0 {
|
||||||
return ctx, sdkerrors.Wrapf(
|
return ctx, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrInsufficientFunds,
|
sdkerrors.ErrInsufficientFunds,
|
||||||
"sender balance < tx gas cost (%s < %s%s)", balance.String(), msgEthTx.Cost().String(), emint.DenomDefault,
|
"sender balance < tx gas cost (%s%s < %s%s)", balance.String(), evmDenom, msgEthTx.Cost().String(), evmDenom,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,15 +262,17 @@ func (nvd NonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim
|
|||||||
// EthGasConsumeDecorator validates enough intrinsic gas for the transaction and
|
// EthGasConsumeDecorator validates enough intrinsic gas for the transaction and
|
||||||
// gas consumption.
|
// gas consumption.
|
||||||
type EthGasConsumeDecorator struct {
|
type EthGasConsumeDecorator struct {
|
||||||
ak auth.AccountKeeper
|
ak auth.AccountKeeper
|
||||||
sk types.SupplyKeeper
|
sk types.SupplyKeeper
|
||||||
|
evmKeeper EVMKeeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEthGasConsumeDecorator creates a new EthGasConsumeDecorator
|
// NewEthGasConsumeDecorator creates a new EthGasConsumeDecorator
|
||||||
func NewEthGasConsumeDecorator(ak auth.AccountKeeper, sk types.SupplyKeeper) EthGasConsumeDecorator {
|
func NewEthGasConsumeDecorator(ak auth.AccountKeeper, sk types.SupplyKeeper, ek EVMKeeper) EthGasConsumeDecorator {
|
||||||
return EthGasConsumeDecorator{
|
return EthGasConsumeDecorator{
|
||||||
ak: ak,
|
ak: ak,
|
||||||
sk: sk,
|
sk: sk,
|
||||||
|
evmKeeper: ek,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,8 +321,10 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
|||||||
// Cost calculates the fees paid to validators based on gas limit and price
|
// Cost calculates the fees paid to validators based on gas limit and price
|
||||||
cost := new(big.Int).Mul(msgEthTx.Data.Price, new(big.Int).SetUint64(gasLimit))
|
cost := new(big.Int).Mul(msgEthTx.Data.Price, new(big.Int).SetUint64(gasLimit))
|
||||||
|
|
||||||
|
evmDenom := egcd.evmKeeper.GetParams(ctx).EvmDenom
|
||||||
|
|
||||||
feeAmt := sdk.NewCoins(
|
feeAmt := sdk.NewCoins(
|
||||||
sdk.NewCoin(emint.DenomDefault, sdk.NewIntFromBigInt(cost)),
|
sdk.NewCoin(evmDenom, sdk.NewIntFromBigInt(cost)),
|
||||||
)
|
)
|
||||||
|
|
||||||
err = auth.DeductFees(egcd.sk, ctx, senderAcc, feeAmt)
|
err = auth.DeductFees(egcd.sk, ctx, senderAcc, feeAmt)
|
||||||
|
@ -38,7 +38,9 @@ func (suite *AnteTestSuite) SetupTest() {
|
|||||||
suite.app.Codec().RegisterConcrete(&sdk.TestMsg{}, "test/TestMsg", nil)
|
suite.app.Codec().RegisterConcrete(&sdk.TestMsg{}, "test/TestMsg", nil)
|
||||||
|
|
||||||
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()})
|
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()})
|
||||||
suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.SupplyKeeper)
|
suite.app.EvmKeeper.SetParams(suite.ctx, evmtypes.DefaultParams())
|
||||||
|
|
||||||
|
suite.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.EvmKeeper, suite.app.SupplyKeeper)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAnteTestSuite(t *testing.T) {
|
func TestAnteTestSuite(t *testing.T) {
|
||||||
|
@ -148,7 +148,7 @@ func NewEthermintApp(
|
|||||||
|
|
||||||
cdc := ethermintcodec.MakeCodec(ModuleBasics)
|
cdc := ethermintcodec.MakeCodec(ModuleBasics)
|
||||||
|
|
||||||
// use custom Ethermint transaction decoder
|
// NOTE we use custom Ethermint transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
||||||
bApp := bam.NewBaseApp(appName, logger, db, evm.TxDecoder(cdc), baseAppOptions...)
|
bApp := bam.NewBaseApp(appName, logger, db, evm.TxDecoder(cdc), baseAppOptions...)
|
||||||
bApp.SetCommitMultiStoreTracer(traceStore)
|
bApp.SetCommitMultiStoreTracer(traceStore)
|
||||||
bApp.SetAppVersion(version.Version)
|
bApp.SetAppVersion(version.Version)
|
||||||
@ -182,6 +182,7 @@ func NewEthermintApp(
|
|||||||
app.subspaces[gov.ModuleName] = app.ParamsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
|
app.subspaces[gov.ModuleName] = app.ParamsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
|
||||||
app.subspaces[crisis.ModuleName] = app.ParamsKeeper.Subspace(crisis.DefaultParamspace)
|
app.subspaces[crisis.ModuleName] = app.ParamsKeeper.Subspace(crisis.DefaultParamspace)
|
||||||
app.subspaces[evidence.ModuleName] = app.ParamsKeeper.Subspace(evidence.DefaultParamspace)
|
app.subspaces[evidence.ModuleName] = app.ParamsKeeper.Subspace(evidence.DefaultParamspace)
|
||||||
|
app.subspaces[evm.ModuleName] = app.ParamsKeeper.Subspace(evm.DefaultParamspace)
|
||||||
|
|
||||||
// use custom Ethermint account for contracts
|
// use custom Ethermint account for contracts
|
||||||
app.AccountKeeper = auth.NewAccountKeeper(
|
app.AccountKeeper = auth.NewAccountKeeper(
|
||||||
@ -212,7 +213,7 @@ func NewEthermintApp(
|
|||||||
)
|
)
|
||||||
app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], app.cdc)
|
app.UpgradeKeeper = upgrade.NewKeeper(skipUpgradeHeights, keys[upgrade.StoreKey], app.cdc)
|
||||||
app.EvmKeeper = evm.NewKeeper(
|
app.EvmKeeper = evm.NewKeeper(
|
||||||
app.cdc, keys[evm.StoreKey], app.AccountKeeper,
|
app.cdc, keys[evm.StoreKey], app.subspaces[evm.ModuleName], app.AccountKeeper,
|
||||||
)
|
)
|
||||||
app.FaucetKeeper = faucet.NewKeeper(
|
app.FaucetKeeper = faucet.NewKeeper(
|
||||||
app.cdc, keys[faucet.StoreKey], app.SupplyKeeper,
|
app.cdc, keys[faucet.StoreKey], app.SupplyKeeper,
|
||||||
@ -311,7 +312,7 @@ func NewEthermintApp(
|
|||||||
// initialize BaseApp
|
// initialize BaseApp
|
||||||
app.SetInitChainer(app.InitChainer)
|
app.SetInitChainer(app.InitChainer)
|
||||||
app.SetBeginBlocker(app.BeginBlocker)
|
app.SetBeginBlocker(app.BeginBlocker)
|
||||||
app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.BankKeeper, app.SupplyKeeper))
|
app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.EvmKeeper, app.SupplyKeeper))
|
||||||
app.SetEndBlocker(app.EndBlocker)
|
app.SetEndBlocker(app.EndBlocker)
|
||||||
|
|
||||||
if loadLatest {
|
if loadLatest {
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/cosmos/ethermint/core"
|
"github.com/cosmos/ethermint/core"
|
||||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||||
"github.com/cosmos/ethermint/types"
|
"github.com/cosmos/ethermint/types"
|
||||||
|
"github.com/cosmos/ethermint/x/evm"
|
||||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||||
|
|
||||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
@ -49,9 +50,6 @@ var (
|
|||||||
|
|
||||||
genInvestor = ethcmn.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b5a0")
|
genInvestor = ethcmn.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b5a0")
|
||||||
|
|
||||||
accKey = sdk.NewKVStoreKey(auth.StoreKey)
|
|
||||||
storeKey = sdk.NewKVStoreKey(evmtypes.StoreKey)
|
|
||||||
|
|
||||||
logger = tmlog.NewNopLogger()
|
logger = tmlog.NewNopLogger()
|
||||||
|
|
||||||
rewardBig8 = big.NewInt(8)
|
rewardBig8 = big.NewInt(8)
|
||||||
@ -101,12 +99,13 @@ func trapSignals() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// nolint: interfacer
|
// nolint: interfacer
|
||||||
func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.AccountKeeper) {
|
func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.AccountKeeper, evmKeeper evm.Keeper) {
|
||||||
genBlock := ethcore.DefaultGenesisBlock()
|
genBlock := ethcore.DefaultGenesisBlock()
|
||||||
ms := cms.CacheMultiStore()
|
ms := cms.CacheMultiStore()
|
||||||
ctx := sdk.NewContext(ms, abci.Header{}, false, logger)
|
ctx := sdk.NewContext(ms, abci.Header{}, false, logger)
|
||||||
|
|
||||||
stateDB := evmtypes.NewCommitStateDB(ctx, storeKey, ak)
|
// Set the default Ethermint parameters to the parameter keeper store
|
||||||
|
evmKeeper.SetParams(ctx, evmtypes.DefaultParams())
|
||||||
|
|
||||||
// sort the addresses and insertion of key/value pairs matters
|
// sort the addresses and insertion of key/value pairs matters
|
||||||
genAddrs := make([]string, len(genBlock.Alloc))
|
genAddrs := make([]string, len(genBlock.Alloc))
|
||||||
@ -122,23 +121,23 @@ func createAndTestGenesis(t *testing.T, cms sdk.CommitMultiStore, ak auth.Accoun
|
|||||||
addr := ethcmn.HexToAddress(addrStr)
|
addr := ethcmn.HexToAddress(addrStr)
|
||||||
acc := genBlock.Alloc[addr]
|
acc := genBlock.Alloc[addr]
|
||||||
|
|
||||||
stateDB.AddBalance(addr, acc.Balance)
|
evmKeeper.AddBalance(ctx, addr, acc.Balance)
|
||||||
stateDB.SetCode(addr, acc.Code)
|
evmKeeper.SetCode(ctx, addr, acc.Code)
|
||||||
stateDB.SetNonce(addr, acc.Nonce)
|
evmKeeper.SetNonce(ctx, addr, acc.Nonce)
|
||||||
|
|
||||||
for key, value := range acc.Storage {
|
for key, value := range acc.Storage {
|
||||||
stateDB.SetState(addr, key, value)
|
evmKeeper.SetState(ctx, addr, key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// get balance of one of the genesis account having 400 ETH
|
// get balance of one of the genesis account having 400 ETH
|
||||||
b := stateDB.GetBalance(genInvestor)
|
b := evmKeeper.GetBalance(ctx, genInvestor)
|
||||||
require.Equal(t, "200000000000000000000", b.String())
|
require.Equal(t, "200000000000000000000", b.String())
|
||||||
|
|
||||||
// commit the stateDB with 'false' to delete empty objects
|
// commit the stateDB with 'false' to delete empty objects
|
||||||
//
|
//
|
||||||
// NOTE: Commit does not yet return the intra merkle root (version)
|
// NOTE: Commit does not yet return the intra merkle root (version)
|
||||||
_, err := stateDB.Commit(false)
|
_, err := evmKeeper.Commit(ctx, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// persist multi-store cache state
|
// persist multi-store cache state
|
||||||
@ -176,20 +175,27 @@ func TestImportBlocks(t *testing.T) {
|
|||||||
|
|
||||||
cms := store.NewCommitMultiStore(db)
|
cms := store.NewCommitMultiStore(db)
|
||||||
|
|
||||||
// The ParamsKeeper handles parameter storage for the application
|
authStoreKey := sdk.NewKVStoreKey(auth.StoreKey)
|
||||||
keyParams := sdk.NewKVStoreKey(params.StoreKey)
|
evmStoreKey := sdk.NewKVStoreKey(evmtypes.StoreKey)
|
||||||
tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey)
|
paramsStoreKey := sdk.NewKVStoreKey(params.StoreKey)
|
||||||
paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams)
|
paramsTransientStoreKey := sdk.NewTransientStoreKey(params.TStoreKey)
|
||||||
// Set specific supspaces
|
|
||||||
authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace)
|
|
||||||
ak := auth.NewAccountKeeper(cdc, accKey, authSubspace, types.ProtoAccount)
|
|
||||||
|
|
||||||
// mount stores
|
// mount stores
|
||||||
keys := []*sdk.KVStoreKey{accKey, storeKey}
|
keys := []*sdk.KVStoreKey{authStoreKey, evmStoreKey, paramsStoreKey}
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, nil)
|
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cms.MountStoreWithDB(paramsTransientStoreKey, sdk.StoreTypeTransient, nil)
|
||||||
|
|
||||||
|
paramsKeeper := params.NewKeeper(cdc, paramsStoreKey, paramsTransientStoreKey)
|
||||||
|
|
||||||
|
// Set specific subspaces
|
||||||
|
authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace)
|
||||||
|
evmSubspace := paramsKeeper.Subspace(evmtypes.DefaultParamspace).WithKeyTable(evmtypes.ParamKeyTable())
|
||||||
|
ak := auth.NewAccountKeeper(cdc, authStoreKey, authSubspace, types.ProtoAccount)
|
||||||
|
evmKeeper := evm.NewKeeper(cdc, evmStoreKey, evmSubspace, ak)
|
||||||
|
|
||||||
cms.SetPruning(sdkstore.PruneNothing)
|
cms.SetPruning(sdkstore.PruneNothing)
|
||||||
|
|
||||||
// load latest version (root)
|
// load latest version (root)
|
||||||
@ -197,7 +203,7 @@ func TestImportBlocks(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// set and test genesis block
|
// set and test genesis block
|
||||||
createAndTestGenesis(t, cms, ak)
|
createAndTestGenesis(t, cms, ak, evmKeeper)
|
||||||
|
|
||||||
// open blockchain export file
|
// open blockchain export file
|
||||||
blockchainInput, err := os.Open(flagBlockchain)
|
blockchainInput, err := os.Open(flagBlockchain)
|
||||||
@ -242,27 +248,25 @@ func TestImportBlocks(t *testing.T) {
|
|||||||
ctx := sdk.NewContext(ms, abci.Header{}, false, logger)
|
ctx := sdk.NewContext(ms, abci.Header{}, false, logger)
|
||||||
ctx = ctx.WithBlockHeight(int64(block.NumberU64()))
|
ctx = ctx.WithBlockHeight(int64(block.NumberU64()))
|
||||||
|
|
||||||
stateDB := createStateDB(ctx, ak)
|
|
||||||
|
|
||||||
if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 {
|
if chainConfig.DAOForkSupport && chainConfig.DAOForkBlock != nil && chainConfig.DAOForkBlock.Cmp(block.Number()) == 0 {
|
||||||
applyDAOHardFork(stateDB)
|
applyDAOHardFork(evmKeeper)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
stateDB.Prepare(tx.Hash(), block.Hash(), i)
|
evmKeeper.Prepare(ctx, tx.Hash(), block.Hash(), i)
|
||||||
|
|
||||||
receipt, gas, err := applyTransaction(
|
receipt, gas, err := applyTransaction(
|
||||||
chainConfig, chainContext, nil, gp, stateDB, header, tx, usedGas, vmConfig,
|
chainConfig, chainContext, nil, gp, evmKeeper, header, tx, usedGas, vmConfig,
|
||||||
)
|
)
|
||||||
require.NoError(t, err, "failed to apply tx at block %d; tx: %X; gas %d; receipt:%v", block.NumberU64(), tx.Hash(), gas, receipt)
|
require.NoError(t, err, "failed to apply tx at block %d; tx: %X; gas %d; receipt:%v", block.NumberU64(), tx.Hash(), gas, receipt)
|
||||||
require.NotNil(t, receipt)
|
require.NotNil(t, receipt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply mining rewards
|
// apply mining rewards
|
||||||
accumulateRewards(chainConfig, stateDB, header, block.Uncles())
|
accumulateRewards(chainConfig, evmKeeper, header, block.Uncles())
|
||||||
|
|
||||||
// commit stateDB
|
// commit stateDB
|
||||||
_, err := stateDB.Commit(chainConfig.IsEIP158(block.Number()))
|
_, err := evmKeeper.CommitStateDB.Commit(chainConfig.IsEIP158(block.Number()))
|
||||||
require.NoError(t, err, "failed to commit StateDB")
|
require.NoError(t, err, "failed to commit StateDB")
|
||||||
|
|
||||||
// simulate BaseApp EndBlocker commitment
|
// simulate BaseApp EndBlocker commitment
|
||||||
@ -276,16 +280,11 @@ func TestImportBlocks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// nolint: interfacer
|
|
||||||
func createStateDB(ctx sdk.Context, ak auth.AccountKeeper) *evmtypes.CommitStateDB {
|
|
||||||
return evmtypes.NewCommitStateDB(ctx, storeKey, ak)
|
|
||||||
}
|
|
||||||
|
|
||||||
// accumulateRewards credits the coinbase of the given block with the mining
|
// accumulateRewards credits the coinbase of the given block with the mining
|
||||||
// reward. The total reward consists of the static block reward and rewards for
|
// reward. The total reward consists of the static block reward and rewards for
|
||||||
// included uncles. The coinbase of each uncle block is also rewarded.
|
// included uncles. The coinbase of each uncle block is also rewarded.
|
||||||
func accumulateRewards(
|
func accumulateRewards(
|
||||||
config *ethparams.ChainConfig, stateDB *evmtypes.CommitStateDB,
|
config *ethparams.ChainConfig, evmKeeper evm.Keeper,
|
||||||
header *ethtypes.Header, uncles []*ethtypes.Header,
|
header *ethtypes.Header, uncles []*ethtypes.Header,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@ -304,12 +303,12 @@ func accumulateRewards(
|
|||||||
r.Sub(r, header.Number)
|
r.Sub(r, header.Number)
|
||||||
r.Mul(r, blockReward)
|
r.Mul(r, blockReward)
|
||||||
r.Div(r, rewardBig8)
|
r.Div(r, rewardBig8)
|
||||||
stateDB.AddBalance(uncle.Coinbase, r)
|
evmKeeper.CommitStateDB.AddBalance(uncle.Coinbase, r)
|
||||||
r.Div(blockReward, rewardBig32)
|
r.Div(blockReward, rewardBig32)
|
||||||
reward.Add(reward, r)
|
reward.Add(reward, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
stateDB.AddBalance(header.Coinbase, reward)
|
evmKeeper.CommitStateDB.AddBalance(header.Coinbase, reward)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyDAOHardFork modifies the state database according to the DAO hard-fork
|
// ApplyDAOHardFork modifies the state database according to the DAO hard-fork
|
||||||
@ -318,16 +317,16 @@ func accumulateRewards(
|
|||||||
// Code is pulled from go-ethereum 1.9 because the StateDB interface does not include the
|
// Code is pulled from go-ethereum 1.9 because the StateDB interface does not include the
|
||||||
// SetBalance function implementation
|
// SetBalance function implementation
|
||||||
// Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/consensus/misc/dao.go#L74
|
// Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/consensus/misc/dao.go#L74
|
||||||
func applyDAOHardFork(statedb *evmtypes.CommitStateDB) {
|
func applyDAOHardFork(evmKeeper evm.Keeper) {
|
||||||
// Retrieve the contract to refund balances into
|
// Retrieve the contract to refund balances into
|
||||||
if !statedb.Exist(ethparams.DAORefundContract) {
|
if !evmKeeper.CommitStateDB.Exist(ethparams.DAORefundContract) {
|
||||||
statedb.CreateAccount(ethparams.DAORefundContract)
|
evmKeeper.CommitStateDB.CreateAccount(ethparams.DAORefundContract)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move every DAO account and extra-balance account funds into the refund contract
|
// Move every DAO account and extra-balance account funds into the refund contract
|
||||||
for _, addr := range ethparams.DAODrainList() {
|
for _, addr := range ethparams.DAODrainList() {
|
||||||
statedb.AddBalance(ethparams.DAORefundContract, statedb.GetBalance(addr))
|
evmKeeper.CommitStateDB.AddBalance(ethparams.DAORefundContract, evmKeeper.CommitStateDB.GetBalance(addr))
|
||||||
statedb.SetBalance(addr, new(big.Int))
|
evmKeeper.CommitStateDB.SetBalance(addr, new(big.Int))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,7 +338,7 @@ func applyDAOHardFork(statedb *evmtypes.CommitStateDB) {
|
|||||||
// Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/core/state_processor.go#L88
|
// Ref: https://github.com/ethereum/go-ethereum/blob/52f2461774bcb8cdd310f86b4bc501df5b783852/core/state_processor.go#L88
|
||||||
func applyTransaction(
|
func applyTransaction(
|
||||||
config *ethparams.ChainConfig, bc ethcore.ChainContext, author *ethcmn.Address,
|
config *ethparams.ChainConfig, bc ethcore.ChainContext, author *ethcmn.Address,
|
||||||
gp *ethcore.GasPool, statedb *evmtypes.CommitStateDB, header *ethtypes.Header,
|
gp *ethcore.GasPool, evmKeeper evm.Keeper, header *ethtypes.Header,
|
||||||
tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config,
|
tx *ethtypes.Transaction, usedGas *uint64, cfg ethvm.Config,
|
||||||
) (*ethtypes.Receipt, uint64, error) {
|
) (*ethtypes.Receipt, uint64, error) {
|
||||||
msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number))
|
msg, err := tx.AsMessage(ethtypes.MakeSigner(config, header.Number))
|
||||||
@ -352,7 +351,7 @@ func applyTransaction(
|
|||||||
|
|
||||||
// Create a new environment which holds all relevant information
|
// Create a new environment which holds all relevant information
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := ethvm.NewEVM(context, statedb, config, cfg)
|
vmenv := ethvm.NewEVM(context, evmKeeper.CommitStateDB, config, cfg)
|
||||||
|
|
||||||
// Apply the transaction to the current state (included in the env)
|
// Apply the transaction to the current state (included in the env)
|
||||||
execResult, err := ethcore.ApplyMessage(vmenv, msg, gp)
|
execResult, err := ethcore.ApplyMessage(vmenv, msg, gp)
|
||||||
@ -364,9 +363,9 @@ func applyTransaction(
|
|||||||
// Update the state with pending changes
|
// Update the state with pending changes
|
||||||
var intRoot ethcmn.Hash
|
var intRoot ethcmn.Hash
|
||||||
if config.IsByzantium(header.Number) {
|
if config.IsByzantium(header.Number) {
|
||||||
err = statedb.Finalise(true)
|
err = evmKeeper.CommitStateDB.Finalise(true)
|
||||||
} else {
|
} else {
|
||||||
intRoot, err = statedb.IntermediateRoot(config.IsEIP158(header.Number))
|
intRoot, err = evmKeeper.CommitStateDB.IntermediateRoot(config.IsEIP158(header.Number))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -388,11 +387,11 @@ func applyTransaction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the receipt logs and create a bloom for filtering
|
// Set the receipt logs and create a bloom for filtering
|
||||||
receipt.Logs, err = statedb.GetLogs(tx.Hash())
|
receipt.Logs, err = evmKeeper.CommitStateDB.GetLogs(tx.Hash())
|
||||||
receipt.Bloom = ethtypes.CreateBloom(ethtypes.Receipts{receipt})
|
receipt.Bloom = ethtypes.CreateBloom(ethtypes.Receipts{receipt})
|
||||||
receipt.BlockHash = statedb.BlockHash()
|
receipt.BlockHash = evmKeeper.CommitStateDB.BlockHash()
|
||||||
receipt.BlockNumber = header.Number
|
receipt.BlockNumber = header.Number
|
||||||
receipt.TransactionIndex = uint(statedb.TxIndex())
|
receipt.TransactionIndex = uint(evmKeeper.CommitStateDB.TxIndex())
|
||||||
|
|
||||||
return receipt, execResult.UsedGas, err
|
return receipt, execResult.UsedGas, err
|
||||||
}
|
}
|
||||||
|
@ -751,12 +751,14 @@ func TestEth_EstimateGas(t *testing.T) {
|
|||||||
param[0]["to"] = "0x1122334455667788990011223344556677889900"
|
param[0]["to"] = "0x1122334455667788990011223344556677889900"
|
||||||
param[0]["value"] = "0x1"
|
param[0]["value"] = "0x1"
|
||||||
rpcRes := call(t, "eth_estimateGas", param)
|
rpcRes := call(t, "eth_estimateGas", param)
|
||||||
|
require.NotNil(t, rpcRes)
|
||||||
|
require.NotEmpty(t, rpcRes.Result)
|
||||||
|
|
||||||
var gas hexutil.Bytes
|
var gas string
|
||||||
err := json.Unmarshal(rpcRes.Result, &gas)
|
err := json.Unmarshal(rpcRes.Result, &gas)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err, string(rpcRes.Result))
|
||||||
|
|
||||||
require.Equal(t, "0xffdf", gas.String())
|
require.Equal(t, "0x1051d", gas)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEth_EstimateGas_ContractDeployment(t *testing.T) {
|
func TestEth_EstimateGas_ContractDeployment(t *testing.T) {
|
||||||
@ -768,12 +770,14 @@ func TestEth_EstimateGas_ContractDeployment(t *testing.T) {
|
|||||||
param[0]["data"] = bytecode
|
param[0]["data"] = bytecode
|
||||||
|
|
||||||
rpcRes := call(t, "eth_estimateGas", param)
|
rpcRes := call(t, "eth_estimateGas", param)
|
||||||
|
require.NotNil(t, rpcRes)
|
||||||
|
require.NotEmpty(t, rpcRes.Result)
|
||||||
|
|
||||||
var gas hexutil.Uint64
|
var gas hexutil.Uint64
|
||||||
err := json.Unmarshal(rpcRes.Result, &gas)
|
err := json.Unmarshal(rpcRes.Result, &gas)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err, string(rpcRes.Result))
|
||||||
|
|
||||||
require.Equal(t, hexutil.Uint64(0x1cab2), gas)
|
require.Equal(t, "0x1cab2", gas.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEth_ExportAccount(t *testing.T) {
|
func TestEth_ExportAccount(t *testing.T) {
|
||||||
@ -831,10 +835,10 @@ func TestEth_ExportAccount_WithStorage(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// deployed bytecode
|
// deployed bytecode
|
||||||
bytecode := ethcmn.FromHex("0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063eb8ac92114602d575b600080fd5b606060048036036040811015604157600080fd5b8101908080359060200190929190803590602001909291905050506062565b005b8160008190555080827ff3ca124a697ba07e8c5e80bebcfcc48991fc16a63170e8a9206e30508960d00360405160405180910390a3505056fea265627a7a723158201d94d2187aaf3a6790527b615fcc40970febf0385fa6d72a2344848ebd0df3e964736f6c63430005110032")
|
bytecode := "0x6080604052348015600f57600080fd5b506004361060285760003560e01c8063eb8ac92114602d575b600080fd5b606060048036036040811015604157600080fd5b8101908080359060200190929190803590602001909291905050506062565b005b8160008190555080827ff3ca124a697ba07e8c5e80bebcfcc48991fc16a63170e8a9206e30508960d00360405160405180910390a3505056fea265627a7a723158201d94d2187aaf3a6790527b615fcc40970febf0385fa6d72a2344848ebd0df3e964736f6c63430005110032"
|
||||||
require.Equal(t, addr, strings.ToLower(account.Address.Hex()))
|
require.Equal(t, addr, strings.ToLower(account.Address.Hex()))
|
||||||
require.Equal(t, big.NewInt(0), account.Balance)
|
require.Equal(t, big.NewInt(0), account.Balance)
|
||||||
require.Equal(t, hexutil.Bytes(bytecode), account.Code)
|
require.Equal(t, bytecode, account.Code.String())
|
||||||
require.NotEqual(t, types.Storage(nil), account.Storage)
|
require.NotEqual(t, types.Storage(nil), account.Storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,9 +7,10 @@ import (
|
|||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
const (
|
const (
|
||||||
ModuleName = types.ModuleName
|
ModuleName = types.ModuleName
|
||||||
StoreKey = types.StoreKey
|
StoreKey = types.StoreKey
|
||||||
RouterKey = types.RouterKey
|
RouterKey = types.RouterKey
|
||||||
|
DefaultParamspace = types.DefaultParamspace
|
||||||
)
|
)
|
||||||
|
|
||||||
// nolint
|
// nolint
|
||||||
|
@ -28,6 +28,9 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) []abci.ValidatorU
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
k.SetChainConfig(ctx, data.ChainConfig)
|
||||||
|
k.SetParams(ctx, data.Params)
|
||||||
|
|
||||||
// set state objects and code to store
|
// set state objects and code to store
|
||||||
_, err = k.Commit(ctx, false)
|
_, err = k.Commit(ctx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -74,8 +77,12 @@ func ExportGenesis(ctx sdk.Context, k Keeper, ak types.AccountKeeper) GenesisSta
|
|||||||
ethGenAccounts = append(ethGenAccounts, genAccount)
|
ethGenAccounts = append(ethGenAccounts, genAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config, _ := k.GetChainConfig(ctx)
|
||||||
|
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Accounts: ethGenAccounts,
|
Accounts: ethGenAccounts,
|
||||||
TxsLogs: k.GetAllTxLogs(ctx),
|
TxsLogs: k.GetAllTxLogs(ctx),
|
||||||
|
ChainConfig: config,
|
||||||
|
Params: k.GetParams(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,8 +65,12 @@ func handleMsgEthereumTx(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*s
|
|||||||
k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount)
|
k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount)
|
||||||
k.TxCount++
|
k.TxCount++
|
||||||
|
|
||||||
// TODO: move to keeper
|
config, found := k.GetChainConfig(ctx)
|
||||||
executionResult, err := st.TransitionDb(ctx)
|
if !found {
|
||||||
|
return nil, types.ErrChainConfigNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
executionResult, err := st.TransitionDb(ctx, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -142,7 +146,12 @@ func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk
|
|||||||
k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount)
|
k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount)
|
||||||
k.TxCount++
|
k.TxCount++
|
||||||
|
|
||||||
executionResult, err := st.TransitionDb(ctx)
|
config, found := k.GetChainConfig(ctx)
|
||||||
|
if !found {
|
||||||
|
return nil, types.ErrChainConfigNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
executionResult, err := st.TransitionDb(ctx, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
|
|
||||||
"github.com/cosmos/ethermint/x/evm/types"
|
"github.com/cosmos/ethermint/x/evm/types"
|
||||||
|
|
||||||
@ -28,7 +29,8 @@ type Keeper struct {
|
|||||||
// - storing transaction Logs
|
// - storing transaction Logs
|
||||||
// - storing block height -> bloom filter map. Needed for the Web3 API.
|
// - storing block height -> bloom filter map. Needed for the Web3 API.
|
||||||
// - storing block hash -> block height map. Needed for the Web3 API.
|
// - storing block hash -> block height map. Needed for the Web3 API.
|
||||||
storeKey sdk.StoreKey
|
storeKey sdk.StoreKey
|
||||||
|
// Ethermint concrete implementation on the EVM StateDB interface
|
||||||
CommitStateDB *types.CommitStateDB
|
CommitStateDB *types.CommitStateDB
|
||||||
// Transaction counter in a block. Used on StateSB's Prepare function.
|
// Transaction counter in a block. Used on StateSB's Prepare function.
|
||||||
// It is reset to 0 every block on BeginBlock so there's no point in storing the counter
|
// It is reset to 0 every block on BeginBlock so there's no point in storing the counter
|
||||||
@ -39,12 +41,18 @@ type Keeper struct {
|
|||||||
|
|
||||||
// NewKeeper generates new evm module keeper
|
// NewKeeper generates new evm module keeper
|
||||||
func NewKeeper(
|
func NewKeeper(
|
||||||
cdc *codec.Codec, storeKey sdk.StoreKey, ak types.AccountKeeper,
|
cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, ak types.AccountKeeper,
|
||||||
) Keeper {
|
) Keeper {
|
||||||
|
// set KeyTable if it has not already been set
|
||||||
|
if !paramSpace.HasKeyTable() {
|
||||||
|
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations
|
||||||
return Keeper{
|
return Keeper{
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
storeKey: storeKey,
|
storeKey: storeKey,
|
||||||
CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, ak),
|
CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, paramSpace, ak),
|
||||||
TxCount: 0,
|
TxCount: 0,
|
||||||
Bloom: big.NewInt(0),
|
Bloom: big.NewInt(0),
|
||||||
}
|
}
|
||||||
@ -134,3 +142,25 @@ func (k Keeper) GetAccountStorage(ctx sdk.Context, address common.Address) (type
|
|||||||
|
|
||||||
return storage, nil
|
return storage, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetChainConfig gets block height from block consensus hash
|
||||||
|
func (k Keeper) GetChainConfig(ctx sdk.Context) (types.ChainConfig, bool) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixChainConfig)
|
||||||
|
// get from an empty key that's already prefixed by KeyPrefixChainConfig
|
||||||
|
bz := store.Get([]byte{})
|
||||||
|
if len(bz) == 0 {
|
||||||
|
return types.ChainConfig{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
var config types.ChainConfig
|
||||||
|
k.cdc.MustUnmarshalBinaryBare(bz, &config)
|
||||||
|
return config, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetChainConfig sets the mapping from block consensus hash to block height
|
||||||
|
func (k Keeper) SetChainConfig(ctx sdk.Context, config types.ChainConfig) {
|
||||||
|
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixChainConfig)
|
||||||
|
bz := k.cdc.MustMarshalBinaryBare(config)
|
||||||
|
// get to an empty key that's already prefixed by KeyPrefixChainConfig
|
||||||
|
store.Set([]byte{}, bz)
|
||||||
|
}
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
"github.com/cosmos/ethermint/app"
|
"github.com/cosmos/ethermint/app"
|
||||||
ethermint "github.com/cosmos/ethermint/types"
|
ethermint "github.com/cosmos/ethermint/types"
|
||||||
"github.com/cosmos/ethermint/x/evm/keeper"
|
"github.com/cosmos/ethermint/x/evm/keeper"
|
||||||
|
"github.com/cosmos/ethermint/x/evm/types"
|
||||||
|
|
||||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
@ -148,3 +149,15 @@ func (suite *KeeperTestSuite) TestDBStorage() {
|
|||||||
// simulate BaseApp EndBlocker commitment
|
// simulate BaseApp EndBlocker commitment
|
||||||
suite.app.Commit()
|
suite.app.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) TestChainConfig() {
|
||||||
|
config, found := suite.app.EvmKeeper.GetChainConfig(suite.ctx)
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(types.DefaultChainConfig(), config)
|
||||||
|
|
||||||
|
config.EIP150Block = sdk.NewInt(100)
|
||||||
|
suite.app.EvmKeeper.SetChainConfig(suite.ctx, config)
|
||||||
|
newConfig, found := suite.app.EvmKeeper.GetChainConfig(suite.ctx)
|
||||||
|
suite.Require().True(found)
|
||||||
|
suite.Require().Equal(config, newConfig)
|
||||||
|
}
|
||||||
|
17
x/evm/keeper/params.go
Normal file
17
x/evm/keeper/params.go
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package keeper
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
|
"github.com/cosmos/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetParams returns the total set of evm parameters.
|
||||||
|
func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) {
|
||||||
|
return k.CommitStateDB.WithContext(ctx).GetParams()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetParams sets the evm parameters to the param space.
|
||||||
|
func (k Keeper) SetParams(ctx sdk.Context, params types.Params) {
|
||||||
|
k.CommitStateDB.WithContext(ctx).SetParams(params)
|
||||||
|
}
|
14
x/evm/keeper/params_test.go
Normal file
14
x/evm/keeper/params_test.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package keeper_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/cosmos/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite *KeeperTestSuite) TestParams() {
|
||||||
|
params := suite.app.EvmKeeper.GetParams(suite.ctx)
|
||||||
|
suite.Require().Equal(types.DefaultParams(), params)
|
||||||
|
params.EvmDenom = "ara"
|
||||||
|
suite.app.EvmKeeper.SetParams(suite.ctx, params)
|
||||||
|
newParams := suite.app.EvmKeeper.GetParams(suite.ctx)
|
||||||
|
suite.Require().Equal(newParams, params)
|
||||||
|
}
|
@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
// NewQuerier is the module level router for state queries
|
// NewQuerier is the module level router for state queries
|
||||||
func NewQuerier(keeper Keeper) sdk.Querier {
|
func NewQuerier(keeper Keeper) sdk.Querier {
|
||||||
return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) {
|
return func(ctx sdk.Context, path []string, _ abci.RequestQuery) ([]byte, error) {
|
||||||
switch path[0] {
|
switch path[0] {
|
||||||
case types.QueryProtocolVersion:
|
case types.QueryProtocolVersion:
|
||||||
return queryProtocolVersion(keeper)
|
return queryProtocolVersion(keeper)
|
||||||
@ -203,7 +203,7 @@ func queryExportAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte,
|
|||||||
addr := ethcmn.HexToAddress(path[1])
|
addr := ethcmn.HexToAddress(path[1])
|
||||||
|
|
||||||
var storage types.Storage
|
var storage types.Storage
|
||||||
err := keeper.CommitStateDB.ForEachStorage(addr, func(key, value ethcmn.Hash) bool {
|
err := keeper.ForEachStorage(ctx, addr, func(key, value ethcmn.Hash) bool {
|
||||||
storage = append(storage, types.NewState(key, value))
|
storage = append(storage, types.NewState(key, value))
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
@ -18,8 +18,11 @@ var testJSON = `{
|
|||||||
"address": "0x2cc7fdf9fde6746731d7f11979609d455c2c197a",
|
"address": "0x2cc7fdf9fde6746731d7f11979609d455c2c197a",
|
||||||
"balance": 0,
|
"balance": 0,
|
||||||
"code": "0x60806040"
|
"code": "0x60806040"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"params": {
|
||||||
|
"evm_denom": "aphoton"
|
||||||
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
func (suite *EvmTestSuite) TestInitGenesis() {
|
func (suite *EvmTestSuite) TestInitGenesis() {
|
||||||
|
@ -2,25 +2,171 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenerateChainConfig returns an Ethereum chainconfig for EVM state transitions
|
// ChainConfig defines the Ethereum ChainConfig parameters using sdk.Int values instead of big.Int.
|
||||||
func GenerateChainConfig(chainID *big.Int) *params.ChainConfig {
|
//
|
||||||
// TODO: Update chainconfig to take in parameters for fork blocks
|
// NOTE 1: Since empty/uninitialized Ints (i.e with a nil big.Int value) are parsed to zero, we need to manually
|
||||||
|
// specify that negative Int values will be considered as nil. See getBlockValue for reference.
|
||||||
|
//
|
||||||
|
// NOTE 2: This type is not a configurable Param since the SDK does not allow for validation against
|
||||||
|
// a previous stored parameter values or the current block height (retrieved from context). If you
|
||||||
|
// want to update the config values, use an software upgrade procedure.
|
||||||
|
type ChainConfig struct {
|
||||||
|
HomesteadBlock sdk.Int `json:"homestead_block" yaml:"homestead_block"` // Homestead switch block (< 0 no fork, 0 = already homestead)
|
||||||
|
|
||||||
|
DAOForkBlock sdk.Int `json:"dao_fork_block" yaml:"dao_fork_block"` // TheDAO hard-fork switch block (< 0 no fork)
|
||||||
|
DAOForkSupport bool `json:"dao_fork_support" yaml:"dao_fork_support"` // Whether the nodes supports or opposes the DAO hard-fork
|
||||||
|
|
||||||
|
// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
|
||||||
|
EIP150Block sdk.Int `json:"eip150_block" yaml:"eip150_block"` // EIP150 HF block (< 0 no fork)
|
||||||
|
EIP150Hash string `json:"eip150_hash" yaml:"eip150_hash"` // EIP150 HF hash (needed for header only clients as only gas pricing changed)
|
||||||
|
|
||||||
|
EIP155Block sdk.Int `json:"eip155_block" yaml:"eip155_block"` // EIP155 HF block
|
||||||
|
EIP158Block sdk.Int `json:"eip158_block" yaml:"eip158_block"` // EIP158 HF block
|
||||||
|
|
||||||
|
ByzantiumBlock sdk.Int `json:"byzantium_block" yaml:"byzantium_block"` // Byzantium switch block (< 0 no fork, 0 = already on byzantium)
|
||||||
|
ConstantinopleBlock sdk.Int `json:"constantinople_block" yaml:"constantinople_block"` // Constantinople switch block (< 0 no fork, 0 = already activated)
|
||||||
|
PetersburgBlock sdk.Int `json:"petersburg_block" yaml:"petersburg_block"` // Petersburg switch block (< 0 same as Constantinople)
|
||||||
|
IstanbulBlock sdk.Int `json:"istanbul_block" yaml:"istanbul_block"` // Istanbul switch block (< 0 no fork, 0 = already on istanbul)
|
||||||
|
MuirGlacierBlock sdk.Int `json:"muir_glacier_block" yaml:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (< 0 no fork, 0 = already activated)
|
||||||
|
|
||||||
|
YoloV1Block sdk.Int `json:"yoloV1_block" yaml:"yoloV1_block"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet)
|
||||||
|
EWASMBlock sdk.Int `json:"ewasm_block" yaml:"ewasm_block"` // EWASM switch block (< 0 no fork, 0 = already activated)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthereumConfig returns an Ethereum ChainConfig for EVM state transitions.
|
||||||
|
// All the negative or nil values are converted to nil
|
||||||
|
func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig {
|
||||||
return ¶ms.ChainConfig{
|
return ¶ms.ChainConfig{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
HomesteadBlock: big.NewInt(0),
|
HomesteadBlock: getBlockValue(cc.HomesteadBlock),
|
||||||
DAOForkBlock: big.NewInt(0),
|
DAOForkBlock: getBlockValue(cc.DAOForkBlock),
|
||||||
DAOForkSupport: true,
|
DAOForkSupport: cc.DAOForkSupport,
|
||||||
EIP150Block: big.NewInt(0),
|
EIP150Block: getBlockValue(cc.EIP150Block),
|
||||||
EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
|
EIP150Hash: common.HexToHash(cc.EIP150Hash),
|
||||||
EIP155Block: big.NewInt(0),
|
EIP155Block: getBlockValue(cc.EIP155Block),
|
||||||
EIP158Block: big.NewInt(0),
|
EIP158Block: getBlockValue(cc.EIP158Block),
|
||||||
ByzantiumBlock: big.NewInt(0),
|
ByzantiumBlock: getBlockValue(cc.ByzantiumBlock),
|
||||||
ConstantinopleBlock: big.NewInt(0),
|
ConstantinopleBlock: getBlockValue(cc.ConstantinopleBlock),
|
||||||
PetersburgBlock: big.NewInt(0),
|
PetersburgBlock: getBlockValue(cc.PetersburgBlock),
|
||||||
|
IstanbulBlock: getBlockValue(cc.IstanbulBlock),
|
||||||
|
MuirGlacierBlock: getBlockValue(cc.MuirGlacierBlock),
|
||||||
|
YoloV1Block: getBlockValue(cc.YoloV1Block),
|
||||||
|
EWASMBlock: getBlockValue(cc.EWASMBlock),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String implements the fmt.Stringer interface
|
||||||
|
func (cc ChainConfig) String() string {
|
||||||
|
out, _ := yaml.Marshal(cc)
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultChainConfig returns default evm parameters. Th
|
||||||
|
func DefaultChainConfig() ChainConfig {
|
||||||
|
return ChainConfig{
|
||||||
|
HomesteadBlock: sdk.ZeroInt(),
|
||||||
|
DAOForkBlock: sdk.ZeroInt(),
|
||||||
|
DAOForkSupport: true,
|
||||||
|
EIP150Block: sdk.ZeroInt(),
|
||||||
|
EIP150Hash: common.Hash{}.String(),
|
||||||
|
EIP155Block: sdk.ZeroInt(),
|
||||||
|
EIP158Block: sdk.ZeroInt(),
|
||||||
|
ByzantiumBlock: sdk.ZeroInt(),
|
||||||
|
ConstantinopleBlock: sdk.ZeroInt(),
|
||||||
|
PetersburgBlock: sdk.ZeroInt(),
|
||||||
|
IstanbulBlock: sdk.NewInt(-1),
|
||||||
|
MuirGlacierBlock: sdk.NewInt(-1),
|
||||||
|
YoloV1Block: sdk.NewInt(-1),
|
||||||
|
EWASMBlock: sdk.NewInt(-1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBlockValue(block sdk.Int) *big.Int {
|
||||||
|
if block.IsNegative() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return block.BigInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate performs a basic validation of the ChainConfig params. The function will return an error
|
||||||
|
// if any of the block values is uninitialized (i.e nil) or if the EIP150Hash is an invalid hash.
|
||||||
|
func (cc ChainConfig) Validate() error {
|
||||||
|
if err := validateBlock(cc.HomesteadBlock); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "homesteadBlock")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.DAOForkBlock); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "daoForkBlock")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.EIP150Block); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "eip150Block")
|
||||||
|
}
|
||||||
|
if err := validateHash(cc.EIP150Hash); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.EIP155Block); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "eip155Block")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.EIP158Block); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "eip158Block")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.ByzantiumBlock); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "byzantiumBlock")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.ConstantinopleBlock); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "constantinopleBlock")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.PetersburgBlock); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "petersburgBlock")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.IstanbulBlock); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "istanbulBlock")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.MuirGlacierBlock); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "muirGlacierBlock")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.YoloV1Block); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "yoloV1Block")
|
||||||
|
}
|
||||||
|
if err := validateBlock(cc.EWASMBlock); err != nil {
|
||||||
|
return sdkerrors.Wrap(err, "eWASMBlock")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateHash(hex string) error {
|
||||||
|
if hex != "" && strings.TrimSpace(hex) == "" {
|
||||||
|
return sdkerrors.Wrapf(ErrInvalidChainConfig, "hash cannot be blank")
|
||||||
|
}
|
||||||
|
|
||||||
|
bz := common.FromHex(hex)
|
||||||
|
lenHex := len(bz)
|
||||||
|
if lenHex > 0 && lenHex != common.HashLength {
|
||||||
|
return sdkerrors.Wrapf(ErrInvalidChainConfig, "invalid hash length, expected %d, got %d", common.HashLength, lenHex)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateBlock(block sdk.Int) error {
|
||||||
|
if block == (sdk.Int{}) || block.BigInt() == nil {
|
||||||
|
return sdkerrors.Wrapf(
|
||||||
|
ErrInvalidChainConfig,
|
||||||
|
"cannot use uninitialized or nil values for Int, set a negative Int value if you want to define a nil Ethereum block",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
245
x/evm/types/chain_config_test.go
Normal file
245
x/evm/types/chain_config_test.go
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultEIP150Hash = common.Hash{}.String()
|
||||||
|
|
||||||
|
func TestChainConfigValidate(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
config ChainConfig
|
||||||
|
expError bool
|
||||||
|
}{
|
||||||
|
{"default", DefaultChainConfig(), false},
|
||||||
|
{
|
||||||
|
"valid",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.OneInt(),
|
||||||
|
EIP158Block: sdk.OneInt(),
|
||||||
|
ByzantiumBlock: sdk.OneInt(),
|
||||||
|
ConstantinopleBlock: sdk.OneInt(),
|
||||||
|
PetersburgBlock: sdk.OneInt(),
|
||||||
|
IstanbulBlock: sdk.OneInt(),
|
||||||
|
MuirGlacierBlock: sdk.OneInt(),
|
||||||
|
YoloV1Block: sdk.OneInt(),
|
||||||
|
EWASMBlock: sdk.OneInt(),
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"empty",
|
||||||
|
ChainConfig{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid HomesteadBlock",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid DAOForkBlock",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid EIP150Block",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid EIP150Hash",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: " ",
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid EIP155Block",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid EIP158Block",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.OneInt(),
|
||||||
|
EIP158Block: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid ByzantiumBlock",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.OneInt(),
|
||||||
|
EIP158Block: sdk.OneInt(),
|
||||||
|
ByzantiumBlock: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid ConstantinopleBlock",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.OneInt(),
|
||||||
|
EIP158Block: sdk.OneInt(),
|
||||||
|
ByzantiumBlock: sdk.OneInt(),
|
||||||
|
ConstantinopleBlock: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid PetersburgBlock",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.OneInt(),
|
||||||
|
EIP158Block: sdk.OneInt(),
|
||||||
|
ByzantiumBlock: sdk.OneInt(),
|
||||||
|
ConstantinopleBlock: sdk.OneInt(),
|
||||||
|
PetersburgBlock: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid IstanbulBlock",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.OneInt(),
|
||||||
|
EIP158Block: sdk.OneInt(),
|
||||||
|
ByzantiumBlock: sdk.OneInt(),
|
||||||
|
ConstantinopleBlock: sdk.OneInt(),
|
||||||
|
PetersburgBlock: sdk.OneInt(),
|
||||||
|
IstanbulBlock: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid MuirGlacierBlock",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.OneInt(),
|
||||||
|
EIP158Block: sdk.OneInt(),
|
||||||
|
ByzantiumBlock: sdk.OneInt(),
|
||||||
|
ConstantinopleBlock: sdk.OneInt(),
|
||||||
|
PetersburgBlock: sdk.OneInt(),
|
||||||
|
IstanbulBlock: sdk.OneInt(),
|
||||||
|
MuirGlacierBlock: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid YoloV1Block",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.OneInt(),
|
||||||
|
EIP158Block: sdk.OneInt(),
|
||||||
|
ByzantiumBlock: sdk.OneInt(),
|
||||||
|
ConstantinopleBlock: sdk.OneInt(),
|
||||||
|
PetersburgBlock: sdk.OneInt(),
|
||||||
|
IstanbulBlock: sdk.OneInt(),
|
||||||
|
MuirGlacierBlock: sdk.OneInt(),
|
||||||
|
YoloV1Block: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid EWASMBlock",
|
||||||
|
ChainConfig{
|
||||||
|
HomesteadBlock: sdk.OneInt(),
|
||||||
|
DAOForkBlock: sdk.OneInt(),
|
||||||
|
EIP150Block: sdk.OneInt(),
|
||||||
|
EIP150Hash: defaultEIP150Hash,
|
||||||
|
EIP155Block: sdk.OneInt(),
|
||||||
|
EIP158Block: sdk.OneInt(),
|
||||||
|
ByzantiumBlock: sdk.OneInt(),
|
||||||
|
ConstantinopleBlock: sdk.OneInt(),
|
||||||
|
PetersburgBlock: sdk.OneInt(),
|
||||||
|
IstanbulBlock: sdk.OneInt(),
|
||||||
|
MuirGlacierBlock: sdk.OneInt(),
|
||||||
|
YoloV1Block: sdk.OneInt(),
|
||||||
|
EWASMBlock: sdk.Int{},
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
err := tc.config.Validate()
|
||||||
|
|
||||||
|
if tc.expError {
|
||||||
|
require.Error(t, err, tc.name)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err, tc.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChainConfig_String(t *testing.T) {
|
||||||
|
configStr := `homestead_block: "0"
|
||||||
|
dao_fork_block: "0"
|
||||||
|
dao_fork_support: true
|
||||||
|
eip150_block: "0"
|
||||||
|
eip150_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
eip155_block: "0"
|
||||||
|
eip158_block: "0"
|
||||||
|
byzantium_block: "0"
|
||||||
|
constantinople_block: "0"
|
||||||
|
petersburg_block: "0"
|
||||||
|
istanbul_block: "-1"
|
||||||
|
muir_glacier_block: "-1"
|
||||||
|
yoloV1_block: "-1"
|
||||||
|
ewasm_block: "-1"
|
||||||
|
`
|
||||||
|
require.Equal(t, configStr, DefaultChainConfig().String())
|
||||||
|
}
|
@ -13,6 +13,7 @@ func RegisterCodec(cdc *codec.Codec) {
|
|||||||
cdc.RegisterConcrete(MsgEthereumTx{}, "ethermint/MsgEthereumTx", nil)
|
cdc.RegisterConcrete(MsgEthereumTx{}, "ethermint/MsgEthereumTx", nil)
|
||||||
cdc.RegisterConcrete(MsgEthermint{}, "ethermint/MsgEthermint", nil)
|
cdc.RegisterConcrete(MsgEthermint{}, "ethermint/MsgEthermint", nil)
|
||||||
cdc.RegisterConcrete(TxData{}, "ethermint/TxData", nil)
|
cdc.RegisterConcrete(TxData{}, "ethermint/TxData", nil)
|
||||||
|
cdc.RegisterConcrete(ChainConfig{}, "ethermint/ChainConfig", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -9,4 +9,10 @@ import (
|
|||||||
var (
|
var (
|
||||||
// ErrInvalidState returns an error resulting from an invalid Storage State.
|
// ErrInvalidState returns an error resulting from an invalid Storage State.
|
||||||
ErrInvalidState = sdkerrors.Register(ModuleName, 2, "invalid storage state")
|
ErrInvalidState = sdkerrors.Register(ModuleName, 2, "invalid storage state")
|
||||||
|
|
||||||
|
// ErrChainConfigNotFound returns an error if the chain config cannot be found on the store.
|
||||||
|
ErrChainConfigNotFound = sdkerrors.Register(ModuleName, 3, "chain configuration not found")
|
||||||
|
|
||||||
|
// ErrInvalidChainConfig returns an error resulting from an invalid ChainConfig.
|
||||||
|
ErrInvalidChainConfig = sdkerrors.Register(ModuleName, 4, "invalid chain configuration")
|
||||||
)
|
)
|
||||||
|
@ -13,8 +13,10 @@ import (
|
|||||||
type (
|
type (
|
||||||
// GenesisState defines the evm module genesis state
|
// GenesisState defines the evm module genesis state
|
||||||
GenesisState struct {
|
GenesisState struct {
|
||||||
Accounts []GenesisAccount `json:"accounts"`
|
Accounts []GenesisAccount `json:"accounts"`
|
||||||
TxsLogs []TransactionLogs `json:"txs_logs"`
|
TxsLogs []TransactionLogs `json:"txs_logs"`
|
||||||
|
ChainConfig ChainConfig `json:"chain_config"`
|
||||||
|
Params Params `json:"params"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenesisAccount defines an account to be initialized in the genesis state.
|
// GenesisAccount defines an account to be initialized in the genesis state.
|
||||||
@ -46,11 +48,14 @@ func (ga GenesisAccount) Validate() error {
|
|||||||
return ga.Storage.Validate()
|
return ga.Storage.Validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultGenesisState sets default evm genesis state with empty accounts.
|
// DefaultGenesisState sets default evm genesis state with empty accounts and default params and
|
||||||
|
// chain config values.
|
||||||
func DefaultGenesisState() GenesisState {
|
func DefaultGenesisState() GenesisState {
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Accounts: []GenesisAccount{},
|
Accounts: []GenesisAccount{},
|
||||||
TxsLogs: []TransactionLogs{},
|
TxsLogs: []TransactionLogs{},
|
||||||
|
ChainConfig: DefaultChainConfig(),
|
||||||
|
Params: DefaultParams(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,5 +85,9 @@ func (gs GenesisState) Validate() error {
|
|||||||
seenTxs[tx.Hash.String()] = true
|
seenTxs[tx.Hash.String()] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
if err := gs.ChainConfig.Validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return gs.Params.Validate()
|
||||||
}
|
}
|
||||||
|
@ -122,9 +122,16 @@ func TestValidateGenesis(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
ChainConfig: DefaultChainConfig(),
|
||||||
|
Params: DefaultParams(),
|
||||||
},
|
},
|
||||||
expPass: true,
|
expPass: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "empty genesis",
|
||||||
|
genState: GenesisState{},
|
||||||
|
expPass: false,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "invalid genesis",
|
name: "invalid genesis",
|
||||||
genState: GenesisState{
|
genState: GenesisState{
|
||||||
@ -227,6 +234,22 @@ func TestValidateGenesis(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expPass: false,
|
expPass: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "invalid params",
|
||||||
|
genState: GenesisState{
|
||||||
|
ChainConfig: DefaultChainConfig(),
|
||||||
|
Params: Params{},
|
||||||
|
},
|
||||||
|
expPass: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid chain config",
|
||||||
|
genState: GenesisState{
|
||||||
|
ChainConfig: ChainConfig{},
|
||||||
|
Params: DefaultParams(),
|
||||||
|
},
|
||||||
|
expPass: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/store"
|
"github.com/cosmos/cosmos-sdk/store"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/params"
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
|
|
||||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
@ -119,11 +120,12 @@ func (suite *JournalTestSuite) setup() {
|
|||||||
paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams)
|
paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams)
|
||||||
|
|
||||||
authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace)
|
authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace)
|
||||||
|
evmSubspace := paramsKeeper.Subspace(types.DefaultParamspace)
|
||||||
|
|
||||||
ak := auth.NewAccountKeeper(cdc, authKey, authSubspace, ethermint.ProtoAccount)
|
ak := auth.NewAccountKeeper(cdc, authKey, authSubspace, ethermint.ProtoAccount)
|
||||||
|
|
||||||
suite.ctx = sdk.NewContext(cms, abci.Header{ChainID: "8"}, false, tmlog.NewNopLogger())
|
suite.ctx = sdk.NewContext(cms, abci.Header{ChainID: "8"}, false, tmlog.NewNopLogger())
|
||||||
suite.stateDB = NewCommitStateDB(suite.ctx, storeKey, ak).WithContext(suite.ctx)
|
suite.stateDB = NewCommitStateDB(suite.ctx, storeKey, evmSubspace, ak).WithContext(suite.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestJournalTestSuite(t *testing.T) {
|
func TestJournalTestSuite(t *testing.T) {
|
||||||
|
@ -21,11 +21,12 @@ const (
|
|||||||
|
|
||||||
// KVStore key prefixes
|
// KVStore key prefixes
|
||||||
var (
|
var (
|
||||||
KeyPrefixBlockHash = []byte{0x01}
|
KeyPrefixBlockHash = []byte{0x01}
|
||||||
KeyPrefixBloom = []byte{0x02}
|
KeyPrefixBloom = []byte{0x02}
|
||||||
KeyPrefixLogs = []byte{0x03}
|
KeyPrefixLogs = []byte{0x03}
|
||||||
KeyPrefixCode = []byte{0x04}
|
KeyPrefixCode = []byte{0x04}
|
||||||
KeyPrefixStorage = []byte{0x05}
|
KeyPrefixStorage = []byte{0x05}
|
||||||
|
KeyPrefixChainConfig = []byte{0x06}
|
||||||
)
|
)
|
||||||
|
|
||||||
// BloomKey defines the store key for a block Bloom
|
// BloomKey defines the store key for a block Bloom
|
||||||
|
73
x/evm/types/params.go
Normal file
73
x/evm/types/params.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
|
|
||||||
|
ethermint "github.com/cosmos/ethermint/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultParamspace for params keeper
|
||||||
|
DefaultParamspace = ModuleName
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parameter keys
|
||||||
|
var (
|
||||||
|
ParamStoreKeyEVMDenom = []byte("EVMDenom")
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParamKeyTable returns the parameter key table.
|
||||||
|
func ParamKeyTable() params.KeyTable {
|
||||||
|
return params.NewKeyTable().RegisterParamSet(&Params{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Params defines the EVM module parameters
|
||||||
|
type Params struct {
|
||||||
|
EvmDenom string `json:"evm_denom" yaml:"evm_denom"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewParams creates a new Params instance
|
||||||
|
func NewParams(evmDenom string) Params {
|
||||||
|
return Params{
|
||||||
|
EvmDenom: evmDenom,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultParams returns default evm parameters
|
||||||
|
func DefaultParams() Params {
|
||||||
|
return Params{
|
||||||
|
EvmDenom: ethermint.DenomDefault,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the fmt.Stringer interface
|
||||||
|
func (p Params) String() string {
|
||||||
|
out, _ := yaml.Marshal(p)
|
||||||
|
return string(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParamSetPairs returns the parameter set pairs.
|
||||||
|
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
||||||
|
return params.ParamSetPairs{
|
||||||
|
params.NewParamSetPair(ParamStoreKeyEVMDenom, &p.EvmDenom, validateEVMDenom),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate performs basic validation on evm parameters.
|
||||||
|
func (p Params) Validate() error {
|
||||||
|
return sdk.ValidateDenom(p.EvmDenom)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateEVMDenom(i interface{}) error {
|
||||||
|
denom, ok := i.(string)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("invalid parameter type: %T", i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sdk.ValidateDenom(denom)
|
||||||
|
}
|
52
x/evm/types/params_test.go
Normal file
52
x/evm/types/params_test.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParamsValidate(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
params Params
|
||||||
|
expError bool
|
||||||
|
}{
|
||||||
|
{"default", DefaultParams(), false},
|
||||||
|
{
|
||||||
|
"valid",
|
||||||
|
NewParams("ara"),
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"empty",
|
||||||
|
Params{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"invalid evm denom",
|
||||||
|
Params{
|
||||||
|
EvmDenom: "@!#!@$!@5^32",
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
err := tc.params.Validate()
|
||||||
|
|
||||||
|
if tc.expError {
|
||||||
|
require.Error(t, err, tc.name)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err, tc.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParamsValidatePriv(t *testing.T) {
|
||||||
|
require.Error(t, validateEVMDenom(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParams_String(t *testing.T) {
|
||||||
|
require.Equal(t, "evm_denom: aphoton\n", DefaultParams().String())
|
||||||
|
}
|
@ -176,8 +176,8 @@ func (so *stateObject) AddBalance(amount *big.Int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// newBalance := so.balance.Add(amt)
|
evmDenom := so.stateDB.GetParams().EvmDenom
|
||||||
newBalance := so.account.GetCoins().AmountOf(types.DenomDefault).Add(amt)
|
newBalance := so.account.GetCoins().AmountOf(evmDenom).Add(amt)
|
||||||
so.SetBalance(newBalance.BigInt())
|
so.SetBalance(newBalance.BigInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,7 +188,9 @@ func (so *stateObject) SubBalance(amount *big.Int) {
|
|||||||
if amt.IsZero() {
|
if amt.IsZero() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
newBalance := so.account.GetCoins().AmountOf(types.DenomDefault).Sub(amt)
|
|
||||||
|
evmDenom := so.stateDB.GetParams().EvmDenom
|
||||||
|
newBalance := so.account.GetCoins().AmountOf(evmDenom).Sub(amt)
|
||||||
so.SetBalance(newBalance.BigInt())
|
so.SetBalance(newBalance.BigInt())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,9 +198,10 @@ func (so *stateObject) SubBalance(amount *big.Int) {
|
|||||||
func (so *stateObject) SetBalance(amount *big.Int) {
|
func (so *stateObject) SetBalance(amount *big.Int) {
|
||||||
amt := sdk.NewIntFromBigInt(amount)
|
amt := sdk.NewIntFromBigInt(amount)
|
||||||
|
|
||||||
|
evmDenom := so.stateDB.GetParams().EvmDenom
|
||||||
so.stateDB.journal.append(balanceChange{
|
so.stateDB.journal.append(balanceChange{
|
||||||
account: &so.address,
|
account: &so.address,
|
||||||
prev: so.account.GetCoins().AmountOf(types.DenomDefault),
|
prev: so.account.GetCoins().AmountOf(evmDenom),
|
||||||
})
|
})
|
||||||
|
|
||||||
so.setBalance(amt)
|
so.setBalance(amt)
|
||||||
|
@ -10,8 +10,6 @@ import (
|
|||||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
||||||
emint "github.com/cosmos/ethermint/types"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
)
|
)
|
||||||
@ -49,7 +47,7 @@ type ExecutionResult struct {
|
|||||||
GasInfo GasInfo
|
GasInfo GasInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit uint64, gasPrice *big.Int) *vm.EVM {
|
func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit uint64, gasPrice *big.Int, config ChainConfig) *vm.EVM {
|
||||||
// Create context for evm
|
// Create context for evm
|
||||||
context := vm.Context{
|
context := vm.Context{
|
||||||
CanTransfer: core.CanTransfer,
|
CanTransfer: core.CanTransfer,
|
||||||
@ -63,13 +61,13 @@ func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit
|
|||||||
GasPrice: gasPrice,
|
GasPrice: gasPrice,
|
||||||
}
|
}
|
||||||
|
|
||||||
return vm.NewEVM(context, csdb, GenerateChainConfig(st.ChainID), vm.Config{})
|
return vm.NewEVM(context, csdb, config.EthereumConfig(st.ChainID), vm.Config{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransitionDb will transition the state by applying the current transaction and
|
// TransitionDb will transition the state by applying the current transaction and
|
||||||
// returning the evm execution result.
|
// returning the evm execution result.
|
||||||
// NOTE: State transition checks are run during AnteHandler execution.
|
// NOTE: State transition checks are run during AnteHandler execution.
|
||||||
func (st StateTransition) TransitionDb(ctx sdk.Context) (*ExecutionResult, error) {
|
func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*ExecutionResult, error) {
|
||||||
contractCreation := st.Recipient == nil
|
contractCreation := st.Recipient == nil
|
||||||
|
|
||||||
cost, err := core.IntrinsicGas(st.Payload, contractCreation, true, false)
|
cost, err := core.IntrinsicGas(st.Payload, contractCreation, true, false)
|
||||||
@ -103,12 +101,13 @@ func (st StateTransition) TransitionDb(ctx sdk.Context) (*ExecutionResult, error
|
|||||||
// Clear cache of accounts to handle changes outside of the EVM
|
// Clear cache of accounts to handle changes outside of the EVM
|
||||||
csdb.UpdateAccounts()
|
csdb.UpdateAccounts()
|
||||||
|
|
||||||
gasPrice := ctx.MinGasPrices().AmountOf(emint.DenomDefault)
|
evmDenom := csdb.GetParams().EvmDenom
|
||||||
|
gasPrice := ctx.MinGasPrices().AmountOf(evmDenom)
|
||||||
if gasPrice.IsNil() {
|
if gasPrice.IsNil() {
|
||||||
return nil, errors.New("gas price cannot be nil")
|
return nil, errors.New("gas price cannot be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.Int)
|
evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.Int, config)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ret []byte
|
ret []byte
|
||||||
|
@ -132,7 +132,7 @@ func (suite *StateDBTestSuite) TestTransitionDb() {
|
|||||||
for _, tc := range testCase {
|
for _, tc := range testCase {
|
||||||
tc.malleate()
|
tc.malleate()
|
||||||
|
|
||||||
_, err = tc.state.TransitionDb(suite.ctx)
|
_, err = tc.state.TransitionDb(suite.ctx, types.DefaultChainConfig())
|
||||||
|
|
||||||
if tc.expPass {
|
if tc.expPass {
|
||||||
suite.Require().NoError(err, tc.name)
|
suite.Require().NoError(err, tc.name)
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/params"
|
||||||
|
|
||||||
emint "github.com/cosmos/ethermint/types"
|
emint "github.com/cosmos/ethermint/types"
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ type CommitStateDB struct {
|
|||||||
ctx sdk.Context
|
ctx sdk.Context
|
||||||
|
|
||||||
storeKey sdk.StoreKey
|
storeKey sdk.StoreKey
|
||||||
|
paramSpace params.Subspace
|
||||||
accountKeeper AccountKeeper
|
accountKeeper AccountKeeper
|
||||||
|
|
||||||
// array that hold 'live' objects, which will get modified while processing a
|
// array that hold 'live' objects, which will get modified while processing a
|
||||||
@ -85,11 +87,12 @@ type CommitStateDB struct {
|
|||||||
// CONTRACT: Stores used for state must be cache-wrapped as the ordering of the
|
// CONTRACT: Stores used for state must be cache-wrapped as the ordering of the
|
||||||
// key/value space matters in determining the merkle root.
|
// key/value space matters in determining the merkle root.
|
||||||
func NewCommitStateDB(
|
func NewCommitStateDB(
|
||||||
ctx sdk.Context, storeKey sdk.StoreKey, ak AccountKeeper,
|
ctx sdk.Context, storeKey sdk.StoreKey, paramSpace params.Subspace, ak AccountKeeper,
|
||||||
) *CommitStateDB {
|
) *CommitStateDB {
|
||||||
return &CommitStateDB{
|
return &CommitStateDB{
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
storeKey: storeKey,
|
storeKey: storeKey,
|
||||||
|
paramSpace: paramSpace,
|
||||||
accountKeeper: ak,
|
accountKeeper: ak,
|
||||||
stateObjects: []stateEntry{},
|
stateObjects: []stateEntry{},
|
||||||
addressToObjectIndex: make(map[ethcmn.Address]int),
|
addressToObjectIndex: make(map[ethcmn.Address]int),
|
||||||
@ -110,6 +113,11 @@ func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB {
|
|||||||
// Setters
|
// Setters
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// SetParams sets the evm parameters to the param space.
|
||||||
|
func (csdb *CommitStateDB) SetParams(params Params) {
|
||||||
|
csdb.paramSpace.SetParamSet(csdb.ctx, ¶ms)
|
||||||
|
}
|
||||||
|
|
||||||
// SetBalance sets the balance of an account.
|
// SetBalance sets the balance of an account.
|
||||||
func (csdb *CommitStateDB) SetBalance(addr ethcmn.Address, amount *big.Int) {
|
func (csdb *CommitStateDB) SetBalance(addr ethcmn.Address, amount *big.Int) {
|
||||||
so := csdb.GetOrNewStateObject(addr)
|
so := csdb.GetOrNewStateObject(addr)
|
||||||
@ -239,6 +247,12 @@ func (csdb *CommitStateDB) SubRefund(gas uint64) {
|
|||||||
// Getters
|
// Getters
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// GetParams returns the total set of evm parameters.
|
||||||
|
func (csdb *CommitStateDB) GetParams() (params Params) {
|
||||||
|
csdb.paramSpace.GetParamSet(csdb.ctx, ¶ms)
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
// GetBalance retrieves the balance from the given address or 0 if object not
|
// GetBalance retrieves the balance from the given address or 0 if object not
|
||||||
// found.
|
// found.
|
||||||
func (csdb *CommitStateDB) GetBalance(addr ethcmn.Address) *big.Int {
|
func (csdb *CommitStateDB) GetBalance(addr ethcmn.Address) *big.Int {
|
||||||
@ -489,8 +503,9 @@ func (csdb *CommitStateDB) IntermediateRoot(deleteEmptyObjects bool) (ethcmn.Has
|
|||||||
|
|
||||||
// updateStateObject writes the given state object to the store.
|
// updateStateObject writes the given state object to the store.
|
||||||
func (csdb *CommitStateDB) updateStateObject(so *stateObject) error {
|
func (csdb *CommitStateDB) updateStateObject(so *stateObject) error {
|
||||||
|
evmDenom := csdb.GetParams().EvmDenom
|
||||||
// NOTE: we don't use sdk.NewCoin here to avoid panic on test importer's genesis
|
// NOTE: we don't use sdk.NewCoin here to avoid panic on test importer's genesis
|
||||||
newBalance := sdk.Coin{Denom: emint.DenomDefault, Amount: sdk.NewIntFromBigInt(so.Balance())}
|
newBalance := sdk.Coin{Denom: evmDenom, Amount: sdk.NewIntFromBigInt(so.Balance())}
|
||||||
if !newBalance.IsValid() {
|
if !newBalance.IsValid() {
|
||||||
return fmt.Errorf("invalid balance %s", newBalance)
|
return fmt.Errorf("invalid balance %s", newBalance)
|
||||||
}
|
}
|
||||||
@ -631,9 +646,10 @@ func (csdb *CommitStateDB) UpdateAccounts() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
evmDenom := csdb.GetParams().EvmDenom
|
||||||
balance := sdk.Coin{
|
balance := sdk.Coin{
|
||||||
Denom: emint.DenomDefault,
|
Denom: evmDenom,
|
||||||
Amount: emintAcc.GetCoins().AmountOf(emint.DenomDefault),
|
Amount: emintAcc.GetCoins().AmountOf(evmDenom),
|
||||||
}
|
}
|
||||||
|
|
||||||
if stateEntry.stateObject.Balance() != balance.Amount.BigInt() && balance.IsValid() ||
|
if stateEntry.stateObject.Balance() != balance.Amount.BigInt() && balance.IsValid() ||
|
||||||
@ -692,6 +708,7 @@ func (csdb *CommitStateDB) Copy() *CommitStateDB {
|
|||||||
state := &CommitStateDB{
|
state := &CommitStateDB{
|
||||||
ctx: csdb.ctx,
|
ctx: csdb.ctx,
|
||||||
storeKey: csdb.storeKey,
|
storeKey: csdb.storeKey,
|
||||||
|
paramSpace: csdb.paramSpace,
|
||||||
accountKeeper: csdb.accountKeeper,
|
accountKeeper: csdb.accountKeeper,
|
||||||
stateObjects: []stateEntry{},
|
stateObjects: []stateEntry{},
|
||||||
addressToObjectIndex: make(map[ethcmn.Address]int),
|
addressToObjectIndex: make(map[ethcmn.Address]int),
|
||||||
@ -815,8 +832,7 @@ func (csdb *CommitStateDB) setError(err error) {
|
|||||||
// getStateObject attempts to retrieve a state object given by the address.
|
// getStateObject attempts to retrieve a state object given by the address.
|
||||||
// Returns nil and sets an error if not found.
|
// Returns nil and sets an error if not found.
|
||||||
func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *stateObject) {
|
func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *stateObject) {
|
||||||
idx, found := csdb.addressToObjectIndex[addr]
|
if idx, found := csdb.addressToObjectIndex[addr]; found {
|
||||||
if found {
|
|
||||||
// prefer 'live' (cached) objects
|
// prefer 'live' (cached) objects
|
||||||
if so := csdb.stateObjects[idx].stateObject; so != nil {
|
if so := csdb.stateObjects[idx].stateObject; so != nil {
|
||||||
if so.deleted {
|
if so.deleted {
|
||||||
@ -842,8 +858,7 @@ func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *sta
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (csdb *CommitStateDB) setStateObject(so *stateObject) {
|
func (csdb *CommitStateDB) setStateObject(so *stateObject) {
|
||||||
idx, found := csdb.addressToObjectIndex[so.Address()]
|
if idx, found := csdb.addressToObjectIndex[so.Address()]; found {
|
||||||
if found {
|
|
||||||
// update the existing object
|
// update the existing object
|
||||||
csdb.stateObjects[idx].stateObject = so
|
csdb.stateObjects[idx].stateObject = so
|
||||||
return
|
return
|
||||||
|
@ -57,6 +57,16 @@ func (suite *StateDBTestSuite) SetupTest() {
|
|||||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||||
suite.stateObject = suite.stateDB.GetOrNewStateObject(suite.address)
|
suite.stateObject = suite.stateDB.GetOrNewStateObject(suite.address)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *StateDBTestSuite) TestParams() {
|
||||||
|
params := suite.stateDB.GetParams()
|
||||||
|
suite.Require().Equal(types.DefaultParams(), params)
|
||||||
|
params.EvmDenom = "ara"
|
||||||
|
suite.stateDB.SetParams(params)
|
||||||
|
newParams := suite.stateDB.GetParams()
|
||||||
|
suite.Require().Equal(newParams, params)
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *StateDBTestSuite) TestBloomFilter() {
|
func (suite *StateDBTestSuite) TestBloomFilter() {
|
||||||
// Prepare db for logs
|
// Prepare db for logs
|
||||||
tHash := ethcmn.BytesToHash([]byte{0x1})
|
tHash := ethcmn.BytesToHash([]byte{0x1})
|
||||||
|
Loading…
Reference in New Issue
Block a user