forked from cerc-io/laconicd-deprecated
upgrade changes cleanup (#236)
* changes from update version * app changes * cmd changes * build and send tx * fix tests * eth_rpc fixes * lint * add WithEventManager to handler ctx * changelog * go mod verify and tidy
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package app
|
||||
package ante
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -46,15 +46,15 @@ func NewAnteHandler(ak auth.AccountKeeper, sk types.SupplyKeeper) sdk.AnteHandle
|
||||
ante.NewSetPubKeyDecorator(ak), // SetPubKeyDecorator must be called before all signature verification decorators
|
||||
ante.NewValidateSigCountDecorator(ak),
|
||||
ante.NewDeductFeeDecorator(ak, sk),
|
||||
ante.NewSigGasConsumeDecorator(ak, consumeSigGas),
|
||||
ante.NewSigGasConsumeDecorator(ak, sigGasConsumer),
|
||||
ante.NewSigVerificationDecorator(ak),
|
||||
ante.NewIncrementSequenceDecorator(ak), // innermost AnteDecorator
|
||||
)
|
||||
|
||||
return stdAnte(ctx, tx, sim)
|
||||
|
||||
case *evmtypes.EthereumTxMsg:
|
||||
return ethAnteHandler(ctx, ak, sk, castTx, sim)
|
||||
case evmtypes.MsgEthereumTx:
|
||||
return ethAnteHandler(ctx, ak, sk, &castTx, sim)
|
||||
|
||||
default:
|
||||
return ctx, sdk.ErrInternal(fmt.Sprintf("transaction type invalid: %T", tx))
|
||||
@@ -62,7 +62,9 @@ func NewAnteHandler(ak auth.AccountKeeper, sk types.SupplyKeeper) sdk.AnteHandle
|
||||
}
|
||||
}
|
||||
|
||||
func consumeSigGas(
|
||||
// sigGasConsumer overrides the DefaultSigVerificationGasConsumer from the x/auth
|
||||
// module on the SDK. It doesn't allow ed25519 nor multisig thresholds.
|
||||
func sigGasConsumer(
|
||||
meter sdk.GasMeter, sig []byte, pubkey tmcrypto.PubKey, params types.Params,
|
||||
) error {
|
||||
switch pubkey.(type) {
|
||||
@@ -89,7 +91,7 @@ func consumeSigGas(
|
||||
// prevent spam and DoS attacks.
|
||||
func ethAnteHandler(
|
||||
ctx sdk.Context, ak auth.AccountKeeper, sk types.SupplyKeeper,
|
||||
ethTxMsg *evmtypes.EthereumTxMsg, sim bool,
|
||||
ethTxMsg *evmtypes.MsgEthereumTx, sim bool,
|
||||
) (newCtx sdk.Context, err error) {
|
||||
|
||||
var senderAddr sdk.AccAddress
|
||||
@@ -120,7 +122,9 @@ func ethAnteHandler(
|
||||
if r := recover(); r != nil {
|
||||
switch rType := r.(type) {
|
||||
case sdk.ErrorOutOfGas:
|
||||
log := fmt.Sprintf("out of gas in location: %v", rType.Descriptor)
|
||||
log := fmt.Sprintf("out of gas in location: %v; gasUsed: %d",
|
||||
rType.Descriptor, ctx.GasMeter().GasConsumed(),
|
||||
)
|
||||
err = sdk.ErrOutOfGas(log)
|
||||
default:
|
||||
panic(r)
|
||||
@@ -139,9 +143,9 @@ func ethAnteHandler(
|
||||
// Cost calculates the fees paid to validators based on gas limit and price
|
||||
cost := new(big.Int).Mul(ethTxMsg.Data.Price, new(big.Int).SetUint64(ethTxMsg.Data.GasLimit))
|
||||
|
||||
feeAmt := sdk.Coins{
|
||||
feeAmt := sdk.NewCoins(
|
||||
sdk.NewCoin(emint.DenomDefault, sdk.NewIntFromBigInt(cost)),
|
||||
}
|
||||
)
|
||||
|
||||
err = auth.DeductFees(sk, ctx, senderAcc, feeAmt)
|
||||
if err != nil {
|
||||
@@ -166,7 +170,7 @@ func ethAnteHandler(
|
||||
}
|
||||
|
||||
func validateEthTxCheckTx(
|
||||
ctx sdk.Context, ak auth.AccountKeeper, ethTxMsg *evmtypes.EthereumTxMsg,
|
||||
ctx sdk.Context, ak auth.AccountKeeper, ethTxMsg *evmtypes.MsgEthereumTx,
|
||||
) (sdk.AccAddress, error) {
|
||||
// Validate sufficient fees have been provided that meet a minimum threshold
|
||||
// defined by the proposer (for mempool purposes during CheckTx).
|
||||
@@ -193,7 +197,7 @@ func validateEthTxCheckTx(
|
||||
}
|
||||
|
||||
// Validates signature and returns sender address
|
||||
func validateSignature(ctx sdk.Context, ethTxMsg *evmtypes.EthereumTxMsg) (sdk.AccAddress, error) {
|
||||
func validateSignature(ctx sdk.Context, ethTxMsg *evmtypes.MsgEthereumTx) (sdk.AccAddress, error) {
|
||||
// parse the chainID from a string to a base-10 integer
|
||||
chainID, ok := new(big.Int).SetString(ctx.ChainID(), 10)
|
||||
if !ok {
|
||||
@@ -214,7 +218,7 @@ func validateSignature(ctx sdk.Context, ethTxMsg *evmtypes.EthereumTxMsg) (sdk.A
|
||||
// that the transaction uses before the transaction is executed. The gas is a
|
||||
// constant value of 21000 plus any cost inccured by additional bytes of data
|
||||
// supplied with the transaction.
|
||||
func validateIntrinsicGas(ethTxMsg *evmtypes.EthereumTxMsg) error {
|
||||
func validateIntrinsicGas(ethTxMsg *evmtypes.MsgEthereumTx) error {
|
||||
gas, err := ethcore.IntrinsicGas(ethTxMsg.Data.Payload, ethTxMsg.To() == nil, true)
|
||||
if err != nil {
|
||||
return sdk.ErrInternal(fmt.Sprintf("failed to compute intrinsic gas cost: %s", err))
|
||||
@@ -222,7 +226,7 @@ func validateIntrinsicGas(ethTxMsg *evmtypes.EthereumTxMsg) error {
|
||||
|
||||
if ethTxMsg.Data.GasLimit < gas {
|
||||
return sdk.ErrInternal(
|
||||
fmt.Sprintf("intrinsic gas too low; %d < %d", ethTxMsg.Data.GasLimit, gas),
|
||||
fmt.Sprintf("intrinsic gas too low: %d < %d", ethTxMsg.Data.GasLimit, gas),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -232,7 +236,7 @@ func validateIntrinsicGas(ethTxMsg *evmtypes.EthereumTxMsg) error {
|
||||
// validateAccount validates the account nonce and that the account has enough
|
||||
// funds to cover the tx cost.
|
||||
func validateAccount(
|
||||
ctx sdk.Context, ak auth.AccountKeeper, ethTxMsg *evmtypes.EthereumTxMsg, signer sdk.AccAddress,
|
||||
ctx sdk.Context, ak auth.AccountKeeper, ethTxMsg *evmtypes.MsgEthereumTx, signer sdk.AccAddress,
|
||||
) error {
|
||||
|
||||
acc := ak.GetAccount(ctx, signer)
|
||||
@@ -241,8 +245,9 @@ func validateAccount(
|
||||
if ctx.BlockHeight() == 0 && acc.GetAccountNumber() != 0 {
|
||||
return sdk.ErrInternal(
|
||||
fmt.Sprintf(
|
||||
"invalid account number for height zero; got %d, expected 0", acc.GetAccountNumber(),
|
||||
))
|
||||
"invalid account number for height zero (got %d)", acc.GetAccountNumber(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// Validate nonce is correct
|
||||
@@ -262,7 +267,7 @@ func validateAccount(
|
||||
}
|
||||
|
||||
func checkNonce(
|
||||
ctx sdk.Context, ak auth.AccountKeeper, ethTxMsg *evmtypes.EthereumTxMsg, signer sdk.AccAddress,
|
||||
ctx sdk.Context, ak auth.AccountKeeper, ethTxMsg *evmtypes.MsgEthereumTx, signer sdk.AccAddress,
|
||||
) error {
|
||||
acc := ak.GetAccount(ctx, signer)
|
||||
// Validate the transaction nonce is valid (equivalent to the sender account’s
|
||||
@@ -270,7 +275,8 @@ func checkNonce(
|
||||
seq := acc.GetSequence()
|
||||
if ethTxMsg.Data.AccountNonce != seq {
|
||||
return sdk.ErrInvalidSequence(
|
||||
fmt.Sprintf("invalid nonce; got %d, expected %d", ethTxMsg.Data.AccountNonce, seq))
|
||||
fmt.Sprintf("invalid nonce; got %d, expected %d", ethTxMsg.Data.AccountNonce, seq),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -281,7 +287,7 @@ func checkNonce(
|
||||
// proposer.
|
||||
//
|
||||
// NOTE: This should only be ran during a CheckTx mode.
|
||||
func ensureSufficientMempoolFees(ctx sdk.Context, ethTxMsg *evmtypes.EthereumTxMsg) error {
|
||||
func ensureSufficientMempoolFees(ctx sdk.Context, ethTxMsg *evmtypes.MsgEthereumTx) error {
|
||||
// fee = GP * GL
|
||||
fee := sdk.NewDecCoinFromCoin(sdk.NewInt64Coin(emint.DenomDefault, ethTxMsg.Fee().Int64()))
|
||||
|
||||
@@ -297,7 +303,9 @@ func ensureSufficientMempoolFees(ctx sdk.Context, ethTxMsg *evmtypes.EthereumTxM
|
||||
if !ctx.MinGasPrices().IsZero() && !allGTE {
|
||||
// reject the transaction that does not meet the minimum fee
|
||||
return sdk.ErrInsufficientFee(
|
||||
fmt.Sprintf("insufficient fee, got: %q required: %q", fee, ctx.MinGasPrices()),
|
||||
fmt.Sprintf(
|
||||
"insufficient fee, got: %q required: %q", fee, ctx.MinGasPrices(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/cosmos/ethermint/app"
|
||||
"github.com/cosmos/ethermint/app/ante"
|
||||
"github.com/cosmos/ethermint/types"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
)
|
||||
|
||||
func requireValidTx(
|
||||
t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, sim bool,
|
||||
) {
|
||||
_, err := anteHandler(ctx, tx, sim)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func requireInvalidTx(
|
||||
t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context,
|
||||
tx sdk.Tx, sim bool,
|
||||
) {
|
||||
_, err := anteHandler(ctx, tx, sim)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestValidEthTx() {
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc1 := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
err := acc1.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc1)
|
||||
|
||||
acc2 := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr2)
|
||||
err = acc2.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc2)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(suite.ctx, ethMsg, priv1)
|
||||
requireValidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestValidTx() {
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, priv2 := newTestAddrKey()
|
||||
|
||||
acc1 := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
err := acc1.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc1)
|
||||
|
||||
acc2 := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr2)
|
||||
err = acc2.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc2)
|
||||
|
||||
// require a valid SDK tx to pass
|
||||
fee := newTestStdFee()
|
||||
msg1 := newTestMsg(addr1, addr2)
|
||||
msgs := []sdk.Msg{msg1}
|
||||
|
||||
privKeys := []tmcrypto.PrivKey{priv1, priv2}
|
||||
accNums := []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber()}
|
||||
accSeqs := []uint64{acc1.GetSequence(), acc2.GetSequence()}
|
||||
|
||||
tx := newTestSDKTx(suite.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
|
||||
requireValidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestSDKInvalidSigs() {
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, priv2 := newTestAddrKey()
|
||||
addr3, priv3 := newTestAddrKey()
|
||||
|
||||
acc1 := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
err := acc1.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc1)
|
||||
|
||||
acc2 := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr2)
|
||||
err = acc2.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc2)
|
||||
|
||||
fee := newTestStdFee()
|
||||
msg1 := newTestMsg(addr1, addr2)
|
||||
|
||||
// require validation failure with no signers
|
||||
msgs := []sdk.Msg{msg1}
|
||||
|
||||
privKeys := []tmcrypto.PrivKey{}
|
||||
accNums := []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber()}
|
||||
accSeqs := []uint64{acc1.GetSequence(), acc2.GetSequence()}
|
||||
|
||||
tx := newTestSDKTx(suite.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
|
||||
// require validation failure with invalid number of signers
|
||||
msgs = []sdk.Msg{msg1}
|
||||
|
||||
privKeys = []tmcrypto.PrivKey{priv1}
|
||||
accNums = []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber()}
|
||||
accSeqs = []uint64{acc1.GetSequence(), acc2.GetSequence()}
|
||||
|
||||
tx = newTestSDKTx(suite.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
|
||||
// require validation failure with an invalid signer
|
||||
msg2 := newTestMsg(addr1, addr3)
|
||||
msgs = []sdk.Msg{msg1, msg2}
|
||||
|
||||
privKeys = []tmcrypto.PrivKey{priv1, priv2, priv3}
|
||||
accNums = []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber(), 0}
|
||||
accSeqs = []uint64{acc1.GetSequence(), acc2.GetSequence(), 0}
|
||||
|
||||
tx = newTestSDKTx(suite.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestSDKInvalidAcc() {
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
|
||||
acc1 := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
err := acc1.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc1)
|
||||
|
||||
fee := newTestStdFee()
|
||||
msg1 := newTestMsg(addr1)
|
||||
msgs := []sdk.Msg{msg1}
|
||||
privKeys := []tmcrypto.PrivKey{priv1}
|
||||
|
||||
// require validation failure with invalid account number
|
||||
accNums := []uint64{1}
|
||||
accSeqs := []uint64{acc1.GetSequence()}
|
||||
|
||||
tx := newTestSDKTx(suite.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
|
||||
// require validation failure with invalid sequence (nonce)
|
||||
accNums = []uint64{acc1.GetAccountNumber()}
|
||||
accSeqs = []uint64{1}
|
||||
|
||||
tx = newTestSDKTx(suite.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestEthInvalidSig() {
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
_, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(suite.ctx, ethMsg, priv1)
|
||||
ctx := suite.ctx.WithChainID("4")
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestEthInvalidNonce() {
|
||||
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
err := acc.SetSequence(10)
|
||||
suite.Require().NoError(err)
|
||||
err = acc.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(suite.ctx, ethMsg, priv1)
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestEthInsufficientBalance() {
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(suite.ctx, ethMsg, priv1)
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestEthInvalidIntrinsicGas() {
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
err := acc.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
gasLimit := uint64(1000)
|
||||
ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, gasLimit, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(suite.ctx, ethMsg, priv1)
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestEthInvalidMempoolFees() {
|
||||
// setup app with checkTx = true
|
||||
suite.app = app.Setup(true)
|
||||
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.SupplyKeeper)
|
||||
|
||||
suite.ctx = suite.ctx.WithMinGasPrices(sdk.NewDecCoins(sdk.NewCoins(sdk.NewCoin(types.DenomDefault, sdk.NewInt(500000)))))
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
err := acc.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("payload"))
|
||||
|
||||
tx := newTestEthTx(suite.ctx, ethMsg, priv1)
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, suite.ctx, tx, false)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestEthInvalidChainID() {
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
err := acc.SetCoins(newTestCoins())
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewMsgEthereumTx(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(suite.ctx, ethMsg, priv1)
|
||||
ctx := suite.ctx.WithChainID("bad-chain-id")
|
||||
requireInvalidTx(suite.T(), suite.anteHandler, ctx, tx, false)
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
|
||||
"github.com/cosmos/ethermint/app"
|
||||
ante "github.com/cosmos/ethermint/app/ante"
|
||||
"github.com/cosmos/ethermint/crypto"
|
||||
emint "github.com/cosmos/ethermint/types"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
)
|
||||
|
||||
type AnteTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
ctx sdk.Context
|
||||
app *app.EthermintApp
|
||||
anteHandler sdk.AnteHandler
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) SetupTest() {
|
||||
checkTx := false
|
||||
|
||||
suite.app = app.Setup(checkTx)
|
||||
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.anteHandler = ante.NewAnteHandler(suite.app.AccountKeeper, suite.app.SupplyKeeper)
|
||||
}
|
||||
|
||||
func TestAnteTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(AnteTestSuite))
|
||||
}
|
||||
|
||||
func newTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg {
|
||||
return sdk.NewTestMsg(addrs...)
|
||||
}
|
||||
|
||||
func newTestCoins() sdk.Coins {
|
||||
return sdk.NewCoins(sdk.NewInt64Coin(emint.DenomDefault, 500000000))
|
||||
}
|
||||
|
||||
func newTestStdFee() auth.StdFee {
|
||||
return auth.NewStdFee(220000, sdk.NewCoins(sdk.NewInt64Coin(emint.DenomDefault, 150)))
|
||||
}
|
||||
|
||||
// GenerateAddress generates an Ethereum address.
|
||||
func newTestAddrKey() (sdk.AccAddress, tmcrypto.PrivKey) {
|
||||
privkey, _ := crypto.GenerateKey()
|
||||
addr := ethcrypto.PubkeyToAddress(privkey.ToECDSA().PublicKey)
|
||||
|
||||
return sdk.AccAddress(addr.Bytes()), privkey
|
||||
}
|
||||
|
||||
func newTestSDKTx(
|
||||
ctx sdk.Context, msgs []sdk.Msg, privs []tmcrypto.PrivKey,
|
||||
accNums []uint64, seqs []uint64, fee auth.StdFee,
|
||||
) sdk.Tx {
|
||||
|
||||
sigs := make([]auth.StdSignature, len(privs))
|
||||
for i, priv := range privs {
|
||||
signBytes := auth.StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, "")
|
||||
|
||||
sig, err := priv.Sign(signBytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sigs[i] = auth.StdSignature{
|
||||
PubKey: priv.PubKey(),
|
||||
Signature: sig,
|
||||
}
|
||||
}
|
||||
|
||||
return auth.NewStdTx(msgs, fee, sigs, "")
|
||||
}
|
||||
|
||||
func newTestEthTx(ctx sdk.Context, msg evmtypes.MsgEthereumTx, priv tmcrypto.PrivKey) sdk.Tx {
|
||||
chainID, ok := new(big.Int).SetString(ctx.ChainID(), 10)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("invalid chainID: %s", ctx.ChainID()))
|
||||
}
|
||||
|
||||
privkey, ok := priv.(crypto.PrivKeySecp256k1)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("invalid private key type: %T", priv))
|
||||
}
|
||||
|
||||
msg.Sign(chainID, privkey.ToECDSA())
|
||||
return msg
|
||||
}
|
||||
@@ -1,308 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/stretchr/testify/require"
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/ethermint/types"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
)
|
||||
|
||||
func requireValidTx(
|
||||
t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context, tx sdk.Tx, sim bool,
|
||||
) {
|
||||
_, err := anteHandler(ctx, tx, sim)
|
||||
require.True(t, err == nil)
|
||||
}
|
||||
|
||||
func requireInvalidTx(
|
||||
t *testing.T, anteHandler sdk.AnteHandler, ctx sdk.Context,
|
||||
tx sdk.Tx, sim bool, code sdk.CodeType,
|
||||
) {
|
||||
|
||||
_, err := anteHandler(ctx, tx, sim)
|
||||
// require.Equal(t, code, err, fmt.Sprintf("invalid result: %v", err))
|
||||
require.Error(t, err)
|
||||
|
||||
if code == sdk.CodeOutOfGas {
|
||||
_, ok := tx.(auth.StdTx)
|
||||
require.True(t, ok, "tx must be in form auth.StdTx")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidEthTx(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc1 := input.accKeeper.NewAccountWithAddress(input.ctx, addr1)
|
||||
// nolint:errcheck
|
||||
acc1.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc1)
|
||||
|
||||
acc2 := input.accKeeper.NewAccountWithAddress(input.ctx, addr2)
|
||||
// nolint:errcheck
|
||||
acc2.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc2)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||
requireValidTx(t, input.anteHandler, input.ctx, tx, false)
|
||||
}
|
||||
|
||||
func TestValidTx(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, priv2 := newTestAddrKey()
|
||||
|
||||
acc1 := input.accKeeper.NewAccountWithAddress(input.ctx, addr1)
|
||||
// nolint:errcheck
|
||||
acc1.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc1)
|
||||
|
||||
acc2 := input.accKeeper.NewAccountWithAddress(input.ctx, addr2)
|
||||
// nolint:errcheck
|
||||
acc2.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc2)
|
||||
|
||||
// require a valid SDK tx to pass
|
||||
fee := newTestStdFee()
|
||||
msg1 := newTestMsg(addr1, addr2)
|
||||
msgs := []sdk.Msg{msg1}
|
||||
|
||||
privKeys := []tmcrypto.PrivKey{priv1, priv2}
|
||||
accNums := []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber()}
|
||||
accSeqs := []uint64{acc1.GetSequence(), acc2.GetSequence()}
|
||||
|
||||
tx := newTestSDKTx(input.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
|
||||
requireValidTx(t, input.anteHandler, input.ctx, tx, false)
|
||||
}
|
||||
|
||||
func TestSDKInvalidSigs(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, priv2 := newTestAddrKey()
|
||||
addr3, priv3 := newTestAddrKey()
|
||||
|
||||
acc1 := input.accKeeper.NewAccountWithAddress(input.ctx, addr1)
|
||||
// nolint:errcheck
|
||||
acc1.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc1)
|
||||
|
||||
acc2 := input.accKeeper.NewAccountWithAddress(input.ctx, addr2)
|
||||
// nolint:errcheck
|
||||
acc2.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc2)
|
||||
|
||||
fee := newTestStdFee()
|
||||
msg1 := newTestMsg(addr1, addr2)
|
||||
|
||||
// require validation failure with no signers
|
||||
msgs := []sdk.Msg{msg1}
|
||||
|
||||
privKeys := []tmcrypto.PrivKey{}
|
||||
accNums := []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber()}
|
||||
accSeqs := []uint64{acc1.GetSequence(), acc2.GetSequence()}
|
||||
|
||||
tx := newTestSDKTx(input.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeNoSignatures)
|
||||
|
||||
// require validation failure with invalid number of signers
|
||||
msgs = []sdk.Msg{msg1}
|
||||
|
||||
privKeys = []tmcrypto.PrivKey{priv1}
|
||||
accNums = []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber()}
|
||||
accSeqs = []uint64{acc1.GetSequence(), acc2.GetSequence()}
|
||||
|
||||
tx = newTestSDKTx(input.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeUnauthorized)
|
||||
|
||||
// require validation failure with an invalid signer
|
||||
msg2 := newTestMsg(addr1, addr3)
|
||||
msgs = []sdk.Msg{msg1, msg2}
|
||||
|
||||
privKeys = []tmcrypto.PrivKey{priv1, priv2, priv3}
|
||||
accNums = []uint64{acc1.GetAccountNumber(), acc2.GetAccountNumber(), 0}
|
||||
accSeqs = []uint64{acc1.GetSequence(), acc2.GetSequence(), 0}
|
||||
|
||||
tx = newTestSDKTx(input.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeUnknownAddress)
|
||||
}
|
||||
|
||||
func TestSDKInvalidAcc(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
|
||||
acc1 := input.accKeeper.NewAccountWithAddress(input.ctx, addr1)
|
||||
// nolint:errcheck
|
||||
acc1.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc1)
|
||||
|
||||
fee := newTestStdFee()
|
||||
msg1 := newTestMsg(addr1)
|
||||
msgs := []sdk.Msg{msg1}
|
||||
privKeys := []tmcrypto.PrivKey{priv1}
|
||||
|
||||
// require validation failure with invalid account number
|
||||
accNums := []uint64{1}
|
||||
accSeqs := []uint64{acc1.GetSequence()}
|
||||
|
||||
tx := newTestSDKTx(input.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeUnauthorized)
|
||||
|
||||
// require validation failure with invalid sequence (nonce)
|
||||
accNums = []uint64{acc1.GetAccountNumber()}
|
||||
accSeqs = []uint64{1}
|
||||
|
||||
tx = newTestSDKTx(input.ctx, msgs, privKeys, accNums, accSeqs, fee)
|
||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeUnauthorized)
|
||||
}
|
||||
|
||||
func TestEthInvalidSig(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
|
||||
_, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||
ctx := input.ctx.WithChainID("4")
|
||||
requireInvalidTx(t, input.anteHandler, ctx, tx, false, sdk.CodeUnauthorized)
|
||||
}
|
||||
|
||||
func TestEthInvalidNonce(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := input.accKeeper.NewAccountWithAddress(input.ctx, addr1)
|
||||
// nolint:errcheck
|
||||
acc.SetCoins(newTestCoins())
|
||||
// nolint:errcheck
|
||||
acc.SetSequence(10)
|
||||
input.accKeeper.SetAccount(input.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInvalidSequence)
|
||||
}
|
||||
|
||||
func TestEthInsufficientBalance(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := input.accKeeper.NewAccountWithAddress(input.ctx, addr1)
|
||||
input.accKeeper.SetAccount(input.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInsufficientFunds)
|
||||
}
|
||||
|
||||
func TestEthInvalidIntrinsicGas(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := input.accKeeper.NewAccountWithAddress(input.ctx, addr1)
|
||||
// nolint:errcheck
|
||||
acc.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
gasLimit := uint64(1000)
|
||||
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, gasLimit, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInternal)
|
||||
}
|
||||
|
||||
func TestEthInvalidMempoolFees(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
input.ctx = input.ctx.WithMinGasPrices(sdk.DecCoins{sdk.NewDecCoin(types.DenomDefault, sdk.NewInt(500000))})
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := input.accKeeper.NewAccountWithAddress(input.ctx, addr1)
|
||||
// nolint:errcheck
|
||||
acc.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||
requireInvalidTx(t, input.anteHandler, input.ctx, tx, false, sdk.CodeInsufficientFee)
|
||||
}
|
||||
|
||||
func TestEthInvalidChainID(t *testing.T) {
|
||||
input := newTestSetup()
|
||||
input.ctx = input.ctx.WithBlockHeight(1)
|
||||
|
||||
addr1, priv1 := newTestAddrKey()
|
||||
addr2, _ := newTestAddrKey()
|
||||
|
||||
acc := input.accKeeper.NewAccountWithAddress(input.ctx, addr1)
|
||||
// nolint:errcheck
|
||||
acc.SetCoins(newTestCoins())
|
||||
input.accKeeper.SetAccount(input.ctx, acc)
|
||||
|
||||
// require a valid Ethereum tx to pass
|
||||
to := ethcmn.BytesToAddress(addr2.Bytes())
|
||||
amt := big.NewInt(32)
|
||||
gas := big.NewInt(20)
|
||||
ethMsg := evmtypes.NewEthereumTxMsg(0, &to, amt, 22000, gas, []byte("test"))
|
||||
|
||||
tx := newTestEthTx(input.ctx, ethMsg, priv1)
|
||||
ctx := input.ctx.WithChainID("bad-chain-id")
|
||||
requireInvalidTx(t, input.anteHandler, ctx, tx, false, types.CodeInvalidChainID)
|
||||
}
|
||||
+160
-80
@@ -1,15 +1,13 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||
"github.com/cosmos/ethermint/x/evm"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
cryptokeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
@@ -26,12 +24,14 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
|
||||
"github.com/cosmos/ethermint/app/ante"
|
||||
emintcrypto "github.com/cosmos/ethermint/crypto"
|
||||
eminttypes "github.com/cosmos/ethermint/types"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
"github.com/cosmos/ethermint/x/evm"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
tmlog "github.com/tendermint/tendermint/libs/log"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
)
|
||||
|
||||
@@ -44,21 +44,23 @@ var (
|
||||
// DefaultNodeHome sets the folder where the applcation data and configuration will be stored
|
||||
DefaultNodeHome = os.ExpandEnv("$HOME/.emintd")
|
||||
|
||||
// ModuleBasics is the module BasicManager is in charge of setting up basic,
|
||||
// ModuleBasics defines the module BasicManager is in charge of setting up basic,
|
||||
// non-dependant module elements, such as codec registration
|
||||
// and genesis verification.
|
||||
ModuleBasics = module.NewBasicManager(
|
||||
genutil.AppModuleBasic{},
|
||||
auth.AppModuleBasic{},
|
||||
supply.AppModuleBasic{},
|
||||
genutil.AppModuleBasic{},
|
||||
bank.AppModuleBasic{},
|
||||
staking.AppModuleBasic{},
|
||||
mint.AppModuleBasic{},
|
||||
distr.AppModuleBasic{},
|
||||
gov.NewAppModuleBasic(paramsclient.ProposalHandler, distr.ProposalHandler),
|
||||
gov.NewAppModuleBasic(
|
||||
paramsclient.ProposalHandler, distr.ProposalHandler,
|
||||
),
|
||||
params.AppModuleBasic{},
|
||||
crisis.AppModuleBasic{},
|
||||
slashing.AppModuleBasic{},
|
||||
supply.AppModuleBasic{},
|
||||
evm.AppModuleBasic{},
|
||||
)
|
||||
|
||||
@@ -71,6 +73,11 @@ var (
|
||||
staking.NotBondedPoolName: {supply.Burner, supply.Staking},
|
||||
gov.ModuleName: {supply.Burner},
|
||||
}
|
||||
|
||||
// module accounts that are allowed to receive tokens
|
||||
allowedReceivingModAcc = map[string]bool{
|
||||
distr.ModuleName: true,
|
||||
}
|
||||
)
|
||||
|
||||
// MakeCodec generates the necessary codecs for Amino
|
||||
@@ -100,18 +107,21 @@ type EthermintApp struct {
|
||||
keys map[string]*sdk.KVStoreKey
|
||||
tkeys map[string]*sdk.TransientStoreKey
|
||||
|
||||
// subspaces
|
||||
subspaces map[string]params.Subspace
|
||||
|
||||
// keepers
|
||||
accountKeeper auth.AccountKeeper
|
||||
bankKeeper bank.Keeper
|
||||
supplyKeeper supply.Keeper
|
||||
stakingKeeper staking.Keeper
|
||||
slashingKeeper slashing.Keeper
|
||||
mintKeeper mint.Keeper
|
||||
distrKeeper distr.Keeper
|
||||
govKeeper gov.Keeper
|
||||
crisisKeeper crisis.Keeper
|
||||
paramsKeeper params.Keeper
|
||||
evmKeeper evm.Keeper
|
||||
AccountKeeper auth.AccountKeeper
|
||||
BankKeeper bank.Keeper
|
||||
SupplyKeeper supply.Keeper
|
||||
StakingKeeper staking.Keeper
|
||||
SlashingKeeper slashing.Keeper
|
||||
MintKeeper mint.Keeper
|
||||
DistrKeeper distr.Keeper
|
||||
GovKeeper gov.Keeper
|
||||
CrisisKeeper crisis.Keeper
|
||||
ParamsKeeper params.Keeper
|
||||
EvmKeeper evm.Keeper
|
||||
|
||||
// the module manager
|
||||
mm *module.Manager
|
||||
@@ -124,18 +134,25 @@ type EthermintApp struct {
|
||||
// in a sovereign zone and as an application running with a shared security model.
|
||||
// For now, it will support only running as a sovereign application.
|
||||
func NewEthermintApp(
|
||||
logger tmlog.Logger, db dbm.DB, loadLatest bool,
|
||||
invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp)) *EthermintApp {
|
||||
logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp),
|
||||
) *EthermintApp {
|
||||
|
||||
cdc := MakeCodec()
|
||||
|
||||
bApp := bam.NewBaseApp(appName, logger, db, evmtypes.TxDecoder(cdc), baseAppOptions...)
|
||||
// use custom Ethermint transaction decoder
|
||||
bApp := bam.NewBaseApp(appName, logger, db, evm.TxDecoder(cdc), baseAppOptions...)
|
||||
bApp.SetCommitMultiStoreTracer(traceStore)
|
||||
bApp.SetAppVersion(version.Version)
|
||||
|
||||
keys := sdk.NewKVStoreKeys(bam.MainStoreKey, auth.StoreKey, staking.StoreKey,
|
||||
keys := sdk.NewKVStoreKeys(
|
||||
bam.MainStoreKey, auth.StoreKey, staking.StoreKey,
|
||||
supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
|
||||
gov.StoreKey, params.StoreKey, evmtypes.EvmStoreKey, evmtypes.EvmCodeKey)
|
||||
blockKey := sdk.NewKVStoreKey(evmtypes.EvmBlockKey)
|
||||
tkeys := sdk.NewTransientStoreKeys(staking.TStoreKey, params.TStoreKey)
|
||||
gov.StoreKey, params.StoreKey, evm.CodeKey, evm.StoreKey,
|
||||
)
|
||||
blockKey := sdk.NewKVStoreKey(evm.BlockKey)
|
||||
|
||||
tkeys := sdk.NewTransientStoreKeys(params.TStoreKey)
|
||||
|
||||
app := &EthermintApp{
|
||||
BaseApp: bApp,
|
||||
@@ -143,89 +160,118 @@ func NewEthermintApp(
|
||||
invCheckPeriod: invCheckPeriod,
|
||||
keys: keys,
|
||||
tkeys: tkeys,
|
||||
subspaces: make(map[string]params.Subspace),
|
||||
}
|
||||
|
||||
// init params keeper and subspaces
|
||||
app.paramsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tkeys[params.TStoreKey], params.DefaultCodespace)
|
||||
authSubspace := app.paramsKeeper.Subspace(auth.DefaultParamspace)
|
||||
bankSubspace := app.paramsKeeper.Subspace(bank.DefaultParamspace)
|
||||
stakingSubspace := app.paramsKeeper.Subspace(staking.DefaultParamspace)
|
||||
mintSubspace := app.paramsKeeper.Subspace(mint.DefaultParamspace)
|
||||
distrSubspace := app.paramsKeeper.Subspace(distr.DefaultParamspace)
|
||||
slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace)
|
||||
govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
|
||||
crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace)
|
||||
app.ParamsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tkeys[params.TStoreKey], params.DefaultCodespace)
|
||||
app.subspaces[auth.ModuleName] = app.ParamsKeeper.Subspace(auth.DefaultParamspace)
|
||||
app.subspaces[bank.ModuleName] = app.ParamsKeeper.Subspace(bank.DefaultParamspace)
|
||||
app.subspaces[staking.ModuleName] = app.ParamsKeeper.Subspace(staking.DefaultParamspace)
|
||||
app.subspaces[mint.ModuleName] = app.ParamsKeeper.Subspace(mint.DefaultParamspace)
|
||||
app.subspaces[distr.ModuleName] = app.ParamsKeeper.Subspace(distr.DefaultParamspace)
|
||||
app.subspaces[slashing.ModuleName] = app.ParamsKeeper.Subspace(slashing.DefaultParamspace)
|
||||
app.subspaces[gov.ModuleName] = app.ParamsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
|
||||
app.subspaces[crisis.ModuleName] = app.ParamsKeeper.Subspace(crisis.DefaultParamspace)
|
||||
|
||||
// add keepers
|
||||
app.accountKeeper = auth.NewAccountKeeper(app.cdc, keys[auth.StoreKey], authSubspace, eminttypes.ProtoBaseAccount)
|
||||
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, bankSubspace, bank.DefaultCodespace, app.ModuleAccountAddrs())
|
||||
app.supplyKeeper = supply.NewKeeper(app.cdc, keys[supply.StoreKey], app.accountKeeper, app.bankKeeper, maccPerms)
|
||||
stakingKeeper := staking.NewKeeper(app.cdc, keys[staking.StoreKey],
|
||||
app.supplyKeeper, stakingSubspace, staking.DefaultCodespace)
|
||||
app.mintKeeper = mint.NewKeeper(app.cdc, keys[mint.StoreKey], mintSubspace, &stakingKeeper, app.supplyKeeper, auth.FeeCollectorName)
|
||||
app.distrKeeper = distr.NewKeeper(app.cdc, keys[distr.StoreKey], distrSubspace, &stakingKeeper,
|
||||
app.supplyKeeper, distr.DefaultCodespace, auth.FeeCollectorName, app.ModuleAccountAddrs())
|
||||
app.slashingKeeper = slashing.NewKeeper(app.cdc, keys[slashing.StoreKey], &stakingKeeper,
|
||||
slashingSubspace, slashing.DefaultCodespace)
|
||||
app.crisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.supplyKeeper, auth.FeeCollectorName)
|
||||
app.evmKeeper = evm.NewKeeper(app.accountKeeper, keys[evmtypes.EvmStoreKey], keys[evmtypes.EvmCodeKey], blockKey, cdc)
|
||||
// use custom Ethermint account for contracts
|
||||
app.AccountKeeper = auth.NewAccountKeeper(
|
||||
app.cdc, keys[auth.StoreKey], app.subspaces[auth.ModuleName], eminttypes.ProtoBaseAccount,
|
||||
)
|
||||
app.BankKeeper = bank.NewBaseKeeper(
|
||||
app.AccountKeeper, app.subspaces[bank.ModuleName], bank.DefaultCodespace, app.ModuleAccountAddrs(),
|
||||
)
|
||||
app.SupplyKeeper = supply.NewKeeper(
|
||||
app.cdc, keys[supply.StoreKey], app.AccountKeeper, app.BankKeeper, maccPerms,
|
||||
)
|
||||
stakingKeeper := staking.NewKeeper(
|
||||
app.cdc, keys[staking.StoreKey], app.SupplyKeeper, app.subspaces[staking.ModuleName],
|
||||
staking.DefaultCodespace,
|
||||
)
|
||||
app.MintKeeper = mint.NewKeeper(
|
||||
app.cdc, keys[mint.StoreKey], app.subspaces[mint.ModuleName], &stakingKeeper,
|
||||
app.SupplyKeeper, auth.FeeCollectorName,
|
||||
)
|
||||
app.DistrKeeper = distr.NewKeeper(
|
||||
app.cdc, keys[distr.StoreKey], app.subspaces[distr.ModuleName], &stakingKeeper,
|
||||
app.SupplyKeeper, distr.DefaultCodespace, auth.FeeCollectorName, app.ModuleAccountAddrs(),
|
||||
)
|
||||
app.SlashingKeeper = slashing.NewKeeper(
|
||||
app.cdc, keys[slashing.StoreKey], &stakingKeeper, app.subspaces[slashing.ModuleName],
|
||||
slashing.DefaultCodespace,
|
||||
)
|
||||
app.CrisisKeeper = crisis.NewKeeper(
|
||||
app.subspaces[crisis.ModuleName], invCheckPeriod, app.SupplyKeeper, auth.FeeCollectorName,
|
||||
)
|
||||
app.EvmKeeper = evm.NewKeeper(
|
||||
app.cdc, blockKey, keys[evm.CodeKey], keys[evm.StoreKey], app.AccountKeeper,
|
||||
)
|
||||
|
||||
// register the proposal types
|
||||
govRouter := gov.NewRouter()
|
||||
govRouter.AddRoute(gov.RouterKey, gov.ProposalHandler).
|
||||
AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper)).
|
||||
AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper))
|
||||
app.govKeeper = gov.NewKeeper(app.cdc, keys[gov.StoreKey], govSubspace,
|
||||
app.supplyKeeper, &stakingKeeper, gov.DefaultCodespace, govRouter)
|
||||
AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
|
||||
AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper))
|
||||
app.GovKeeper = gov.NewKeeper(
|
||||
app.cdc, keys[gov.StoreKey], app.subspaces[gov.ModuleName], app.SupplyKeeper,
|
||||
&stakingKeeper, gov.DefaultCodespace, govRouter,
|
||||
)
|
||||
|
||||
// register the staking hooks
|
||||
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
|
||||
app.stakingKeeper = *stakingKeeper.SetHooks(
|
||||
staking.NewMultiStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()),
|
||||
app.StakingKeeper = *stakingKeeper.SetHooks(
|
||||
staking.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()),
|
||||
)
|
||||
|
||||
// NOTE: Any module instantiated in the module manager that is later modified
|
||||
// must be passed by reference here.
|
||||
app.mm = module.NewManager(
|
||||
genutil.NewAppModule(app.accountKeeper, app.stakingKeeper, app.BaseApp.DeliverTx),
|
||||
auth.NewAppModule(app.accountKeeper),
|
||||
bank.NewAppModule(app.bankKeeper, app.accountKeeper),
|
||||
crisis.NewAppModule(&app.crisisKeeper),
|
||||
supply.NewAppModule(app.supplyKeeper, app.accountKeeper),
|
||||
distr.NewAppModule(app.distrKeeper, app.accountKeeper, app.supplyKeeper, app.stakingKeeper),
|
||||
gov.NewAppModule(app.govKeeper, app.accountKeeper, app.supplyKeeper),
|
||||
mint.NewAppModule(app.mintKeeper),
|
||||
slashing.NewAppModule(app.slashingKeeper, app.accountKeeper, app.stakingKeeper),
|
||||
staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
|
||||
evm.NewAppModule(app.evmKeeper),
|
||||
genutil.NewAppModule(app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx),
|
||||
auth.NewAppModule(app.AccountKeeper),
|
||||
bank.NewAppModule(app.BankKeeper, app.AccountKeeper),
|
||||
crisis.NewAppModule(&app.CrisisKeeper),
|
||||
supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper),
|
||||
gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.SupplyKeeper),
|
||||
mint.NewAppModule(app.MintKeeper),
|
||||
slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper),
|
||||
distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper),
|
||||
staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper),
|
||||
evm.NewAppModule(app.EvmKeeper),
|
||||
)
|
||||
|
||||
// During begin block slashing happens after distr.BeginBlocker so that
|
||||
// there is nothing left over in the validator fee pool, so as to keep the
|
||||
// CanWithdrawInvariant invariant.
|
||||
app.mm.SetOrderBeginBlockers(evmtypes.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName)
|
||||
|
||||
app.mm.SetOrderEndBlockers(evmtypes.ModuleName, crisis.ModuleName, gov.ModuleName, staking.ModuleName)
|
||||
app.mm.SetOrderBeginBlockers(
|
||||
evm.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName,
|
||||
)
|
||||
app.mm.SetOrderEndBlockers(
|
||||
evm.ModuleName, crisis.ModuleName, gov.ModuleName, staking.ModuleName,
|
||||
)
|
||||
|
||||
// NOTE: The genutils module must occur after staking so that pools are
|
||||
// properly initialized with tokens from genesis accounts.
|
||||
app.mm.SetOrderInitGenesis(
|
||||
distr.ModuleName, staking.ModuleName,
|
||||
auth.ModuleName, bank.ModuleName, slashing.ModuleName, gov.ModuleName,
|
||||
mint.ModuleName, supply.ModuleName, crisis.ModuleName, genutil.ModuleName, evmtypes.ModuleName,
|
||||
auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName,
|
||||
slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName,
|
||||
crisis.ModuleName, genutil.ModuleName, evm.ModuleName,
|
||||
)
|
||||
|
||||
app.mm.RegisterInvariants(&app.crisisKeeper)
|
||||
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
||||
app.mm.RegisterRoutes(app.Router(), app.QueryRouter())
|
||||
|
||||
// initialize stores
|
||||
app.MountKVStores(keys)
|
||||
app.MountTransientStores(tkeys)
|
||||
|
||||
// Mount block hash mapping key as DB (no need for historical queries)
|
||||
// TODO: why does this need to be always StoreTypeDB?
|
||||
app.MountStore(blockKey, sdk.StoreTypeDB)
|
||||
|
||||
// initialize BaseApp
|
||||
app.SetInitChainer(app.InitChainer)
|
||||
app.SetBeginBlocker(app.BeginBlocker)
|
||||
app.SetAnteHandler(NewAnteHandler(app.accountKeeper, app.supplyKeeper))
|
||||
app.SetAnteHandler(ante.NewAnteHandler(app.AccountKeeper, app.SupplyKeeper))
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
|
||||
if loadLatest {
|
||||
@@ -234,12 +280,12 @@ func NewEthermintApp(
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// GenesisState is the state of the blockchain is represented here as a map of raw json
|
||||
// messages key'd by a identifier string.
|
||||
type GenesisState map[string]json.RawMessage
|
||||
// Name returns the name of the App
|
||||
func (app *EthermintApp) Name() string { return app.BaseApp.Name() }
|
||||
|
||||
// BeginBlocker updates every begin block
|
||||
func (app *EthermintApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
||||
@@ -253,7 +299,7 @@ func (app *EthermintApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) a
|
||||
|
||||
// InitChainer updates at chain initialization
|
||||
func (app *EthermintApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
var genesisState GenesisState
|
||||
var genesisState simapp.GenesisState
|
||||
app.cdc.MustUnmarshalJSON(req.AppStateBytes, &genesisState)
|
||||
return app.mm.InitGenesis(ctx, genesisState)
|
||||
}
|
||||
@@ -267,8 +313,42 @@ func (app *EthermintApp) LoadHeight(height int64) error {
|
||||
func (app *EthermintApp) ModuleAccountAddrs() map[string]bool {
|
||||
modAccAddrs := make(map[string]bool)
|
||||
for acc := range maccPerms {
|
||||
modAccAddrs[app.supplyKeeper.GetModuleAddress(acc).String()] = true
|
||||
modAccAddrs[supply.NewModuleAddress(acc).String()] = true
|
||||
}
|
||||
|
||||
return modAccAddrs
|
||||
}
|
||||
|
||||
// BlacklistedAccAddrs returns all the app's module account addresses black listed for receiving tokens.
|
||||
func (app *EthermintApp) BlacklistedAccAddrs() map[string]bool {
|
||||
blacklistedAddrs := make(map[string]bool)
|
||||
for acc := range maccPerms {
|
||||
blacklistedAddrs[supply.NewModuleAddress(acc).String()] = !allowedReceivingModAcc[acc]
|
||||
}
|
||||
|
||||
return blacklistedAddrs
|
||||
}
|
||||
|
||||
// GetKey returns the KVStoreKey for the provided store key.
|
||||
//
|
||||
// NOTE: This is solely to be used for testing purposes.
|
||||
func (app *EthermintApp) GetKey(storeKey string) *sdk.KVStoreKey {
|
||||
return app.keys[storeKey]
|
||||
}
|
||||
|
||||
// Codec returns Ethermint's codec.
|
||||
//
|
||||
// NOTE: This is solely to be used for testing purposes as it may be desirable
|
||||
// for modules to register their own custom testing types.
|
||||
func (app *EthermintApp) Codec() *codec.Codec {
|
||||
return app.cdc
|
||||
}
|
||||
|
||||
// GetMaccPerms returns a copy of the module account permissions
|
||||
func GetMaccPerms() map[string][]string {
|
||||
dupMaccPerms := make(map[string][]string)
|
||||
for k, v := range maccPerms {
|
||||
dupMaccPerms[k] = v
|
||||
}
|
||||
return dupMaccPerms
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
func TestEthermintAppExport(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
app := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, true, 0)
|
||||
app := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0)
|
||||
|
||||
genesisState := ModuleBasics.DefaultGenesis()
|
||||
stateBytes, err := codec.MarshalJSONIndent(app.cdc, genesisState)
|
||||
@@ -31,7 +31,7 @@ func TestEthermintAppExport(t *testing.T) {
|
||||
app.Commit()
|
||||
|
||||
// Making a new app object with the db, so that initchain hasn't been called
|
||||
app2 := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, true, 0)
|
||||
app2 := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0)
|
||||
_, _, err = app2.ExportAppStateAndValidators(false, []string{})
|
||||
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
||||
}
|
||||
|
||||
+24
-25
@@ -35,7 +35,7 @@ func (app *EthermintApp) ExportAppStateAndValidators(
|
||||
}
|
||||
|
||||
// Write validators to staking module to be used by TM node
|
||||
validators = staking.WriteValidators(ctx, app.stakingKeeper)
|
||||
validators = staking.WriteValidators(ctx, app.StakingKeeper)
|
||||
return appState, validators, nil
|
||||
}
|
||||
|
||||
@@ -61,49 +61,48 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList
|
||||
}
|
||||
|
||||
/* Just to be safe, assert the invariants on current state. */
|
||||
app.crisisKeeper.AssertInvariants(ctx)
|
||||
app.CrisisKeeper.AssertInvariants(ctx)
|
||||
|
||||
/* Handle fee distribution state. */
|
||||
|
||||
// withdraw all validator commission
|
||||
app.stakingKeeper.IterateValidators(ctx, func(_ int64, val exported.ValidatorI) (stop bool) {
|
||||
_, _ = app.distrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator())
|
||||
app.StakingKeeper.IterateValidators(ctx, func(_ int64, val exported.ValidatorI) (stop bool) {
|
||||
_, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator())
|
||||
return false
|
||||
})
|
||||
|
||||
// withdraw all delegator rewards
|
||||
dels := app.stakingKeeper.GetAllDelegations(ctx)
|
||||
dels := app.StakingKeeper.GetAllDelegations(ctx)
|
||||
for _, delegation := range dels {
|
||||
_, _ = app.distrKeeper.WithdrawDelegationRewards(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress)
|
||||
_, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress)
|
||||
}
|
||||
|
||||
// clear validator slash events
|
||||
app.distrKeeper.DeleteAllValidatorSlashEvents(ctx)
|
||||
app.DistrKeeper.DeleteAllValidatorSlashEvents(ctx)
|
||||
|
||||
// clear validator historical rewards
|
||||
app.distrKeeper.DeleteAllValidatorHistoricalRewards(ctx)
|
||||
app.DistrKeeper.DeleteAllValidatorHistoricalRewards(ctx)
|
||||
|
||||
// set context height to zero
|
||||
height := ctx.BlockHeight()
|
||||
ctx = ctx.WithBlockHeight(0)
|
||||
|
||||
// reinitialize all validators
|
||||
app.stakingKeeper.IterateValidators(ctx, func(_ int64, val exported.ValidatorI) (stop bool) {
|
||||
|
||||
app.StakingKeeper.IterateValidators(ctx, func(_ int64, val exported.ValidatorI) (stop bool) {
|
||||
// donate any unwithdrawn outstanding reward fraction tokens to the community pool
|
||||
scraps := app.distrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator())
|
||||
feePool := app.distrKeeper.GetFeePool(ctx)
|
||||
scraps := app.DistrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator())
|
||||
feePool := app.DistrKeeper.GetFeePool(ctx)
|
||||
feePool.CommunityPool = feePool.CommunityPool.Add(scraps)
|
||||
app.distrKeeper.SetFeePool(ctx, feePool)
|
||||
app.DistrKeeper.SetFeePool(ctx, feePool)
|
||||
|
||||
app.distrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator())
|
||||
app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator())
|
||||
return false
|
||||
})
|
||||
|
||||
// reinitialize all delegations
|
||||
for _, del := range dels {
|
||||
app.distrKeeper.Hooks().BeforeDelegationCreated(ctx, del.DelegatorAddress, del.ValidatorAddress)
|
||||
app.distrKeeper.Hooks().AfterDelegationModified(ctx, del.DelegatorAddress, del.ValidatorAddress)
|
||||
app.DistrKeeper.Hooks().BeforeDelegationCreated(ctx, del.DelegatorAddress, del.ValidatorAddress)
|
||||
app.DistrKeeper.Hooks().AfterDelegationModified(ctx, del.DelegatorAddress, del.ValidatorAddress)
|
||||
}
|
||||
|
||||
// reset context height
|
||||
@@ -112,20 +111,20 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList
|
||||
/* Handle staking state. */
|
||||
|
||||
// iterate through redelegations, reset creation height
|
||||
app.stakingKeeper.IterateRedelegations(ctx, func(_ int64, red staking.Redelegation) (stop bool) {
|
||||
app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red staking.Redelegation) (stop bool) {
|
||||
for i := range red.Entries {
|
||||
red.Entries[i].CreationHeight = 0
|
||||
}
|
||||
app.stakingKeeper.SetRedelegation(ctx, red)
|
||||
app.StakingKeeper.SetRedelegation(ctx, red)
|
||||
return false
|
||||
})
|
||||
|
||||
// iterate through unbonding delegations, reset creation height
|
||||
app.stakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd staking.UnbondingDelegation) (stop bool) {
|
||||
app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd staking.UnbondingDelegation) (stop bool) {
|
||||
for i := range ubd.Entries {
|
||||
ubd.Entries[i].CreationHeight = 0
|
||||
}
|
||||
app.stakingKeeper.SetUnbondingDelegation(ctx, ubd)
|
||||
app.StakingKeeper.SetUnbondingDelegation(ctx, ubd)
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -137,7 +136,7 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList
|
||||
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
addr := sdk.ValAddress(iter.Key()[1:])
|
||||
validator, found := app.stakingKeeper.GetValidator(ctx, addr)
|
||||
validator, found := app.StakingKeeper.GetValidator(ctx, addr)
|
||||
if !found {
|
||||
panic("expected validator, not found")
|
||||
}
|
||||
@@ -147,22 +146,22 @@ func (app *EthermintApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList
|
||||
validator.Jailed = true
|
||||
}
|
||||
|
||||
app.stakingKeeper.SetValidator(ctx, validator)
|
||||
app.StakingKeeper.SetValidator(ctx, validator)
|
||||
counter++
|
||||
}
|
||||
|
||||
iter.Close()
|
||||
|
||||
_ = app.stakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
_ = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
|
||||
/* Handle slashing state. */
|
||||
|
||||
// reset start height on signing infos
|
||||
app.slashingKeeper.IterateValidatorSigningInfos(
|
||||
app.SlashingKeeper.IterateValidatorSigningInfos(
|
||||
ctx,
|
||||
func(addr sdk.ConsAddress, info slashing.ValidatorSigningInfo) (stop bool) {
|
||||
info.StartHeight = 0
|
||||
app.slashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
|
||||
app.SlashingKeeper.SetValidatorSigningInfo(ctx, addr, info)
|
||||
return false
|
||||
},
|
||||
)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
)
|
||||
|
||||
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
||||
func Setup(isCheckTx bool) *EthermintApp {
|
||||
db := dbm.NewMemDB()
|
||||
app := NewEthermintApp(log.NewNopLogger(), db, nil, true, 0)
|
||||
if !isCheckTx {
|
||||
// init chain must be called to stop deliverState from being nil
|
||||
genesisState := simapp.NewDefaultGenesisState()
|
||||
stateBytes, err := codec.MarshalJSONIndent(app.Codec(), genesisState)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Initialize the chain
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
AppStateBytes: stateBytes,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/mock"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
|
||||
"github.com/cosmos/ethermint/crypto"
|
||||
emint "github.com/cosmos/ethermint/types"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
)
|
||||
|
||||
type testSetup struct {
|
||||
ctx sdk.Context
|
||||
cdc *codec.Codec
|
||||
accKeeper auth.AccountKeeper
|
||||
supplyKeeper types.SupplyKeeper
|
||||
anteHandler sdk.AnteHandler
|
||||
}
|
||||
|
||||
func newTestSetup() testSetup {
|
||||
db := dbm.NewMemDB()
|
||||
authCapKey := sdk.NewKVStoreKey("authCapKey")
|
||||
keySupply := sdk.NewKVStoreKey("keySupply")
|
||||
keyParams := sdk.NewKVStoreKey("params")
|
||||
tkeyParams := sdk.NewTransientStoreKey("transient_params")
|
||||
|
||||
ms := store.NewCommitMultiStore(db)
|
||||
ms.MountStoreWithDB(authCapKey, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keySupply, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(keyParams, sdk.StoreTypeIAVL, db)
|
||||
ms.MountStoreWithDB(tkeyParams, sdk.StoreTypeIAVL, db)
|
||||
|
||||
if err := ms.LoadLatestVersion(); err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
}
|
||||
|
||||
cdc := MakeCodec()
|
||||
cdc.RegisterConcrete(&sdk.TestMsg{}, "test/TestMsg", nil)
|
||||
|
||||
// Set params keeper and subspaces
|
||||
paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace)
|
||||
authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace)
|
||||
|
||||
ctx := sdk.NewContext(
|
||||
ms,
|
||||
abci.Header{ChainID: "3", Time: time.Now().UTC()},
|
||||
true,
|
||||
log.NewNopLogger(),
|
||||
)
|
||||
|
||||
// Add keepers
|
||||
accKeeper := auth.NewAccountKeeper(cdc, authCapKey, authSubspace, auth.ProtoBaseAccount)
|
||||
accKeeper.SetParams(ctx, types.DefaultParams())
|
||||
supplyKeeper := mock.NewDummySupplyKeeper(accKeeper)
|
||||
anteHandler := NewAnteHandler(accKeeper, supplyKeeper)
|
||||
|
||||
return testSetup{
|
||||
ctx: ctx,
|
||||
cdc: cdc,
|
||||
accKeeper: accKeeper,
|
||||
supplyKeeper: supplyKeeper,
|
||||
anteHandler: anteHandler,
|
||||
}
|
||||
}
|
||||
|
||||
func newTestMsg(addrs ...sdk.AccAddress) *sdk.TestMsg {
|
||||
return sdk.NewTestMsg(addrs...)
|
||||
}
|
||||
|
||||
func newTestCoins() sdk.Coins {
|
||||
return sdk.Coins{sdk.NewInt64Coin(emint.DenomDefault, 500000000)}
|
||||
}
|
||||
|
||||
func newTestStdFee() auth.StdFee {
|
||||
return auth.NewStdFee(220000, sdk.NewCoins(sdk.NewInt64Coin(emint.DenomDefault, 150)))
|
||||
}
|
||||
|
||||
// GenerateAddress generates an Ethereum address.
|
||||
func newTestAddrKey() (sdk.AccAddress, tmcrypto.PrivKey) {
|
||||
privkey, _ := crypto.GenerateKey()
|
||||
addr := ethcrypto.PubkeyToAddress(privkey.ToECDSA().PublicKey)
|
||||
|
||||
return sdk.AccAddress(addr.Bytes()), privkey
|
||||
}
|
||||
|
||||
func newTestSDKTx(
|
||||
ctx sdk.Context, msgs []sdk.Msg, privs []tmcrypto.PrivKey,
|
||||
accNums []uint64, seqs []uint64, fee auth.StdFee,
|
||||
) sdk.Tx {
|
||||
|
||||
sigs := make([]auth.StdSignature, len(privs))
|
||||
for i, priv := range privs {
|
||||
signBytes := auth.StdSignBytes(ctx.ChainID(), accNums[i], seqs[i], fee, msgs, "")
|
||||
|
||||
sig, err := priv.Sign(signBytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sigs[i] = auth.StdSignature{
|
||||
PubKey: priv.PubKey(),
|
||||
Signature: sig,
|
||||
}
|
||||
}
|
||||
|
||||
return auth.NewStdTx(msgs, fee, sigs, "")
|
||||
}
|
||||
|
||||
func newTestEthTx(ctx sdk.Context, msg *evmtypes.EthereumTxMsg, priv tmcrypto.PrivKey) sdk.Tx {
|
||||
chainID, ok := new(big.Int).SetString(ctx.ChainID(), 10)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("invalid chainID: %s", ctx.ChainID()))
|
||||
}
|
||||
|
||||
privkey, ok := priv.(crypto.PrivKeySecp256k1)
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("invalid private key type: %T", priv))
|
||||
}
|
||||
|
||||
msg.Sign(chainID, privkey.ToECDSA())
|
||||
return msg
|
||||
}
|
||||
Reference in New Issue
Block a user