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:
Federico Kunze
2020-04-01 15:49:21 -03:00
committed by GitHub
parent 1627ed81bf
commit da9157e406
46 changed files with 1630 additions and 1234 deletions
+28 -20
View File
@@ -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 accounts
@@ -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(),
),
)
}
+301
View File
@@ -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)
}
+104
View File
@@ -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
}
-308
View File
@@ -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
View File
@@ -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
}
+2 -2
View File
@@ -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
View File
@@ -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
},
)
+34
View File
@@ -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
}
-138
View File
@@ -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
}