forked from cerc-io/laconicd-deprecated
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21f42d27c7 | ||
|
|
a031f9abca | ||
|
|
47bafe4619 | ||
|
|
fc0ade482d | ||
|
|
dbaaef07c7 | ||
|
|
b9e7398220 | ||
|
|
1aa98edb04 | ||
|
|
9794007231 | ||
|
|
d41612b891 | ||
|
|
3ef957206c | ||
|
|
151747bc81 |
+1
-1
@@ -11,9 +11,9 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
authante "github.com/tharsis/ethermint/x/auth/ante"
|
||||
|
||||
channelkeeper "github.com/cosmos/ibc-go/modules/core/04-channel/keeper"
|
||||
ibcante "github.com/cosmos/ibc-go/modules/core/ante"
|
||||
|
||||
+3
-2
@@ -4,9 +4,10 @@ import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
authante "github.com/tharsis/ethermint/x/auth/ante"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
"github.com/palantir/stacktrace"
|
||||
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
@@ -28,7 +29,7 @@ type EVMKeeper interface {
|
||||
GetParams(ctx sdk.Context) evmtypes.Params
|
||||
WithContext(ctx sdk.Context)
|
||||
ResetRefundTransient(ctx sdk.Context)
|
||||
NewEVM(msg core.Message, config *params.ChainConfig, params evmtypes.Params, coinbase common.Address, tracer vm.Tracer) *vm.EVM
|
||||
NewEVM(msg core.Message, config *params.ChainConfig, params evmtypes.Params, coinbase common.Address, tracer vm.EVMLogger) *vm.EVM
|
||||
GetCodeHash(addr common.Address) common.Hash
|
||||
}
|
||||
|
||||
|
||||
+124
-62
@@ -3,6 +3,15 @@ package app
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/db"
|
||||
types2 "github.com/cosmos/cosmos-sdk/store/types"
|
||||
types3 "github.com/cosmos/cosmos-sdk/store/v2"
|
||||
"github.com/cosmos/cosmos-sdk/store/v2/multi"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/middleware"
|
||||
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -14,13 +23,10 @@ import (
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/server/api"
|
||||
@@ -64,6 +70,8 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper"
|
||||
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
|
||||
govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
|
||||
govv1beta2 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper"
|
||||
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||
@@ -87,7 +95,6 @@ import (
|
||||
ibctransferkeeper "github.com/cosmos/ibc-go/modules/apps/transfer/keeper"
|
||||
ibctransfertypes "github.com/cosmos/ibc-go/modules/apps/transfer/types"
|
||||
ibc "github.com/cosmos/ibc-go/modules/core"
|
||||
ibcclient "github.com/cosmos/ibc-go/modules/core/02-client"
|
||||
ibcclientclient "github.com/cosmos/ibc-go/modules/core/02-client/client"
|
||||
porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types"
|
||||
ibchost "github.com/cosmos/ibc-go/modules/core/24-host"
|
||||
@@ -96,7 +103,6 @@ import (
|
||||
// unnamed import of statik for swagger UI support
|
||||
_ "github.com/tharsis/ethermint/client/docs/statik"
|
||||
|
||||
"github.com/tharsis/ethermint/app/ante"
|
||||
srvflags "github.com/tharsis/ethermint/server/flags"
|
||||
ethermint "github.com/tharsis/ethermint/types"
|
||||
|
||||
@@ -208,13 +214,15 @@ type EthermintApp struct {
|
||||
cdc *codec.LegacyAmino
|
||||
appCodec codec.Codec
|
||||
interfaceRegistry types.InterfaceRegistry
|
||||
legacyRouter *middleware.LegacyRouter
|
||||
msgSvcRouter *middleware.MsgServiceRouter
|
||||
|
||||
invCheckPeriod uint
|
||||
|
||||
// keys to access the substores
|
||||
keys map[string]*sdk.KVStoreKey
|
||||
tkeys map[string]*sdk.TransientStoreKey
|
||||
memKeys map[string]*sdk.MemoryStoreKey
|
||||
keys map[string]*types2.KVStoreKey
|
||||
tkeys map[string]*types2.TransientStoreKey
|
||||
memKeys map[string]*types2.MemoryStoreKey
|
||||
|
||||
// keepers
|
||||
AccountKeeper authkeeper.AccountKeeper
|
||||
@@ -261,32 +269,19 @@ type EthermintApp struct {
|
||||
// NewEthermintApp returns a reference to a new initialized Ethermint application.
|
||||
func NewEthermintApp(
|
||||
logger log.Logger,
|
||||
db dbm.DB,
|
||||
db db.DBConnection,
|
||||
traceStore io.Writer,
|
||||
loadLatest bool,
|
||||
skipUpgradeHeights map[int64]bool,
|
||||
homePath string,
|
||||
invCheckPeriod uint,
|
||||
encodingConfig simappparams.EncodingConfig,
|
||||
appOpts servertypes.AppOptions,
|
||||
baseAppOptions ...func(*baseapp.BaseApp),
|
||||
baseAppOptions ...baseapp.AppOption,
|
||||
) *EthermintApp {
|
||||
appCodec := encodingConfig.Marshaler
|
||||
appCodec := encodingConfig.Codec
|
||||
cdc := encodingConfig.Amino
|
||||
interfaceRegistry := encodingConfig.InterfaceRegistry
|
||||
|
||||
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
||||
bApp := baseapp.NewBaseApp(
|
||||
appName,
|
||||
logger,
|
||||
db,
|
||||
encodingConfig.TxConfig.TxDecoder(),
|
||||
baseAppOptions...,
|
||||
)
|
||||
bApp.SetCommitMultiStoreTracer(traceStore)
|
||||
bApp.SetVersion(version.Version)
|
||||
bApp.SetInterfaceRegistry(interfaceRegistry)
|
||||
|
||||
keys := sdk.NewKVStoreKeys(
|
||||
// SDK keys
|
||||
authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey,
|
||||
@@ -308,11 +303,57 @@ func NewEthermintApp(
|
||||
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey)
|
||||
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)
|
||||
|
||||
// initialize stores
|
||||
setNamespaces := func(config *multi.StoreParams, ver uint64) error {
|
||||
for _, key := range keys {
|
||||
typ, err := types3.StoreKeyToType(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = config.RegisterSubstore(key, typ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, key := range memKeys {
|
||||
typ, err := types3.StoreKeyToType(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = config.RegisterSubstore(key, typ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, key := range tkeys {
|
||||
typ, err := types3.StoreKeyToType(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = config.RegisterSubstore(key, typ); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
baseAppOptions = append(baseAppOptions, baseapp.StoreOption(setNamespaces))
|
||||
|
||||
// NOTE we use custom transaction decoder that supports the sdk.Tx interface instead of sdk.StdTx
|
||||
bApp := baseapp.NewBaseApp(
|
||||
appName,
|
||||
logger,
|
||||
db,
|
||||
baseAppOptions...,
|
||||
)
|
||||
bApp.SetCommitMultiStoreTracer(traceStore)
|
||||
bApp.SetVersion(version.Version)
|
||||
bApp.SetInterfaceRegistry(interfaceRegistry)
|
||||
|
||||
app := &EthermintApp{
|
||||
BaseApp: bApp,
|
||||
cdc: cdc,
|
||||
appCodec: appCodec,
|
||||
interfaceRegistry: interfaceRegistry,
|
||||
legacyRouter: middleware.NewLegacyRouter(),
|
||||
msgSvcRouter: middleware.NewMsgServiceRouter(interfaceRegistry),
|
||||
invCheckPeriod: invCheckPeriod,
|
||||
keys: keys,
|
||||
tkeys: tkeys,
|
||||
@@ -322,7 +363,7 @@ func NewEthermintApp(
|
||||
// init params keeper and subspaces
|
||||
app.ParamsKeeper = initParamsKeeper(appCodec, cdc, keys[paramstypes.StoreKey], tkeys[paramstypes.TStoreKey])
|
||||
// set the BaseApp's parameter store
|
||||
bApp.SetParamStore(app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramskeeper.ConsensusParamsKeyTable()))
|
||||
bApp.SetParamStore(app.ParamsKeeper.Subspace(baseapp.Paramspace).WithKeyTable(paramstypes.ConsensusParamsKeyTable()))
|
||||
|
||||
// add capability keeper and ScopeToModule for ibc module
|
||||
app.CapabilityKeeper = capabilitykeeper.NewKeeper(appCodec, keys[capabilitytypes.StoreKey], memKeys[capabilitytypes.MemStoreKey])
|
||||
@@ -337,6 +378,7 @@ func NewEthermintApp(
|
||||
// use custom Ethermint account for contracts
|
||||
app.AccountKeeper = authkeeper.NewAccountKeeper(
|
||||
appCodec, keys[authtypes.StoreKey], app.GetSubspace(authtypes.ModuleName), ethermint.ProtoAccount, maccPerms,
|
||||
sdk.Bech32MainPrefix,
|
||||
)
|
||||
app.BankKeeper = bankkeeper.NewBaseKeeper(
|
||||
appCodec, keys[banktypes.StoreKey], app.AccountKeeper, app.GetSubspace(banktypes.ModuleName), app.BlockedAddrs(),
|
||||
@@ -350,7 +392,7 @@ func NewEthermintApp(
|
||||
)
|
||||
app.DistrKeeper = distrkeeper.NewKeeper(
|
||||
appCodec, keys[distrtypes.StoreKey], app.GetSubspace(distrtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
|
||||
&stakingKeeper, authtypes.FeeCollectorName, app.ModuleAccountAddrs(),
|
||||
&stakingKeeper, authtypes.FeeCollectorName,
|
||||
)
|
||||
app.SlashingKeeper = slashingkeeper.NewKeeper(
|
||||
appCodec, keys[slashingtypes.StoreKey], &stakingKeeper, app.GetSubspace(slashingtypes.ModuleName),
|
||||
@@ -367,7 +409,8 @@ func NewEthermintApp(
|
||||
stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.SlashingKeeper.Hooks()),
|
||||
)
|
||||
|
||||
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec, app.BaseApp.MsgServiceRouter())
|
||||
app.AuthzKeeper = authzkeeper.NewKeeper(keys[authzkeeper.StoreKey], appCodec,
|
||||
app.msgSvcRouter, app.AccountKeeper)
|
||||
|
||||
tracer := cast.ToString(appOpts.Get(srvflags.EVMTracer))
|
||||
|
||||
@@ -410,16 +453,19 @@ func NewEthermintApp(
|
||||
)
|
||||
|
||||
// register the proposal types
|
||||
govRouter := govtypes.NewRouter()
|
||||
govRouter.AddRoute(govtypes.RouterKey, govtypes.ProposalHandler).
|
||||
govRouter := govv1beta1.NewRouter()
|
||||
govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler).
|
||||
AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(app.ParamsKeeper)).
|
||||
AddRoute(distrtypes.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.DistrKeeper)).
|
||||
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper)).
|
||||
AddRoute(ibchost.RouterKey, ibcclient.NewClientProposalHandler(app.IBCKeeper.ClientKeeper))
|
||||
|
||||
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper))
|
||||
govConfig := govtypes.DefaultConfig()
|
||||
/*
|
||||
Example of setting gov params:
|
||||
govConfig.MaxMetadataLen = 10000
|
||||
*/
|
||||
govKeeper := govkeeper.NewKeeper(
|
||||
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
|
||||
&stakingKeeper, govRouter,
|
||||
&stakingKeeper, govRouter, app.msgSvcRouter, govConfig,
|
||||
)
|
||||
|
||||
app.GovKeeper = *govKeeper.SetHooks(
|
||||
@@ -468,7 +514,7 @@ func NewEthermintApp(
|
||||
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
|
||||
crisis.NewAppModule(&app.CrisisKeeper, skipGenesisInvariants),
|
||||
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper),
|
||||
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil),
|
||||
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
@@ -535,8 +581,8 @@ func NewEthermintApp(
|
||||
)
|
||||
|
||||
app.mm.RegisterInvariants(&app.CrisisKeeper)
|
||||
app.mm.RegisterRoutes(app.Router(), app.QueryRouter(), encodingConfig.Amino)
|
||||
app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter())
|
||||
app.mm.RegisterRoutes(app.legacyRouter, app.QueryRouter(), encodingConfig.Amino)
|
||||
app.configurator = module.NewConfigurator(app.appCodec, app.msgSvcRouter, app.GRPCQueryRouter())
|
||||
app.mm.RegisterServices(app.configurator)
|
||||
|
||||
// add test gRPC service for testing gRPC queries in isolation
|
||||
@@ -551,7 +597,7 @@ func NewEthermintApp(
|
||||
bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper),
|
||||
capability.NewAppModule(appCodec, *app.CapabilityKeeper),
|
||||
gov.NewAppModule(appCodec, app.GovKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper),
|
||||
mint.NewAppModule(appCodec, app.MintKeeper, app.AccountKeeper, nil),
|
||||
staking.NewAppModule(appCodec, app.StakingKeeper, app.AccountKeeper, app.BankKeeper),
|
||||
distr.NewAppModule(appCodec, app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
slashing.NewAppModule(appCodec, app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper),
|
||||
@@ -565,37 +611,54 @@ func NewEthermintApp(
|
||||
|
||||
app.sm.RegisterStoreDecoders()
|
||||
|
||||
// initialize stores
|
||||
app.MountKVStores(keys)
|
||||
app.MountTransientStores(tkeys)
|
||||
app.MountMemoryStores(memKeys)
|
||||
|
||||
// initialize BaseApp
|
||||
app.SetInitChainer(app.InitChainer)
|
||||
app.SetBeginBlocker(app.BeginBlocker)
|
||||
|
||||
// use Ethermint's custom AnteHandler
|
||||
app.SetAnteHandler(
|
||||
ante.NewAnteHandler(
|
||||
app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.FeeGrantKeeper, app.IBCKeeper.ChannelKeeper,
|
||||
encodingConfig.TxConfig.SignModeHandler(),
|
||||
),
|
||||
)
|
||||
// TODO: use Ethermint's custom AnteHandler
|
||||
app.setTxHandler(encodingConfig.TxConfig, cast.ToStringSlice(appOpts.Get(server.FlagIndexEvents)))
|
||||
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
|
||||
if loadLatest {
|
||||
if err := app.LoadLatestVersion(); err != nil {
|
||||
tmos.Exit(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
app.ScopedIBCKeeper = scopedIBCKeeper
|
||||
app.ScopedTransferKeeper = scopedTransferKeeper
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func (app *EthermintApp) setTxHandler(txConfig client.TxConfig, indexEventsStr []string) {
|
||||
indexEvents := map[string]struct{}{}
|
||||
for _, e := range indexEventsStr {
|
||||
indexEvents[e] = struct{}{}
|
||||
}
|
||||
// need to sub in custom tx handler
|
||||
/*
|
||||
app.SetTxHandler(
|
||||
ante.NewAnteHandler(
|
||||
app.AccountKeeper, app.BankKeeper, app.EvmKeeper, app.FeeGrantKeeper, app.IBCKeeper.ChannelKeeper,
|
||||
encodingConfig.TxConfig.SignModeHandler(),
|
||||
),
|
||||
)
|
||||
*/
|
||||
txHandler, err := middleware.NewDefaultTxHandler(middleware.TxHandlerOptions{
|
||||
Debug: app.Trace(),
|
||||
IndexEvents: indexEvents,
|
||||
LegacyRouter: app.legacyRouter,
|
||||
MsgServiceRouter: app.msgSvcRouter,
|
||||
AccountKeeper: app.AccountKeeper,
|
||||
BankKeeper: app.BankKeeper,
|
||||
FeegrantKeeper: app.FeeGrantKeeper,
|
||||
SignModeHandler: txConfig.SignModeHandler(),
|
||||
SigGasConsumer: middleware.DefaultSigVerificationGasConsumer,
|
||||
TxDecoder: txConfig.TxDecoder(),
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
app.SetTxHandler(txHandler)
|
||||
}
|
||||
|
||||
// Name returns the name of the App
|
||||
func (app *EthermintApp) Name() string { return app.BaseApp.Name() }
|
||||
|
||||
@@ -621,7 +684,7 @@ func (app *EthermintApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain)
|
||||
|
||||
// LoadHeight loads state at a particular height
|
||||
func (app *EthermintApp) LoadHeight(height int64) error {
|
||||
return app.LoadVersion(height)
|
||||
return errors.New("cannot load arbitrary height")
|
||||
}
|
||||
|
||||
// ModuleAccountAddrs returns all the app's module account addresses.
|
||||
@@ -669,21 +732,21 @@ func (app *EthermintApp) InterfaceRegistry() types.InterfaceRegistry {
|
||||
// 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 {
|
||||
func (app *EthermintApp) GetKey(storeKey string) *types3.KVStoreKey {
|
||||
return app.keys[storeKey]
|
||||
}
|
||||
|
||||
// GetTKey returns the TransientStoreKey for the provided store key.
|
||||
//
|
||||
// NOTE: This is solely to be used for testing purposes.
|
||||
func (app *EthermintApp) GetTKey(storeKey string) *sdk.TransientStoreKey {
|
||||
func (app *EthermintApp) GetTKey(storeKey string) *types3.TransientStoreKey {
|
||||
return app.tkeys[storeKey]
|
||||
}
|
||||
|
||||
// GetMemKey returns the MemStoreKey for the provided mem key.
|
||||
//
|
||||
// NOTE: This is solely used for testing purposes.
|
||||
func (app *EthermintApp) GetMemKey(storeKey string) *sdk.MemoryStoreKey {
|
||||
func (app *EthermintApp) GetMemKey(storeKey string) *types3.MemoryStoreKey {
|
||||
return app.memKeys[storeKey]
|
||||
}
|
||||
|
||||
@@ -704,7 +767,6 @@ func (app *EthermintApp) SimulationManager() *module.SimulationManager {
|
||||
// API server.
|
||||
func (app *EthermintApp) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) {
|
||||
clientCtx := apiSvr.ClientCtx
|
||||
rpc.RegisterRoutes(clientCtx, apiSvr.Router)
|
||||
|
||||
evmrest.RegisterTxRoutes(clientCtx, apiSvr.Router)
|
||||
|
||||
@@ -754,7 +816,7 @@ func GetMaccPerms() map[string][]string {
|
||||
|
||||
// initParamsKeeper init params keeper and its subspaces
|
||||
func initParamsKeeper(
|
||||
appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey sdk.StoreKey) paramskeeper.Keeper {
|
||||
appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey types3.StoreKey) paramskeeper.Keeper {
|
||||
paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey)
|
||||
|
||||
// SDK subspaces
|
||||
@@ -764,7 +826,7 @@ func initParamsKeeper(
|
||||
paramsKeeper.Subspace(minttypes.ModuleName)
|
||||
paramsKeeper.Subspace(distrtypes.ModuleName)
|
||||
paramsKeeper.Subspace(slashingtypes.ModuleName)
|
||||
paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable())
|
||||
paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govv1beta2.ParamKeyTable())
|
||||
paramsKeeper.Subspace(crisistypes.ModuleName)
|
||||
paramsKeeper.Subspace(ibctransfertypes.ModuleName)
|
||||
paramsKeeper.Subspace(ibchost.ModuleName)
|
||||
|
||||
+13
-5
@@ -2,23 +2,27 @@ package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/db/memdb"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/tharsis/ethermint/encoding"
|
||||
)
|
||||
|
||||
func TestEthermintAppExport(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
app := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
db := memdb.NewDB()
|
||||
logger, err := log.NewDefaultLogger("plain", "info", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
|
||||
genesisState := NewDefaultGenesisState()
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
@@ -35,7 +39,11 @@ 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, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
logger, err = log.NewDefaultLogger("plain", "info", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
app2 := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
_, err = app2.ExportAppStateAndValidators(false, []string{})
|
||||
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
||||
}
|
||||
|
||||
@@ -2,19 +2,18 @@ package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/db/memdb"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
"github.com/tharsis/ethermint/encoding"
|
||||
)
|
||||
|
||||
func BenchmarkEthermintApp_ExportAppStateAndValidators(b *testing.B) {
|
||||
db := dbm.NewMemDB()
|
||||
app := NewEthermintApp(log.NewTMLogger(io.Discard), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
db := memdb.NewDB()
|
||||
app := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
|
||||
genesisState := NewDefaultGenesisState()
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
@@ -36,7 +35,7 @@ func BenchmarkEthermintApp_ExportAppStateAndValidators(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Making a new app object with the db, so that initchain hasn't been called
|
||||
app2 := NewEthermintApp(log.NewTMLogger(log.NewSyncWriter(io.Discard)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
app2 := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
if _, err := app2.ExportAppStateAndValidators(false, []string{}); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ import (
|
||||
// NewDefaultGenesisState generates the default state for the application.
|
||||
func NewDefaultGenesisState() simapp.GenesisState {
|
||||
encCfg := encoding.MakeConfig(ModuleBasics)
|
||||
return ModuleBasics.DefaultGenesis(encCfg.Marshaler)
|
||||
return ModuleBasics.DefaultGenesis(encCfg.Codec)
|
||||
}
|
||||
|
||||
// ExportAppStateAndValidators exports the state of the application for a genesis
|
||||
|
||||
+7
-6
@@ -2,10 +2,12 @@ package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/db/memdb"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/tharsis/ethermint/encoding"
|
||||
|
||||
@@ -13,13 +15,12 @@ import (
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
)
|
||||
|
||||
// DefaultConsensusParams defines the default Tendermint consensus params used in
|
||||
// EthermintApp testing.
|
||||
var DefaultConsensusParams = &abci.ConsensusParams{
|
||||
Block: &abci.BlockParams{
|
||||
var DefaultConsensusParams = &tmproto.ConsensusParams{
|
||||
Block: &tmproto.BlockParams{
|
||||
MaxBytes: 200000,
|
||||
MaxGas: -1, // no limit
|
||||
},
|
||||
@@ -37,7 +38,7 @@ var DefaultConsensusParams = &abci.ConsensusParams{
|
||||
|
||||
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
|
||||
func Setup(isCheckTx bool) *EthermintApp {
|
||||
db := dbm.NewMemDB()
|
||||
db := memdb.NewDB()
|
||||
app := NewEthermintApp(log.NewNopLogger(), db, nil, true, map[int64]bool{}, DefaultNodeHome, 5, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
|
||||
if !isCheckTx {
|
||||
// init chain must be called to stop deliverState from being nil
|
||||
|
||||
@@ -29,7 +29,6 @@ require (
|
||||
github.com/rs/zerolog v1.25.0
|
||||
github.com/spf13/cast v1.4.1
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.8.1
|
||||
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969
|
||||
github.com/stretchr/testify v1.7.0
|
||||
@@ -53,14 +52,10 @@ require (
|
||||
github.com/99designs/keyring v1.1.6 // indirect
|
||||
github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d // indirect
|
||||
github.com/DataDog/zstd v1.4.8 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.5.7 // indirect
|
||||
github.com/Workiva/go-datastructures v1.0.52 // indirect
|
||||
github.com/agnivade/levenshtein v1.1.0 // indirect
|
||||
github.com/aokoli/goutils v1.1.1 // indirect
|
||||
github.com/armon/go-metrics v0.3.9 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
@@ -81,7 +76,6 @@ require (
|
||||
github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect
|
||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||
github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||
@@ -106,9 +100,7 @@ require (
|
||||
github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 // indirect
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.1.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/ipfs/go-block-format v0.0.2 // indirect
|
||||
github.com/ipfs/go-cid v0.0.3 // indirect
|
||||
@@ -127,13 +119,11 @@ require (
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
|
||||
github.com/minio/highwayhash v1.0.1 // indirect
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||
github.com/mr-tron/base58 v1.1.2 // indirect
|
||||
github.com/mtibben/percent v0.2.1 // indirect
|
||||
github.com/multiformats/go-base32 v0.0.3 // indirect
|
||||
github.com/multiformats/go-multibase v0.0.1 // indirect
|
||||
github.com/mwitkow/go-proto-validators v0.3.2 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
|
||||
@@ -144,7 +134,6 @@ require (
|
||||
github.com/prometheus/common v0.29.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/prometheus/tsdb v0.7.1 // indirect
|
||||
github.com/pseudomuto/protoc-gen-doc v1.5.0 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
|
||||
github.com/rjeczalik/notify v0.9.1 // indirect
|
||||
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect
|
||||
@@ -152,6 +141,7 @@ require (
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect
|
||||
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
|
||||
@@ -177,3 +167,5 @@ replace google.golang.org/grpc => google.golang.org/grpc v1.33.2
|
||||
replace github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
|
||||
|
||||
replace github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76
|
||||
|
||||
replace github.com/cosmos/cosmos-sdk => github.com/vulcanize/cosmos-sdk v0.45.0-smt-alpha
|
||||
|
||||
@@ -73,14 +73,6 @@ github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t
|
||||
github.com/DataDog/zstd v1.4.8 h1:Rpmta4xZ/MgZnriKNd24iZMhGpP5dvUcs/uqfBapKZY=
|
||||
github.com/DataDog/zstd v1.4.8/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
|
||||
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/Masterminds/sprig v2.15.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
|
||||
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
@@ -119,9 +111,6 @@ github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2uc
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
|
||||
github.com/aokoli/goutils v1.1.1 h1:/hA+Ywo3AxoDZY5ZMnkiEkUvkK4BPp927ax110KCqqg=
|
||||
github.com/aokoli/goutils v1.1.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
|
||||
github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0=
|
||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||
@@ -262,7 +251,6 @@ github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2
|
||||
github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU=
|
||||
github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U=
|
||||
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@@ -312,9 +300,6 @@ github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25 h1:2vLKys4RBU4
|
||||
github.com/enigmampc/btcutil v1.0.3-0.20200723161021-e2fb6adb2a25/go.mod h1:hTr8+TLQmkUkgcuh3mcr5fjrT9c64ZzsBCdCEC6UppY=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.1 h1:4CF52PCseTFt4bE+Yk3dIpdVi7XWuPVMhPtm4FaIJPM=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ=
|
||||
github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM=
|
||||
github.com/ethereum/go-ethereum v1.10.1/go.mod h1:E5e/zvdfUVr91JZ0AwjyuJM3x+no51zZJRz61orLLSk=
|
||||
github.com/ethereum/go-ethereum v1.10.3 h1:SEYOYARvbWnoDl1hOSks3ZJQpRiiRJe8ubaQGJQwq0s=
|
||||
@@ -476,7 +461,6 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/protobuf v3.14.0+incompatible/go.mod h1:lUQ9D1ePzbH2PrIS7ob/bjm9HXyH5WHB0Akwh7URreM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -569,21 +553,14 @@ github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iU
|
||||
github.com/holiman/uint256 v1.1.1 h1:4JywC80b+/hSfljFlEBLHrrh+CIONLDz9NuFl0af4Mw=
|
||||
github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
|
||||
github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
|
||||
github.com/huin/goupnp v1.0.1-0.20200620063722-49508fba0031/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo=
|
||||
github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88 h1:bcAj8KroPf552TScjFPIakjH2/tdIrIH8F+cc4v4SRo=
|
||||
github.com/huin/goupnp v1.0.1-0.20210310174557-0ca763054c88/go.mod h1:nNs7wvRfN1eKaMknBydLNQU6146XQim8t4h+q90biWo=
|
||||
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
|
||||
github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.4/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/improbable-eng/grpc-web v0.14.0/go.mod h1:6hRR09jOEG81ADP5wCQju1z71g6OL4eEvELdran/3cs=
|
||||
github.com/improbable-eng/grpc-web v0.14.1 h1:NrN4PY71A6tAz2sKDvC5JCauENWp0ykG8Oq1H3cpFvw=
|
||||
github.com/improbable-eng/grpc-web v0.14.1/go.mod h1:zEjGHa8DAlkoOXmswrNvhUGEYQA9UI7DhrGeHR1DMGU=
|
||||
@@ -698,7 +675,6 @@ github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-b
|
||||
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
|
||||
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77/go.mod h1:5ELEyG+X8f+meRWHuqUOewBOhvHkl7M76pdGEansxW4=
|
||||
github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||
@@ -741,8 +717,6 @@ github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771 h1:MHkK1uRtFbVqvAgvWxafZe54+5uBxLluGylDiKgdhwo=
|
||||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
@@ -754,8 +728,6 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
|
||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
@@ -780,9 +752,6 @@ github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpK
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-proto-validators v0.0.0-20180403085117-0950a7990007/go.mod h1:m2XC9Qq0AlmmVksL6FktJCdTYyLk7V3fKyp0sl1yWQo=
|
||||
github.com/mwitkow/go-proto-validators v0.3.2 h1:qRlmpTzm2pstMKKzTdvwPCF5QfBNURSlAgN/R+qbKos=
|
||||
github.com/mwitkow/go-proto-validators v0.3.2/go.mod h1:ej0Qp0qMgHN/KtDyUt+Q1/tA7a5VarXUOUxD+oeD30w=
|
||||
github.com/mwitkow/grpc-proxy v0.0.0-20181017164139-0f1106ef9c76/go.mod h1:x5OoJHDHqxHS801UIuhqGl6QdSAEJvtausosHSdazIo=
|
||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
|
||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
|
||||
@@ -879,7 +848,6 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
||||
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 h1:bzMe+2coZJYHnhGgVlcQKuRy4FSny4ds8dLQjw5P1XE=
|
||||
@@ -930,10 +898,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
||||
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/pseudomuto/protoc-gen-doc v1.5.0 h1:pHZp0MEiT68jrZV8js8BS7E9ZEnlSLegoQbbtXj5lfo=
|
||||
github.com/pseudomuto/protoc-gen-doc v1.5.0/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg=
|
||||
github.com/pseudomuto/protokit v0.2.0 h1:hlnBDcy3YEDXH7kc9gV+NLaN0cDzhDvD1s7Y6FZ8RpM=
|
||||
github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q=
|
||||
github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ=
|
||||
github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
@@ -1002,8 +966,6 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
@@ -1043,7 +1005,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
@@ -1166,7 +1127,6 @@ go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -1312,7 +1272,6 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -1535,7 +1494,6 @@ google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -1584,8 +1542,6 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20211005153810-c76a74d43a8e h1:Im71rbA1N3CbIag/PumYhQcNR8bLNmuOtRIyOnnLsT8=
|
||||
google.golang.org/genproto v0.0.0-20211005153810-c76a74d43a8e/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4 h1:NBxB1XxiWpGqkPUiJ9PoBXkHV5A9+GohMOA+EmWoPbU=
|
||||
google.golang.org/genproto v0.0.0-20211013025323-ce878158c4d4/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
# Testnet
|
||||
|
||||
## Setup local ethermint multi node testnet
|
||||
|
||||
```shell
|
||||
$ bash multinode_testnet.sh
|
||||
```
|
||||
@@ -0,0 +1,201 @@
|
||||
# Instructions to Run Full Node
|
||||
|
||||
Hardware
|
||||
---
|
||||
|
||||
#### Supported
|
||||
|
||||
- **Operating System (OS):** Ubuntu 20.04
|
||||
- **CPU:** 1 core
|
||||
- **RAM:** 2GB
|
||||
- **Storage:** 25GB SSD
|
||||
|
||||
#### Recommended
|
||||
|
||||
- **Operating System (OS):** Ubuntu 20.04
|
||||
- **CPU:** 2 core
|
||||
- **RAM:** 4GB
|
||||
- **Storage:** 50GB SSD
|
||||
|
||||
# A) Setup
|
||||
|
||||
## 1) Install Golang (go)
|
||||
|
||||
1.1) Remove any existing installation of `go`
|
||||
|
||||
```
|
||||
sudo rm -rf /usr/local/go
|
||||
```
|
||||
|
||||
1.2) Install latest/required Go version (installing `go1.17.2`)
|
||||
|
||||
```
|
||||
curl https://golang.org/dl/go1.17.2.linux-amd64.tar.gz
|
||||
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.2.linux-amd64.tar.gz
|
||||
```
|
||||
|
||||
1.3) Update env variables to include `go`
|
||||
|
||||
```
|
||||
cat <<'EOF' >>$HOME/.profile
|
||||
export GOROOT=/usr/local/go
|
||||
export GOPATH=$HOME/go
|
||||
export GO111MODULE=on
|
||||
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
|
||||
EOF
|
||||
|
||||
source $HOME/.profile
|
||||
```
|
||||
|
||||
1.4) Check the version of go installed
|
||||
|
||||
```
|
||||
go version
|
||||
```
|
||||
|
||||
### 2) Install required software packages
|
||||
|
||||
```
|
||||
sudo apt-get install git curl build-essential make jq -y
|
||||
```
|
||||
|
||||
### 3) Install `ethermint`
|
||||
|
||||
```
|
||||
git clone https://github.com/vulcanize/ethermint.git
|
||||
cd ethermint
|
||||
git fetch --all
|
||||
git checkout v0.1.0-dev
|
||||
make install
|
||||
```
|
||||
|
||||
### 4) Verify your installation
|
||||
|
||||
```
|
||||
ethermintd version --long
|
||||
```
|
||||
|
||||
On running the above command, you should see a similar response like this. Make sure that the *version* and *commit
|
||||
hash* are accurate
|
||||
|
||||
```
|
||||
name: ethermint
|
||||
server_name: ethermintd
|
||||
```
|
||||
|
||||
### 5) Initialize Node
|
||||
|
||||
**Not required if you have already initialized before**
|
||||
|
||||
```
|
||||
ethermintd init <your-node-moniker> --chain-id ethermint_81337-1
|
||||
```
|
||||
|
||||
On running the above command, node will be initialized with default configuration. (config files will be saved in node's
|
||||
default home directory (~/.ethermintd/config)
|
||||
|
||||
NOTE: Backup node and validator keys . You will need to use these keys at a later point in time.
|
||||
|
||||
---
|
||||
|
||||
# B) Starting Node
|
||||
|
||||
## 1) Download Final Genesis
|
||||
|
||||
Use `curl` to download the genesis file
|
||||
**Replace your **genesis** file with published genesis file**
|
||||
|
||||
```shell
|
||||
curl http://167.172.173.94:26657/genesis | jq .result.genesis > ~/.ethermintd/config/genesis.json
|
||||
```
|
||||
|
||||
Verify sha256 hash of genesis file with the below command
|
||||
|
||||
```
|
||||
jq -S -c -M '' ~/.ethermintd/config/genesis.json | shasum -a 256
|
||||
```
|
||||
|
||||
genesis sha256 hash should be
|
||||
|
||||
```
|
||||
4e5b68b5652a608c44c33e669c84ac179d9c0e301f958b5448f037a53c5cbb4e
|
||||
```
|
||||
|
||||
## 2) Update Peers & Seeds in config.toml
|
||||
|
||||
```
|
||||
peers="5ad2e6c35f2c84ff3ee31d89a95b34d92cb6afb1@157.230.101.237:26656,defc95b08547b6ef254723ad9621967a7e819020@161.35.223.44:26656"
|
||||
sed -i.bak -e "s/^persistent_peers *=.*/persistent_peers = \"$peers\"/" ~/.ethermintd/config/config.toml
|
||||
```
|
||||
|
||||
## 3) Start the Full Node
|
||||
|
||||
#### 3.1) Start node as `systemctl` service
|
||||
|
||||
3.1.1) Create the service file
|
||||
|
||||
```
|
||||
sudo tee /etc/systemd/system/ethermintd.service > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=EthermintD Daemon
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User=$USER
|
||||
ExecStart=$(which ethermintd) start --gql-playground --gql-server
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
LimitNOFILE=65535
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
```
|
||||
|
||||
3.1.2) Load service and start
|
||||
|
||||
```
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable ethermintd
|
||||
sudo systemctl start ethermintd
|
||||
|
||||
```
|
||||
|
||||
3.1.3) Check status of service
|
||||
```
|
||||
|
||||
sudo systemctl status ethermintd
|
||||
|
||||
```
|
||||
|
||||
`NOTE:`
|
||||
A helpful command here is `journalctl` that can be used to:
|
||||
|
||||
a) check logs
|
||||
```
|
||||
|
||||
journalctl -u ethermintd
|
||||
|
||||
```
|
||||
|
||||
b) most recent logs
|
||||
```
|
||||
|
||||
journalctl -xeu ethermintd
|
||||
|
||||
```
|
||||
|
||||
c) logs from previous day
|
||||
```
|
||||
|
||||
journalctl --since "1 day ago" -u ethermintd
|
||||
|
||||
```
|
||||
|
||||
d) Check logs with follow flag
|
||||
```
|
||||
|
||||
journalctl -f -u ethermintd
|
||||
|
||||
```
|
||||
@@ -0,0 +1,231 @@
|
||||
# Setting up a Genesis Validator for Vulcanize Ethermint Testnet (ethermint_9000-1)
|
||||
|
||||
Hardware
|
||||
---
|
||||
|
||||
#### Supported
|
||||
|
||||
- **Operating System (OS):** Ubuntu 20.04
|
||||
- **CPU:** 1 core
|
||||
- **RAM:** 2GB
|
||||
- **Storage:** 25GB SSD
|
||||
|
||||
#### Recommended
|
||||
|
||||
- **Operating System (OS):** Ubuntu 20.04
|
||||
- **CPU:** 2 core
|
||||
- **RAM:** 4GB
|
||||
- **Storage:** 50GB SSD
|
||||
|
||||
# A) Setup
|
||||
|
||||
## 1) Install Golang (go)
|
||||
|
||||
1.1) Remove any existing installation of `go`
|
||||
|
||||
```
|
||||
sudo rm -rf /usr/local/go
|
||||
```
|
||||
|
||||
1.2) Install latest/required Go version (installing `go1.17.2`)
|
||||
|
||||
```
|
||||
curl -O https://golang.org/dl/go1.17.2.linux-amd64.tar.gz
|
||||
sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.17.2.linux-amd64.tar.gz
|
||||
```
|
||||
|
||||
1.3) Update env variables to include `go`
|
||||
|
||||
```
|
||||
cat <<'EOF' >>$HOME/.profile
|
||||
export GOROOT=/usr/local/go
|
||||
export GOPATH=$HOME/go
|
||||
export GO111MODULE=on
|
||||
export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin
|
||||
EOF
|
||||
|
||||
source $HOME/.profile
|
||||
```
|
||||
|
||||
1.4) Check the version of go installed
|
||||
|
||||
```
|
||||
go version
|
||||
```
|
||||
|
||||
### 2) Install required software packages
|
||||
|
||||
```
|
||||
sudo apt-get update && sudo apt-get install git curl build-essential make jq -y
|
||||
```
|
||||
|
||||
### 3) Install `ethermint`
|
||||
|
||||
```
|
||||
git clone https://github.com/vulcanize/ethermint.git
|
||||
cd ethermint
|
||||
git fetch --all
|
||||
git checkout v0.1.0-dev
|
||||
make install
|
||||
```
|
||||
|
||||
### 4) Verify your installation
|
||||
|
||||
```
|
||||
ethermintd version --long
|
||||
```
|
||||
|
||||
On running the above command, you should see a similar response like this. Make sure that the *version* and *commit
|
||||
hash* are accurate
|
||||
|
||||
```
|
||||
name: ethermint
|
||||
server_name: ethermintd
|
||||
```
|
||||
|
||||
### 5) Initialize Node
|
||||
|
||||
**Not required if you have already initialized before**
|
||||
|
||||
```
|
||||
ethermintd init <your-node-moniker> --chain-id ethermint_81337-1
|
||||
```
|
||||
|
||||
On running the above command, node will be initialized with default configuration. (config files will be saved in node's
|
||||
default home directory (~/.ethermintd/config)
|
||||
|
||||
NOTE: Backup node and validator keys. You will need to use these keys at a later point in time.
|
||||
|
||||
---
|
||||
|
||||
## 6) Create Account keys
|
||||
|
||||
if you have participated in previous testnet and have mnemonic phrase, use below command to recover your account
|
||||
|
||||
```
|
||||
ethermintd keys add <key-name> --recover
|
||||
```
|
||||
|
||||
to create new account
|
||||
|
||||
```
|
||||
ethermintd keys add <key-name>
|
||||
```
|
||||
|
||||
NOTE: Save `mnemonic` and related account details (public key). You will need to use the need mnemonic/private key to
|
||||
recover accounts at a later point in time.
|
||||
|
||||
## 7) Add Genesis Account
|
||||
|
||||
```
|
||||
ethermintd add-genesis-account <key-name> 4500000000000000agnt --keyring-backend os
|
||||
```
|
||||
|
||||
## 8) Create Your `gentx`
|
||||
|
||||
```
|
||||
ethermintd gentx <key-name> 4500000000000000agnt \
|
||||
--pubkey=$(ethermintd tendermint show-validator) \
|
||||
--chain-id="ethermint_81337-1" \
|
||||
--moniker="my-moniker" \
|
||||
--website="https://yourweb.site" \
|
||||
--details="description of my validator" \
|
||||
--commission-rate="0.10" \
|
||||
--commission-max-rate="0.20" \
|
||||
--commission-max-change-rate="0.01" \
|
||||
--min-self-delegation="1"
|
||||
```
|
||||
|
||||
Note:
|
||||
|
||||
- `<key-name>` and `chain-id` are required. other flags are optional
|
||||
- Don't change amount value while creating your gentx
|
||||
- Genesis transaction file will be saved in `~/.ethermintd/config/gentx` folder
|
||||
|
||||
## 9) Submit Your gentx
|
||||
|
||||
Submit your `gentx` file to the [testnets]() in the format of
|
||||
`<validator-moniker>-gentx.json`
|
||||
|
||||
NOTE: (Do NOT use space in the file name)
|
||||
|
||||
To submit the gentx file, follow the below process:
|
||||
|
||||
- Fork the [testnets]() repository
|
||||
- Upload your gentx file in `ethermint_81337-1/config/gentxs` folder
|
||||
- Submit Pull Request to [testnets]() with name `ADD <your-moniker> gentx`
|
||||
|
||||
---
|
||||
|
||||
**Execute below instructions only after publishing of final genesis file**
|
||||
|
||||
genesis file will be published to [testnets/ethermint_9000-1]()
|
||||
|
||||
# B) Starting the validator
|
||||
|
||||
TBU
|
||||
|
||||
## 3) Start the Node
|
||||
|
||||
#### 3.1) Start node as `systemctl` service
|
||||
|
||||
3.1.1) Create the service file Note: this step is not required if you did setup before
|
||||
|
||||
```
|
||||
sudo tee /etc/systemd/system/ethermintd.service > /dev/null <<EOF
|
||||
[Unit]
|
||||
Description=ethermintd Daemon
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
User=$USER
|
||||
ExecStart=$(which ethermintd) start
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
LimitNOFILE=65535
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
```
|
||||
|
||||
3.1.2) Load service and start
|
||||
|
||||
```
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable ethermintd
|
||||
sudo systemctl start ethermintd
|
||||
```
|
||||
|
||||
3.1.3) Check status of service
|
||||
|
||||
```
|
||||
sudo systemctl status ethermintd
|
||||
```
|
||||
|
||||
`NOTE:`
|
||||
A helpful command here is `journalctl` that can be used to:
|
||||
|
||||
a) check logs
|
||||
|
||||
```
|
||||
journalctl -u ethermintd
|
||||
```
|
||||
|
||||
b) most recent logs
|
||||
|
||||
```
|
||||
journalctl -xeu ethermintd
|
||||
```
|
||||
|
||||
c) logs from previous day
|
||||
|
||||
```
|
||||
journalctl --since "1 day ago" -u ethermintd
|
||||
```
|
||||
|
||||
d) Check logs with follow flag
|
||||
|
||||
```
|
||||
journalctl -f -u ethermintd
|
||||
```
|
||||
@@ -0,0 +1,232 @@
|
||||
#/bin/sh
|
||||
|
||||
# clean the existed chain
|
||||
rm -rf ~/.testethermint*
|
||||
|
||||
echo "Installing the require tools "
|
||||
sudo apt-get install git curl build-essential make nohup jq -y
|
||||
echo "Done Installing the tools"
|
||||
|
||||
command_exists() {
|
||||
type "$1" &>/dev/null
|
||||
}
|
||||
|
||||
if command_exists go; then
|
||||
echo "Golang is already installed"
|
||||
else
|
||||
echo "Installing golang dependencies"
|
||||
wget https://golang.org/dl/go1.17.2.linux-amd64.tar.gz
|
||||
rm -rf /usr/local/go && tar -C /usr/local -xzf go1.17.2.linux-amd64.tar.gz
|
||||
|
||||
echo "Updating the profile"
|
||||
export GOPATH=$HOME/go
|
||||
export GOROOT=/usr/local/go
|
||||
export GOBIN=$GOPATH/bin
|
||||
export PATH=$PATH:/usr/local/go/bin:$GOBIN
|
||||
|
||||
echo "" >>~/.profile
|
||||
echo 'export GOPATH=$HOME/go' >>~/.profile
|
||||
echo 'export GOROOT=/usr/local/go' >>~/.profile
|
||||
echo 'export GOBIN=$GOPATH/bin' >>~/.profile
|
||||
echo 'export PATH=$PATH:/usr/local/go/bin:$GOBIN' >>~/.profile
|
||||
|
||||
source ~/.profile
|
||||
mkdir -p "$GOBIN"
|
||||
mkdir -p $GOPATH/src/github.com
|
||||
go version
|
||||
fi
|
||||
|
||||
# chain env variables
|
||||
export DAEMON_HOME=~/.testethermint
|
||||
export CHAINID=ethermint_9000-1
|
||||
export DENOM=uether
|
||||
export GH_URL=https://github.com/vulcanize/ethermint.git
|
||||
export CHAIN_VERSION=dev
|
||||
export DAEMON=ethermintd
|
||||
|
||||
display_usage() {
|
||||
printf "** Please check the exported values:: **\n Daemon : $DAEMON\n Denom : $DENOM\n ChainID : $CHAINID\n DaemonHome : $DAEMON_HOME\n \n Github URL : $GH_URL\n Chain Version : $CHAIN_VERSION\n"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -z $DAEMON ] || [ -z $DENOM ] || [ -z $CHAINID ] || [ -z $DAEMON_HOME ] || [ -z $GH_URL ] || [ -z $CHAIN_VERSION ]; then
|
||||
display_usage
|
||||
fi
|
||||
|
||||
echo "--------- Install $DAEMON ---------"
|
||||
git clone -b $CHAIN_VERSION --single-branch $GH_URL && cd $(basename $_ .git)
|
||||
git fetch && git checkout $CHAIN_VERSION
|
||||
make install
|
||||
|
||||
cd $HOME
|
||||
|
||||
# check version
|
||||
$DAEMON version --long
|
||||
|
||||
#echo "----------Create test keys-----------"
|
||||
|
||||
export DAEMON_HOME_1=$DAEMON_HOME-1
|
||||
export DAEMON_HOME_2=$DAEMON_HOME-2
|
||||
export DAEMON_HOME_3=$DAEMON_HOME-3
|
||||
export DAEMON_HOME_4=$DAEMON_HOME-4
|
||||
|
||||
printf "DAEMON_HOME_1=$DAEMON_HOME_1\nDAEMON_HOME_2=$DAEMON_HOME_2\nDAEMON_HOME_3=$DAEMON_HOME_3\nDAEMON_HOME_4=$DAEMON_HOME_4\n"
|
||||
|
||||
rm -rf $DAEMON_HOME*
|
||||
|
||||
echo "-----Create daemon home directories if not exist------"
|
||||
|
||||
mkdir -p "$DAEMON_HOME_1"
|
||||
mkdir -p "$DAEMON_HOME_2"
|
||||
mkdir -p "$DAEMON_HOME_3"
|
||||
mkdir -p "$DAEMON_HOME_4"
|
||||
|
||||
echo "--------Start initializing the chain ($CHAINID)---------"
|
||||
|
||||
$DAEMON init --chain-id $CHAINID $DAEMON_HOME_1 --home $DAEMON_HOME_1 --keyring-backend test
|
||||
$DAEMON init --chain-id $CHAINID $DAEMON_HOME_2 --home $DAEMON_HOME_2 --keyring-backend test
|
||||
$DAEMON init --chain-id $CHAINID $DAEMON_HOME_3 --home $DAEMON_HOME_3 --keyring-backend test
|
||||
$DAEMON init --chain-id $CHAINID $DAEMON_HOME_4 --home $DAEMON_HOME_4 --keyring-backend test
|
||||
|
||||
echo "---------Creating four keys-------------"
|
||||
|
||||
$DAEMON keys add validator1 --home $DAEMON_HOME_1 --keyring-backend test
|
||||
$DAEMON keys add validator2 --home $DAEMON_HOME_2 --keyring-backend test
|
||||
$DAEMON keys add validator3 --home $DAEMON_HOME_3 --keyring-backend test
|
||||
$DAEMON keys add validator4 --home $DAEMON_HOME_4 --keyring-backend test
|
||||
|
||||
echo "----------Genesis creation---------"
|
||||
|
||||
$DAEMON --home $DAEMON_HOME_1 add-genesis-account validator1 1000000000000$DENOM --keyring-backend test
|
||||
$DAEMON --home $DAEMON_HOME_2 add-genesis-account validator2 1000000000000$DENOM --keyring-backend test
|
||||
$DAEMON --home $DAEMON_HOME_3 add-genesis-account validator3 1000000000000$DENOM --keyring-backend test
|
||||
$DAEMON --home $DAEMON_HOME_4 add-genesis-account validator4 1000000000000$DENOM --keyring-backend test
|
||||
$DAEMON --home $DAEMON_HOME_1 add-genesis-account $($DAEMON keys show validator2 -a --home $DAEMON_HOME_2 --keyring-backend test) 1000000000000$DENOM
|
||||
$DAEMON --home $DAEMON_HOME_1 add-genesis-account $($DAEMON keys show validator3 -a --home $DAEMON_HOME_3 --keyring-backend test) 1000000000000$DENOM
|
||||
$DAEMON --home $DAEMON_HOME_1 add-genesis-account $($DAEMON keys show validator4 -a --home $DAEMON_HOME_4 --keyring-backend test) 1000000000000$DENOM
|
||||
|
||||
echo "--------Gentx--------"
|
||||
|
||||
$DAEMON gentx validator1 90000000000$DENOM --chain-id $CHAINID --keyring-backend test --home $DAEMON_HOME_1
|
||||
$DAEMON gentx validator2 90000000000$DENOM --chain-id $CHAINID --keyring-backend test --home $DAEMON_HOME_2
|
||||
$DAEMON gentx validator3 90000000000$DENOM --chain-id $CHAINID --keyring-backend test --home $DAEMON_HOME_3
|
||||
$DAEMON gentx validator4 90000000000$DENOM --chain-id $CHAINID --keyring-backend test --home $DAEMON_HOME_4
|
||||
|
||||
echo "---------Copy all the genesis to $DAEMON_HOME_1----------"
|
||||
|
||||
cp $DAEMON_HOME_2/config/gentx/*.json $DAEMON_HOME_1/config/gentx/
|
||||
cp $DAEMON_HOME_3/config/gentx/*.json $DAEMON_HOME_1/config/gentx/
|
||||
cp $DAEMON_HOME_4/config/gentx/*.json $DAEMON_HOME_1/config/gentx/
|
||||
|
||||
echo "----------collect-gentxs------------"
|
||||
|
||||
$DAEMON collect-gentxs --home $DAEMON_HOME_1
|
||||
|
||||
echo "---------Updating $DAEMON_HOME_1 genesis.json ------------"
|
||||
|
||||
sed -i "s/172800000000000/600000000000/g" $DAEMON_HOME_1/config/genesis.json
|
||||
sed -i "s/172800s/600s/g" $DAEMON_HOME_1/config/genesis.json
|
||||
sed -i "s/stake/$DENOM/g" $DAEMON_HOME_1/config/genesis.json
|
||||
|
||||
echo "---------Distribute genesis.json of $DAEMON_HOME_1 to remaining nodes-------"
|
||||
|
||||
cp $DAEMON_HOME_1/config/genesis.json $DAEMON_HOME_2/config/
|
||||
cp $DAEMON_HOME_1/config/genesis.json $DAEMON_HOME_3/config/
|
||||
cp $DAEMON_HOME_1/config/genesis.json $DAEMON_HOME_4/config/
|
||||
|
||||
echo "---------Getting public IP address-----------"
|
||||
|
||||
IP="127.0.0.1"
|
||||
echo "Public IP address: ${IP}"
|
||||
|
||||
echo "----------Update node-id of $DAEMON_HOME_1 in remaining nodes---------"
|
||||
nodeID=$("${DAEMON}" tendermint show-node-id --home $DAEMON_HOME_1)
|
||||
echo $nodeID
|
||||
PERSISTENT_PEERS="$nodeID@$IP:16656"
|
||||
echo "PERSISTENT_PEERS : $PERSISTENT_PEERS"
|
||||
|
||||
echo "----------Updating $DAEMON_HOME_1 chain config-----------"
|
||||
|
||||
sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:16657#g' $DAEMON_HOME_1/config/config.toml
|
||||
sed -i 's#tcp://0.0.0.0:26656#tcp://0.0.0.0:16656#g' $DAEMON_HOME_1/config/config.toml
|
||||
sed -i '/persistent_peers =/c\persistent_peers = "'""'"' $DAEMON_HOME_1/config/config.toml
|
||||
sed -i '/max_num_inbound_peers =/c\max_num_inbound_peers = 140' $DAEMON_HOME_1/config/config.toml
|
||||
sed -i '/max_num_outbound_peers =/c\max_num_outbound_peers = 110' $DAEMON_HOME_1/config/config.toml
|
||||
sed -i '/pprof_laddr =/c\# pprof_laddr = "localhost:6060"' $DAEMON_HOME_1/config/config.toml
|
||||
sed -i '/allow_duplicate_ip =/c\allow_duplicate_ip = true' $DAEMON_HOME_1/config/config.toml
|
||||
|
||||
sed -i 's#0.0.0.0:9090#0.0.0.0:1090#g' $DAEMON_HOME_1/config/app.toml
|
||||
sed -i 's#0.0.0.0:9091#0.0.0.0:1091#g' $DAEMON_HOME_1/config/app.toml
|
||||
|
||||
sed -i 's#0.0.0.0:8545#0.0.0.0:1545#g' $DAEMON_HOME_1/config/app.toml
|
||||
sed -i 's#0.0.0.0:8546#0.0.0.0:1546#g' $DAEMON_HOME_1/config/app.toml
|
||||
|
||||
echo "----------Updating $DAEMON_HOME_2 chain config-----------"
|
||||
|
||||
sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:26657#g' $DAEMON_HOME_2/config/config.toml
|
||||
sed -i 's#tcp://0.0.0.0:26656#tcp://0.0.0.0:26656#g' $DAEMON_HOME_2/config/config.toml
|
||||
sed -i '/persistent_peers =/c\persistent_peers = "'"$PERSISTENT_PEERS"'"' $DAEMON_HOME_2/config/config.toml
|
||||
sed -i '/max_num_inbound_peers =/c\max_num_inbound_peers = 140' $DAEMON_HOME_2/config/config.toml
|
||||
sed -i '/max_num_outbound_peers =/c\max_num_outbound_peers = 110' $DAEMON_HOME_2/config/config.toml
|
||||
sed -i '/pprof_laddr =/c\# pprof_laddr = "localhost:6060"' $DAEMON_HOME_2/config/config.toml
|
||||
sed -i '/allow_duplicate_ip =/c\allow_duplicate_ip = true' $DAEMON_HOME_2/config/config.toml
|
||||
|
||||
sed -i 's#0.0.0.0:9090#0.0.0.0:2090#g' $DAEMON_HOME_2/config/app.toml
|
||||
sed -i 's#0.0.0.0:9091#0.0.0.0:2091#g' $DAEMON_HOME_2/config/app.toml
|
||||
|
||||
sed -i 's#0.0.0.0:8545#0.0.0.0:2545#g' $DAEMON_HOME_2/config/app.toml
|
||||
sed -i 's#0.0.0.0:8546#0.0.0.0:2546#g' $DAEMON_HOME_2/config/app.toml
|
||||
|
||||
echo "----------Updating $DAEMON_HOME_3 chain config------------"
|
||||
|
||||
sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:36657#g' $DAEMON_HOME_3/config/config.toml
|
||||
sed -i 's#tcp://0.0.0.0:26656#tcp://0.0.0.0:36656#g' $DAEMON_HOME_3/config/config.toml
|
||||
sed -i '/persistent_peers =/c\persistent_peers = "'"$PERSISTENT_PEERS"'"' $DAEMON_HOME_3/config/config.toml
|
||||
sed -i '/max_num_inbound_peers =/c\max_num_inbound_peers = 140' $DAEMON_HOME_3/config/config.toml
|
||||
sed -i '/max_num_outbound_peers =/c\max_num_outbound_peers = 110' $DAEMON_HOME_3/config/config.toml
|
||||
sed -i '/pprof_laddr =/c\# pprof_laddr = "localhost:6060"' $DAEMON_HOME_3/config/config.toml
|
||||
sed -i '/allow_duplicate_ip =/c\allow_duplicate_ip = true' $DAEMON_HOME_3/config/config.toml
|
||||
|
||||
sed -i 's#0.0.0.0:9090#0.0.0.0:3090#g' $DAEMON_HOME_3/config/app.toml
|
||||
sed -i 's#0.0.0.0:9091#0.0.0.0:3091#g' $DAEMON_HOME_3/config/app.toml
|
||||
|
||||
sed -i 's#0.0.0.0:8545#0.0.0.0:3545#g' $DAEMON_HOME_3/config/app.toml
|
||||
sed -i 's#0.0.0.0:8546#0.0.0.0:3546#g' $DAEMON_HOME_3/config/app.toml
|
||||
|
||||
echo "----------Updating $DAEMON_HOME_4 chain config------------"
|
||||
|
||||
sed -i 's#tcp://127.0.0.1:26657#tcp://0.0.0.0:46657#g' $DAEMON_HOME_4/config/config.toml
|
||||
sed -i 's#tcp://0.0.0.0:26656#tcp://0.0.0.0:46656#g' $DAEMON_HOME_4/config/config.toml
|
||||
sed -i '/persistent_peers =/c\persistent_peers = "'"$PERSISTENT_PEERS"'"' $DAEMON_HOME_4/config/config.toml
|
||||
sed -i '/max_num_inbound_peers =/c\max_num_inbound_peers = 140' $DAEMON_HOME_4/config/config.toml
|
||||
sed -i '/max_num_outbound_peers =/c\max_num_outbound_peers = 110' $DAEMON_HOME_4/config/config.toml
|
||||
sed -i '/pprof_laddr =/c\# pprof_laddr = "localhost:6060"' $DAEMON_HOME_4/config/config.toml
|
||||
sed -i '/allow_duplicate_ip =/c\allow_duplicate_ip = true' $DAEMON_HOME_4/config/config.toml
|
||||
|
||||
sed -i 's#0.0.0.0:9090#0.0.0.0:4090#g' $DAEMON_HOME_4/config/app.toml
|
||||
sed -i 's#0.0.0.0:9091#0.0.0.0:4091#g' $DAEMON_HOME_4/config/app.toml
|
||||
|
||||
sed -i 's#0.0.0.0:8545#0.0.0.0:4545#g' $DAEMON_HOME_4/config/app.toml
|
||||
sed -i 's#0.0.0.0:8546#0.0.0.0:4546#g' $DAEMON_HOME_4/config/app.toml
|
||||
|
||||
echo "starting the chains"
|
||||
|
||||
nohup $(which $DAEMON) start --gql-playground --gql-server --home $DAEMON_HOME_1 >$DAEMON_HOME_1.log &
|
||||
sleep 5s
|
||||
echo "Checking $DAEMON_HOME_1 chain status"
|
||||
$DAEMON status --node tcp://localhost:16657
|
||||
|
||||
nohup $(which $DAEMON) start --gql-playground --gql-server --home $DAEMON_HOME_2 >$DAEMON_HOME_2.log &
|
||||
sleep 5s
|
||||
echo "Checking $DAEMON_HOME_2 chain status"
|
||||
$DAEMON status --node tcp://localhost:26657
|
||||
|
||||
nohup $(which $DAEMON) start --gql-playground --gql-server --home $DAEMON_HOME_3 >$DAEMON_HOME_3.log &
|
||||
sleep 5s
|
||||
echo "Checking $DAEMON_HOME_3 chain status"
|
||||
$DAEMON status --node tcp://localhost:36657
|
||||
|
||||
nohup $(which $DAEMON) start --gql-playground --gql-server --home $DAEMON_HOME_4 >$DAEMON_HOME_4.log &
|
||||
sleep 5s
|
||||
echo "Checking $DAEMON_HOME_4 chain status"
|
||||
$DAEMON status --node tcp://localhost:46657
|
||||
@@ -0,0 +1,56 @@
|
||||
### Create Validator Post Genesis
|
||||
|
||||
1. Run Full Node
|
||||
2. Create Account and Get test tokens
|
||||
3. Create Validator
|
||||
|
||||
### 1.Run Full Node
|
||||
|
||||
- Check "[Run Full Node](full-node.md)" section to Run a Full Node
|
||||
|
||||
### 2. Create Account & Get test tokens
|
||||
|
||||
```
|
||||
ethermintd keys add <key-name> --keyring-backend test
|
||||
```
|
||||
|
||||
NOTE: Save `mnemonic` and related account details (public key). You will need to use the need mnemonic/private key to
|
||||
recover accounts at a later point in time.
|
||||
|
||||
##### Get Test tokens from faucet
|
||||
|
||||
- Open this link : http://167.172.173.94:1314/ and paste your account
|
||||
- 1 gnt = 10^18 agnt
|
||||
- Each Transaction you will get 500gnt
|
||||
- Total Tokens 5000gnt for account
|
||||
|
||||
### 3.Create Validator
|
||||
|
||||
- ##### Check full node sync status
|
||||
|
||||
`ethermintd status 2>&1 | jq -r ".SyncInfo"`
|
||||
|
||||
`catching_up: false` means node is completely synced
|
||||
- ##### Create validator
|
||||
|
||||
`Note:` Only execute below transaction after complete sync of your full node
|
||||
|
||||
Please replace `key_name` with your key name and `moniker` also
|
||||
|
||||
```
|
||||
ethermintd tx staking create-validator \
|
||||
--amount=4500000000000000000000agnt \
|
||||
--pubkey=$(ethermintd tendermint show-validator) \
|
||||
--moniker="my-moniker" \
|
||||
--website="https://myweb.site" \
|
||||
--details="description of your validator" \
|
||||
--chain-id="ethermint_81337-1" \
|
||||
--commission-rate="0.10" \
|
||||
--commission-max-rate="0.20" \
|
||||
--commission-max-change-rate="0.01" \
|
||||
--min-self-delegation="1" \
|
||||
--gas="auto" \
|
||||
--gas-adjustment="1.2" \
|
||||
--gas-prices="0.025agnt" \
|
||||
--from=<key_name>
|
||||
```
|
||||
@@ -0,0 +1,58 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
// HandlerOptions are the options required for constructing a default SDK AnteHandler.
|
||||
type HandlerOptions struct {
|
||||
AccountKeeper AccountKeeper
|
||||
BankKeeper types.BankKeeper
|
||||
FeegrantKeeper FeegrantKeeper
|
||||
SignModeHandler authsigning.SignModeHandler
|
||||
SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error
|
||||
}
|
||||
|
||||
// NewAnteHandler returns an AnteHandler that checks and increments sequence
|
||||
// numbers, checks signatures & account numbers, and deducts fees from the first
|
||||
// signer.
|
||||
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
|
||||
if options.AccountKeeper == nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder")
|
||||
}
|
||||
|
||||
if options.BankKeeper == nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder")
|
||||
}
|
||||
|
||||
if options.SignModeHandler == nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
|
||||
}
|
||||
|
||||
var sigGasConsumer = options.SigGasConsumer
|
||||
if sigGasConsumer == nil {
|
||||
sigGasConsumer = DefaultSigVerificationGasConsumer
|
||||
}
|
||||
|
||||
anteDecorators := []sdk.AnteDecorator{
|
||||
NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
|
||||
NewRejectExtensionOptionsDecorator(),
|
||||
NewMempoolFeeDecorator(),
|
||||
NewValidateBasicDecorator(),
|
||||
NewTxTimeoutHeightDecorator(),
|
||||
NewValidateMemoDecorator(options.AccountKeeper),
|
||||
NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
|
||||
NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper),
|
||||
NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
|
||||
NewValidateSigCountDecorator(options.AccountKeeper),
|
||||
NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer),
|
||||
NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
|
||||
NewIncrementSequenceDecorator(options.AccountKeeper),
|
||||
}
|
||||
|
||||
return sdk.ChainAnteDecorators(anteDecorators...), nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,206 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec/legacy"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
)
|
||||
|
||||
// ValidateBasicDecorator will call tx.ValidateBasic and return any non-nil error.
|
||||
// If ValidateBasic passes, decorator calls next AnteHandler in chain. Note,
|
||||
// ValidateBasicDecorator decorator will not get executed on ReCheckTx since it
|
||||
// is not dependent on application state.
|
||||
type ValidateBasicDecorator struct{}
|
||||
|
||||
func NewValidateBasicDecorator() ValidateBasicDecorator {
|
||||
return ValidateBasicDecorator{}
|
||||
}
|
||||
|
||||
func (vbd ValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
// no need to validate basic on recheck tx, call next antehandler
|
||||
if ctx.IsReCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
if err := tx.ValidateBasic(); err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// ValidateMemoDecorator will validate memo given the parameters passed in
|
||||
// If memo is too large decorator returns with error, otherwise call next AnteHandler
|
||||
// CONTRACT: Tx must implement TxWithMemo interface
|
||||
type ValidateMemoDecorator struct {
|
||||
ak AccountKeeper
|
||||
}
|
||||
|
||||
func NewValidateMemoDecorator(ak AccountKeeper) ValidateMemoDecorator {
|
||||
return ValidateMemoDecorator{
|
||||
ak: ak,
|
||||
}
|
||||
}
|
||||
|
||||
func (vmd ValidateMemoDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
memoTx, ok := tx.(sdk.TxWithMemo)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
|
||||
}
|
||||
|
||||
params := vmd.ak.GetParams(ctx)
|
||||
|
||||
memoLength := len(memoTx.GetMemo())
|
||||
if uint64(memoLength) > params.MaxMemoCharacters {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrMemoTooLarge,
|
||||
"maximum number of characters is %d but received %d characters",
|
||||
params.MaxMemoCharacters, memoLength,
|
||||
)
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// ConsumeTxSizeGasDecorator will take in parameters and consume gas proportional
|
||||
// to the size of tx before calling next AnteHandler. Note, the gas costs will be
|
||||
// slightly over estimated due to the fact that any given signing account may need
|
||||
// to be retrieved from state.
|
||||
//
|
||||
// CONTRACT: If simulate=true, then signatures must either be completely filled
|
||||
// in or empty.
|
||||
// CONTRACT: To use this decorator, signatures of transaction must be represented
|
||||
// as legacytx.StdSignature otherwise simulate mode will incorrectly estimate gas cost.
|
||||
type ConsumeTxSizeGasDecorator struct {
|
||||
ak AccountKeeper
|
||||
}
|
||||
|
||||
func NewConsumeGasForTxSizeDecorator(ak AccountKeeper) ConsumeTxSizeGasDecorator {
|
||||
return ConsumeTxSizeGasDecorator{
|
||||
ak: ak,
|
||||
}
|
||||
}
|
||||
|
||||
func (cgts ConsumeTxSizeGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
sigTx, ok := tx.(authsigning.SigVerifiableTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type")
|
||||
}
|
||||
params := cgts.ak.GetParams(ctx)
|
||||
|
||||
ctx.GasMeter().ConsumeGas(params.TxSizeCostPerByte*sdk.Gas(len(ctx.TxBytes())), "txSize")
|
||||
|
||||
// simulate gas cost for signatures in simulate mode
|
||||
if simulate {
|
||||
// in simulate mode, each element should be a nil signature
|
||||
sigs, err := sigTx.GetSignaturesV2()
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
n := len(sigs)
|
||||
|
||||
for i, signer := range sigTx.GetSigners() {
|
||||
// if signature is already filled in, no need to simulate gas cost
|
||||
if i < n && !isIncompleteSignature(sigs[i].Data) {
|
||||
continue
|
||||
}
|
||||
|
||||
var pubkey cryptotypes.PubKey
|
||||
|
||||
acc := cgts.ak.GetAccount(ctx, signer)
|
||||
|
||||
// use placeholder simSecp256k1Pubkey if sig is nil
|
||||
if acc == nil || acc.GetPubKey() == nil {
|
||||
pubkey = simSecp256k1Pubkey
|
||||
} else {
|
||||
pubkey = acc.GetPubKey()
|
||||
}
|
||||
|
||||
// use stdsignature to mock the size of a full signature
|
||||
simSig := legacytx.StdSignature{ //nolint:staticcheck // this will be removed when proto is ready
|
||||
Signature: simSecp256k1Sig[:],
|
||||
PubKey: pubkey,
|
||||
}
|
||||
|
||||
sigBz := legacy.Cdc.MustMarshal(simSig)
|
||||
cost := sdk.Gas(len(sigBz) + 6)
|
||||
|
||||
// If the pubkey is a multi-signature pubkey, then we estimate for the maximum
|
||||
// number of signers.
|
||||
if _, ok := pubkey.(*multisig.LegacyAminoPubKey); ok {
|
||||
cost *= params.TxSigLimit
|
||||
}
|
||||
|
||||
ctx.GasMeter().ConsumeGas(params.TxSizeCostPerByte*cost, "txSize")
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// isIncompleteSignature tests whether SignatureData is fully filled in for simulation purposes
|
||||
func isIncompleteSignature(data signing.SignatureData) bool {
|
||||
if data == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
switch data := data.(type) {
|
||||
case *signing.SingleSignatureData:
|
||||
return len(data.Signature) == 0
|
||||
case *signing.MultiSignatureData:
|
||||
if len(data.Signatures) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, s := range data.Signatures {
|
||||
if isIncompleteSignature(s) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type (
|
||||
// TxTimeoutHeightDecorator defines an AnteHandler decorator that checks for a
|
||||
// tx height timeout.
|
||||
TxTimeoutHeightDecorator struct{}
|
||||
|
||||
// TxWithTimeoutHeight defines the interface a tx must implement in order for
|
||||
// TxHeightTimeoutDecorator to process the tx.
|
||||
TxWithTimeoutHeight interface {
|
||||
sdk.Tx
|
||||
|
||||
GetTimeoutHeight() uint64
|
||||
}
|
||||
)
|
||||
|
||||
// TxTimeoutHeightDecorator defines an AnteHandler decorator that checks for a
|
||||
// tx height timeout.
|
||||
func NewTxTimeoutHeightDecorator() TxTimeoutHeightDecorator {
|
||||
return TxTimeoutHeightDecorator{}
|
||||
}
|
||||
|
||||
// AnteHandle implements an AnteHandler decorator for the TxHeightTimeoutDecorator
|
||||
// type where the current block height is checked against the tx's height timeout.
|
||||
// If a height timeout is provided (non-zero) and is less than the current block
|
||||
// height, then an error is returned.
|
||||
func (txh TxTimeoutHeightDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
timeoutTx, ok := tx.(TxWithTimeoutHeight)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "expected tx to implement TxWithTimeoutHeight")
|
||||
}
|
||||
|
||||
timeoutHeight := timeoutTx.GetTimeoutHeight()
|
||||
if timeoutHeight > 0 && uint64(ctx.BlockHeight()) > timeoutHeight {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrTxTimeoutHeight, "block height: %d, timeout height: %d", ctx.BlockHeight(), timeoutHeight,
|
||||
)
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
)
|
||||
|
||||
func (suite *AnteTestSuite) TestValidateBasic() {
|
||||
suite.SetupTest(true) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
|
||||
// msg and signatures
|
||||
msg := testdata.NewTestMsg(addr1)
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{}, []uint64{}, []uint64{}
|
||||
invalidTx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
vbd := ante.NewValidateBasicDecorator()
|
||||
antehandler := sdk.ChainAnteDecorators(vbd)
|
||||
_, err = antehandler(suite.ctx, invalidTx, false)
|
||||
|
||||
suite.Require().NotNil(err, "Did not error on invalid tx")
|
||||
|
||||
privs, accNums, accSeqs = []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
validTx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
_, err = antehandler(suite.ctx, validTx, false)
|
||||
suite.Require().Nil(err, "ValidateBasicDecorator returned error on valid tx. err: %v", err)
|
||||
|
||||
// test decorator skips on recheck
|
||||
suite.ctx = suite.ctx.WithIsReCheckTx(true)
|
||||
|
||||
// decorator should skip processing invalidTx on recheck and thus return nil-error
|
||||
_, err = antehandler(suite.ctx, invalidTx, false)
|
||||
|
||||
suite.Require().Nil(err, "ValidateBasicDecorator ran on ReCheck")
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestValidateMemo() {
|
||||
suite.SetupTest(true) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
|
||||
// msg and signatures
|
||||
msg := testdata.NewTestMsg(addr1)
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
suite.txBuilder.SetMemo(strings.Repeat("01234567890", 500))
|
||||
invalidTx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// require that long memos get rejected
|
||||
vmd := ante.NewValidateMemoDecorator(suite.app.AccountKeeper)
|
||||
antehandler := sdk.ChainAnteDecorators(vmd)
|
||||
_, err = antehandler(suite.ctx, invalidTx, false)
|
||||
|
||||
suite.Require().NotNil(err, "Did not error on tx with high memo")
|
||||
|
||||
suite.txBuilder.SetMemo(strings.Repeat("01234567890", 10))
|
||||
validTx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// require small memos pass ValidateMemo Decorator
|
||||
_, err = antehandler(suite.ctx, validTx, false)
|
||||
suite.Require().Nil(err, "ValidateBasicDecorator returned error on valid tx. err: %v", err)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestConsumeGasForTxSize() {
|
||||
suite.SetupTest(true) // setup
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
|
||||
// msg and signatures
|
||||
msg := testdata.NewTestMsg(addr1)
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
|
||||
cgtsd := ante.NewConsumeGasForTxSizeDecorator(suite.app.AccountKeeper)
|
||||
antehandler := sdk.ChainAnteDecorators(cgtsd)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
sigV2 signing.SignatureV2
|
||||
}{
|
||||
{"SingleSignatureData", signing.SignatureV2{PubKey: priv1.PubKey()}},
|
||||
{"MultiSignatureData", signing.SignatureV2{PubKey: priv1.PubKey(), Data: multisig.NewMultisig(2)}},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
suite.txBuilder.SetMemo(strings.Repeat("01234567890", 10))
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
txBytes, err := suite.clientCtx.TxConfig.TxJSONEncoder()(tx)
|
||||
suite.Require().Nil(err, "Cannot marshal tx: %v", err)
|
||||
|
||||
params := suite.app.AccountKeeper.GetParams(suite.ctx)
|
||||
expectedGas := sdk.Gas(len(txBytes)) * params.TxSizeCostPerByte
|
||||
|
||||
// Set suite.ctx with TxBytes manually
|
||||
suite.ctx = suite.ctx.WithTxBytes(txBytes)
|
||||
|
||||
// track how much gas is necessary to retrieve parameters
|
||||
beforeGas := suite.ctx.GasMeter().GasConsumed()
|
||||
suite.app.AccountKeeper.GetParams(suite.ctx)
|
||||
afterGas := suite.ctx.GasMeter().GasConsumed()
|
||||
expectedGas += afterGas - beforeGas
|
||||
|
||||
beforeGas = suite.ctx.GasMeter().GasConsumed()
|
||||
suite.ctx, err = antehandler(suite.ctx, tx, false)
|
||||
suite.Require().Nil(err, "ConsumeTxSizeGasDecorator returned error: %v", err)
|
||||
|
||||
// require that decorator consumes expected amount of gas
|
||||
consumedGas := suite.ctx.GasMeter().GasConsumed() - beforeGas
|
||||
suite.Require().Equal(expectedGas, consumedGas, "Decorator did not consume the correct amount of gas")
|
||||
|
||||
// simulation must not underestimate gas of this decorator even with nil signatures
|
||||
txBuilder, err := suite.clientCtx.TxConfig.WrapTxBuilder(tx)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().NoError(txBuilder.SetSignatures(tc.sigV2))
|
||||
tx = txBuilder.GetTx()
|
||||
|
||||
simTxBytes, err := suite.clientCtx.TxConfig.TxJSONEncoder()(tx)
|
||||
suite.Require().Nil(err, "Cannot marshal tx: %v", err)
|
||||
// require that simulated tx is smaller than tx with signatures
|
||||
suite.Require().True(len(simTxBytes) < len(txBytes), "simulated tx still has signatures")
|
||||
|
||||
// Set suite.ctx with smaller simulated TxBytes manually
|
||||
suite.ctx = suite.ctx.WithTxBytes(simTxBytes)
|
||||
|
||||
beforeSimGas := suite.ctx.GasMeter().GasConsumed()
|
||||
|
||||
// run antehandler with simulate=true
|
||||
suite.ctx, err = antehandler(suite.ctx, tx, true)
|
||||
consumedSimGas := suite.ctx.GasMeter().GasConsumed() - beforeSimGas
|
||||
|
||||
// require that antehandler passes and does not underestimate decorator cost
|
||||
suite.Require().Nil(err, "ConsumeTxSizeGasDecorator returned error: %v", err)
|
||||
suite.Require().True(consumedSimGas >= expectedGas, "Simulate mode underestimates gas on AnteDecorator. Simulated cost: %d, expected cost: %d", consumedSimGas, expectedGas)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestTxHeightTimeoutDecorator() {
|
||||
suite.SetupTest(true)
|
||||
|
||||
antehandler := sdk.ChainAnteDecorators(ante.NewTxTimeoutHeightDecorator())
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
|
||||
// msg and signatures
|
||||
msg := testdata.NewTestMsg(addr1)
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
timeout uint64
|
||||
height int64
|
||||
expectErr bool
|
||||
}{
|
||||
{"default value", 0, 10, false},
|
||||
{"no timeout (greater height)", 15, 10, false},
|
||||
{"no timeout (same height)", 10, 10, false},
|
||||
{"timeout (smaller height)", 9, 10, true},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc
|
||||
|
||||
suite.Run(tc.name, func() {
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
|
||||
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
suite.txBuilder.SetMemo(strings.Repeat("01234567890", 10))
|
||||
suite.txBuilder.SetTimeoutHeight(tc.timeout)
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
ctx := suite.ctx.WithBlockHeight(tc.height)
|
||||
_, err = antehandler(ctx, tx, true)
|
||||
suite.Require().Equal(tc.expectErr, err != nil, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
// AccountKeeper defines the contract needed for AccountKeeper related APIs.
|
||||
// Interface provides support to use non-sdk AccountKeeper for AnteHandler's decorators.
|
||||
type AccountKeeper interface {
|
||||
GetParams(ctx sdk.Context) (params types.Params)
|
||||
GetAccount(ctx sdk.Context, addr sdk.AccAddress) types.AccountI
|
||||
SetAccount(ctx sdk.Context, acc types.AccountI)
|
||||
GetModuleAddress(moduleName string) sdk.AccAddress
|
||||
}
|
||||
|
||||
// FeegrantKeeper defines the expected feegrant keeper.
|
||||
type FeegrantKeeper interface {
|
||||
UseGrantedFees(ctx sdk.Context, granter, grantee sdk.AccAddress, fee sdk.Coins, msgs []sdk.Msg) error
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
type HasExtensionOptionsTx interface {
|
||||
GetExtensionOptions() []*codectypes.Any
|
||||
GetNonCriticalExtensionOptions() []*codectypes.Any
|
||||
}
|
||||
|
||||
// RejectExtensionOptionsDecorator is an AnteDecorator that rejects all extension
|
||||
// options which can optionally be included in protobuf transactions. Users that
|
||||
// need extension options should create a custom AnteHandler chain that handles
|
||||
// needed extension options properly and rejects unknown ones.
|
||||
type RejectExtensionOptionsDecorator struct{}
|
||||
|
||||
// NewRejectExtensionOptionsDecorator creates a new RejectExtensionOptionsDecorator
|
||||
func NewRejectExtensionOptionsDecorator() RejectExtensionOptionsDecorator {
|
||||
return RejectExtensionOptionsDecorator{}
|
||||
}
|
||||
|
||||
var _ types.AnteDecorator = RejectExtensionOptionsDecorator{}
|
||||
|
||||
// AnteHandle implements the AnteDecorator.AnteHandle method
|
||||
func (r RejectExtensionOptionsDecorator) AnteHandle(ctx types.Context, tx types.Tx, simulate bool, next types.AnteHandler) (newCtx types.Context, err error) {
|
||||
if hasExtOptsTx, ok := tx.(HasExtensionOptionsTx); ok {
|
||||
if len(hasExtOptsTx.GetExtensionOptions()) != 0 {
|
||||
return ctx, sdkerrors.ErrUnknownExtensionOptions
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec/types"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
)
|
||||
|
||||
func (suite *AnteTestSuite) TestRejectExtensionOptionsDecorator() {
|
||||
suite.SetupTest(true) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
reod := ante.NewRejectExtensionOptionsDecorator()
|
||||
antehandler := sdk.ChainAnteDecorators(reod)
|
||||
|
||||
// no extension options should not trigger an error
|
||||
theTx := suite.txBuilder.GetTx()
|
||||
_, err := antehandler(suite.ctx, theTx, false)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
extOptsTxBldr, ok := suite.txBuilder.(tx.ExtensionOptionsTxBuilder)
|
||||
if !ok {
|
||||
// if we can't set extension options, this decorator doesn't apply and we're done
|
||||
return
|
||||
}
|
||||
|
||||
// setting any extension option should cause an error
|
||||
any, err := types.NewAnyWithValue(testdata.NewTestMsg())
|
||||
suite.Require().NoError(err)
|
||||
extOptsTxBldr.SetExtensionOptions(any)
|
||||
theTx = suite.txBuilder.GetTx()
|
||||
_, err = antehandler(suite.ctx, theTx, false)
|
||||
suite.Require().EqualError(err, "unknown extension options")
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
// MempoolFeeDecorator will check if the transaction's fee is at least as large
|
||||
// as the local validator's minimum gasFee (defined in validator config).
|
||||
// If fee is too low, decorator returns error and tx is rejected from mempool.
|
||||
// Note this only applies when ctx.CheckTx = true
|
||||
// If fee is high enough or not CheckTx, then call next AnteHandler
|
||||
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
|
||||
type MempoolFeeDecorator struct{}
|
||||
|
||||
func NewMempoolFeeDecorator() MempoolFeeDecorator {
|
||||
return MempoolFeeDecorator{}
|
||||
}
|
||||
|
||||
func (mfd MempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
feeTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
|
||||
}
|
||||
|
||||
feeCoins := feeTx.GetFee()
|
||||
gas := feeTx.GetGas()
|
||||
|
||||
// Ensure that the provided fees meet a minimum threshold for the validator,
|
||||
// if this is a CheckTx. This is only for local mempool purposes, and thus
|
||||
// is only ran on check tx.
|
||||
if ctx.IsCheckTx() && !simulate {
|
||||
minGasPrices := ctx.MinGasPrices()
|
||||
if !minGasPrices.IsZero() {
|
||||
requiredFees := make(sdk.Coins, len(minGasPrices))
|
||||
|
||||
// Determine the required fees by multiplying each required minimum gas
|
||||
// price by the gas limit, where fee = ceil(minGasPrice * gasLimit).
|
||||
glDec := sdk.NewDec(int64(gas))
|
||||
for i, gp := range minGasPrices {
|
||||
fee := gp.Amount.Mul(glDec)
|
||||
requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt())
|
||||
}
|
||||
|
||||
if !feeCoins.IsAnyGTE(requiredFees) {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeCoins, requiredFees)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// DeductFeeDecorator deducts fees from the first signer of the tx
|
||||
// If the first signer does not have the funds to pay for the fees, return with InsufficientFunds error
|
||||
// Call next AnteHandler if fees successfully deducted
|
||||
// CONTRACT: Tx must implement FeeTx interface to use DeductFeeDecorator
|
||||
type DeductFeeDecorator struct {
|
||||
ak AccountKeeper
|
||||
bankKeeper evmtypes.BankKeeper
|
||||
feegrantKeeper FeegrantKeeper
|
||||
}
|
||||
|
||||
func NewDeductFeeDecorator(ak AccountKeeper, bk evmtypes.BankKeeper, fk FeegrantKeeper) DeductFeeDecorator {
|
||||
return DeductFeeDecorator{
|
||||
ak: ak,
|
||||
bankKeeper: bk,
|
||||
feegrantKeeper: fk,
|
||||
}
|
||||
}
|
||||
|
||||
func (dfd DeductFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
feeTx, ok := tx.(sdk.FeeTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
|
||||
}
|
||||
|
||||
if addr := dfd.ak.GetModuleAddress(types.FeeCollectorName); addr == nil {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.FeeCollectorName))
|
||||
}
|
||||
|
||||
fee := feeTx.GetFee()
|
||||
feePayer := feeTx.FeePayer()
|
||||
feeGranter := feeTx.FeeGranter()
|
||||
|
||||
deductFeesFrom := feePayer
|
||||
|
||||
// if feegranter set deduct fee from feegranter account.
|
||||
// this works with only when feegrant enabled.
|
||||
if feeGranter != nil {
|
||||
if dfd.feegrantKeeper == nil {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "fee grants are not enabled")
|
||||
} else if !feeGranter.Equals(feePayer) {
|
||||
err := dfd.feegrantKeeper.UseGrantedFees(ctx, feeGranter, feePayer, fee, tx.GetMsgs())
|
||||
|
||||
if err != nil {
|
||||
return ctx, sdkerrors.Wrapf(err, "%s not allowed to pay fees from %s", feeGranter, feePayer)
|
||||
}
|
||||
}
|
||||
|
||||
deductFeesFrom = feeGranter
|
||||
}
|
||||
|
||||
deductFeesFromAcc := dfd.ak.GetAccount(ctx, deductFeesFrom)
|
||||
if deductFeesFromAcc == nil {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", deductFeesFrom)
|
||||
}
|
||||
|
||||
// deduct the fees
|
||||
if !feeTx.GetFee().IsZero() {
|
||||
err = DeductFees(dfd.bankKeeper, ctx, deductFeesFromAcc, feeTx.GetFee())
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
}
|
||||
|
||||
events := sdk.Events{sdk.NewEvent(sdk.EventTypeTx,
|
||||
sdk.NewAttribute(sdk.AttributeKeyFee, feeTx.GetFee().String()),
|
||||
)}
|
||||
ctx.EventManager().EmitEvents(events)
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// DeductFees deducts fees from the given account.
|
||||
func DeductFees(bankKeeper evmtypes.BankKeeper, ctx sdk.Context, acc types.AccountI, fees sdk.Coins) error {
|
||||
if !fees.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "invalid fee amount: %s", fees)
|
||||
}
|
||||
|
||||
err := bankKeeper.SendCoinsFromAccountToModule(ctx, acc.GetAddress(), types.FeeCollectorName, fees)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
)
|
||||
|
||||
func (suite *AnteTestSuite) TestEnsureMempoolFees() {
|
||||
suite.SetupTest(true) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
mfd := ante.NewMempoolFeeDecorator()
|
||||
antehandler := sdk.ChainAnteDecorators(mfd)
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
|
||||
// msg and signatures
|
||||
msg := testdata.NewTestMsg(addr1)
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// Set high gas price so standard test fee fails
|
||||
atomPrice := sdk.NewDecCoinFromDec("atom", sdk.NewDec(200).Quo(sdk.NewDec(100000)))
|
||||
highGasPrice := []sdk.DecCoin{atomPrice}
|
||||
suite.ctx = suite.ctx.WithMinGasPrices(highGasPrice)
|
||||
|
||||
// Set IsCheckTx to true
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(true)
|
||||
|
||||
// antehandler errors with insufficient fees
|
||||
_, err = antehandler(suite.ctx, tx, false)
|
||||
suite.Require().NotNil(err, "Decorator should have errored on too low fee for local gasPrice")
|
||||
|
||||
// Set IsCheckTx to false
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(false)
|
||||
|
||||
// antehandler should not error since we do not check minGasPrice in DeliverTx
|
||||
_, err = antehandler(suite.ctx, tx, false)
|
||||
suite.Require().Nil(err, "MempoolFeeDecorator returned error in DeliverTx")
|
||||
|
||||
// Set IsCheckTx back to true for testing sufficient mempool fee
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(true)
|
||||
|
||||
atomPrice = sdk.NewDecCoinFromDec("atom", sdk.NewDec(0).Quo(sdk.NewDec(100000)))
|
||||
lowGasPrice := []sdk.DecCoin{atomPrice}
|
||||
suite.ctx = suite.ctx.WithMinGasPrices(lowGasPrice)
|
||||
|
||||
_, err = antehandler(suite.ctx, tx, false)
|
||||
suite.Require().Nil(err, "Decorator should not have errored on fee higher than local gasPrice")
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestDeductFees() {
|
||||
suite.SetupTest(false) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
|
||||
// msg and signatures
|
||||
msg := testdata.NewTestMsg(addr1)
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// Set account with insufficient funds
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr1)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
coins := sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(10)))
|
||||
err = simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr1, coins)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
dfd := ante.NewDeductFeeDecorator(suite.app.AccountKeeper, suite.app.BankKeeper, nil)
|
||||
antehandler := sdk.ChainAnteDecorators(dfd)
|
||||
|
||||
_, err = antehandler(suite.ctx, tx, false)
|
||||
|
||||
suite.Require().NotNil(err, "Tx did not error when fee payer had insufficient funds")
|
||||
|
||||
// Set account with sufficient funds
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
err = simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr1, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(200))))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
_, err = antehandler(suite.ctx, tx, false)
|
||||
|
||||
suite.Require().Nil(err, "Tx errored after account has been set with sufficient funds")
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
package ante_test
|
||||
|
||||
/* TODO: fix these tests
|
||||
import (
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/simapp/helpers"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
ante "github.com/tharsis/ethermint/x/auth/ante"
|
||||
authsign "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/feegrant"
|
||||
)
|
||||
|
||||
func (suite *AnteTestSuite) TestDeductFeesNoDelegation() {
|
||||
suite.SetupTest(false)
|
||||
// setup
|
||||
app, ctx := suite.app, suite.ctx
|
||||
|
||||
protoTxCfg := tx.NewTxConfig(codec.NewProtoCodec(app.InterfaceRegistry()), tx.DefaultSignModes)
|
||||
|
||||
// this just tests our handler
|
||||
dfd := ante.NewDeductFeeDecorator(app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper)
|
||||
feeAnteHandler := sdk.ChainAnteDecorators(dfd)
|
||||
|
||||
// this tests the whole stack
|
||||
anteHandlerStack := suite.anteHandler
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
priv2, _, addr2 := testdata.KeyTestPubAddr()
|
||||
priv3, _, addr3 := testdata.KeyTestPubAddr()
|
||||
priv4, _, addr4 := testdata.KeyTestPubAddr()
|
||||
priv5, _, addr5 := testdata.KeyTestPubAddr()
|
||||
|
||||
// Set addr1 with insufficient funds
|
||||
err := simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr1, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(10))})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// Set addr2 with more funds
|
||||
err = simapp.FundAccount(suite.app.BankKeeper, suite.ctx, addr2, []sdk.Coin{sdk.NewCoin("atom", sdk.NewInt(99999))})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// grant fee allowance from `addr2` to `addr3` (plenty to pay)
|
||||
err = app.FeeGrantKeeper.GrantAllowance(ctx, addr2, addr3, &feegrant.BasicAllowance{
|
||||
SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 500)),
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
// grant low fee allowance (20atom), to check the tx requesting more than allowed.
|
||||
err = app.FeeGrantKeeper.GrantAllowance(ctx, addr2, addr4, &feegrant.BasicAllowance{
|
||||
SpendLimit: sdk.NewCoins(sdk.NewInt64Coin("atom", 20)),
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
cases := map[string]struct {
|
||||
signerKey cryptotypes.PrivKey
|
||||
signer sdk.AccAddress
|
||||
feeAccount sdk.AccAddress
|
||||
fee int64
|
||||
valid bool
|
||||
}{
|
||||
"paying with low funds": {
|
||||
signerKey: priv1,
|
||||
signer: addr1,
|
||||
fee: 50,
|
||||
valid: false,
|
||||
},
|
||||
"paying with good funds": {
|
||||
signerKey: priv2,
|
||||
signer: addr2,
|
||||
fee: 50,
|
||||
valid: true,
|
||||
},
|
||||
"paying with no account": {
|
||||
signerKey: priv3,
|
||||
signer: addr3,
|
||||
fee: 1,
|
||||
valid: false,
|
||||
},
|
||||
"no fee with real account": {
|
||||
signerKey: priv1,
|
||||
signer: addr1,
|
||||
fee: 0,
|
||||
valid: true,
|
||||
},
|
||||
"no fee with no account": {
|
||||
signerKey: priv5,
|
||||
signer: addr5,
|
||||
fee: 0,
|
||||
valid: false,
|
||||
},
|
||||
"valid fee grant without account": {
|
||||
signerKey: priv3,
|
||||
signer: addr3,
|
||||
feeAccount: addr2,
|
||||
fee: 50,
|
||||
valid: true,
|
||||
},
|
||||
"no fee grant": {
|
||||
signerKey: priv3,
|
||||
signer: addr3,
|
||||
feeAccount: addr1,
|
||||
fee: 2,
|
||||
valid: false,
|
||||
},
|
||||
"allowance smaller than requested fee": {
|
||||
signerKey: priv4,
|
||||
signer: addr4,
|
||||
feeAccount: addr2,
|
||||
fee: 50,
|
||||
valid: false,
|
||||
},
|
||||
"granter cannot cover allowed fee grant": {
|
||||
signerKey: priv4,
|
||||
signer: addr4,
|
||||
feeAccount: addr1,
|
||||
fee: 50,
|
||||
valid: false,
|
||||
},
|
||||
}
|
||||
|
||||
for name, stc := range cases {
|
||||
tc := stc // to make scopelint happy
|
||||
suite.T().Run(name, func(t *testing.T) {
|
||||
fee := sdk.NewCoins(sdk.NewInt64Coin("atom", tc.fee))
|
||||
msgs := []sdk.Msg{testdata.NewTestMsg(tc.signer)}
|
||||
|
||||
acc := app.AccountKeeper.GetAccount(ctx, tc.signer)
|
||||
privs, accNums, seqs := []cryptotypes.PrivKey{tc.signerKey}, []uint64{0}, []uint64{0}
|
||||
if acc != nil {
|
||||
accNums, seqs = []uint64{acc.GetAccountNumber()}, []uint64{acc.GetSequence()}
|
||||
}
|
||||
|
||||
tx, err := genTxWithFeeGranter(protoTxCfg, msgs, fee, helpers.DefaultGenTxGas, ctx.ChainID(), accNums, seqs, tc.feeAccount, privs...)
|
||||
suite.Require().NoError(err)
|
||||
_, err = feeAnteHandler(ctx, tx, false) // tests only feegrant ante
|
||||
if tc.valid {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
|
||||
_, err = anteHandlerStack(ctx, tx, false) // tests while stack
|
||||
if tc.valid {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// don't consume any gas
|
||||
func SigGasNoConsumer(meter sdk.GasMeter, sig []byte, pubkey crypto.PubKey, params authtypes.Params) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func genTxWithFeeGranter(gen client.TxConfig, msgs []sdk.Msg, feeAmt sdk.Coins, gas uint64, chainID string, accNums,
|
||||
accSeqs []uint64, feeGranter sdk.AccAddress, priv ...cryptotypes.PrivKey) (sdk.Tx, error) {
|
||||
sigs := make([]signing.SignatureV2, len(priv))
|
||||
|
||||
// create a random length memo
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
|
||||
memo := simulation.RandStringOfLength(r, simulation.RandIntBetween(r, 0, 100))
|
||||
|
||||
signMode := gen.SignModeHandler().DefaultMode()
|
||||
|
||||
// 1st round: set SignatureV2 with empty signatures, to set correct
|
||||
// signer infos.
|
||||
for i, p := range priv {
|
||||
sigs[i] = signing.SignatureV2{
|
||||
PubKey: p.PubKey(),
|
||||
Data: &signing.SingleSignatureData{
|
||||
SignMode: signMode,
|
||||
},
|
||||
Sequence: accSeqs[i],
|
||||
}
|
||||
}
|
||||
|
||||
tx := gen.NewTxBuilder()
|
||||
err := tx.SetMsgs(msgs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = tx.SetSignatures(sigs...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tx.SetMemo(memo)
|
||||
tx.SetFeeAmount(feeAmt)
|
||||
tx.SetGasLimit(gas)
|
||||
tx.SetFeeGranter(feeGranter)
|
||||
|
||||
// 2nd round: once all signer infos are set, every signer can sign.
|
||||
for i, p := range priv {
|
||||
signerData := authsign.SignerData{
|
||||
ChainID: chainID,
|
||||
AccountNumber: accNums[i],
|
||||
Sequence: accSeqs[i],
|
||||
}
|
||||
signBytes, err := gen.SignModeHandler().GetSignBytes(signMode, signerData, tx.GetTx())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sig, err := p.Sign(signBytes)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
sigs[i].Data.(*signing.SingleSignatureData).Signature = sig
|
||||
err = tx.SetSignatures(sigs...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
return tx.GetTx(), nil
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,76 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
|
||||
)
|
||||
|
||||
var (
|
||||
_ GasTx = (*legacytx.StdTx)(nil) // assert StdTx implements GasTx
|
||||
)
|
||||
|
||||
// GasTx defines a Tx with a GetGas() method which is needed to use SetUpContextDecorator
|
||||
type GasTx interface {
|
||||
sdk.Tx
|
||||
GetGas() uint64
|
||||
}
|
||||
|
||||
// SetUpContextDecorator sets the GasMeter in the Context and wraps the next AnteHandler with a defer clause
|
||||
// to recover from any downstream OutOfGas panics in the AnteHandler chain to return an error with information
|
||||
// on gas provided and gas used.
|
||||
// CONTRACT: Must be first decorator in the chain
|
||||
// CONTRACT: Tx must implement GasTx interface
|
||||
type SetUpContextDecorator struct{}
|
||||
|
||||
func NewSetUpContextDecorator() SetUpContextDecorator {
|
||||
return SetUpContextDecorator{}
|
||||
}
|
||||
|
||||
func (sud SetUpContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
// all transactions must implement GasTx
|
||||
gasTx, ok := tx.(GasTx)
|
||||
if !ok {
|
||||
// Set a gas meter with limit 0 as to prevent an infinite gas meter attack
|
||||
// during runTx.
|
||||
newCtx = SetGasMeter(simulate, ctx, 0)
|
||||
return newCtx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
|
||||
}
|
||||
|
||||
newCtx = SetGasMeter(simulate, ctx, gasTx.GetGas())
|
||||
|
||||
// Decorator will catch an OutOfGasPanic caused in the next antehandler
|
||||
// AnteHandlers must have their own defer/recover in order for the BaseApp
|
||||
// to know how much gas was used! This is because the GasMeter is created in
|
||||
// the AnteHandler, but if it panics the context won't be set properly in
|
||||
// runTx's recover call.
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
switch rType := r.(type) {
|
||||
case sdk.ErrorOutOfGas:
|
||||
log := fmt.Sprintf(
|
||||
"out of gas in location: %v; gasWanted: %d, gasUsed: %d",
|
||||
rType.Descriptor, gasTx.GetGas(), newCtx.GasMeter().GasConsumed())
|
||||
|
||||
err = sdkerrors.Wrap(sdkerrors.ErrOutOfGas, log)
|
||||
default:
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return next(newCtx, tx, simulate)
|
||||
}
|
||||
|
||||
// SetGasMeter returns a new context with a gas meter set from a given context.
|
||||
func SetGasMeter(simulate bool, ctx sdk.Context, gasLimit uint64) sdk.Context {
|
||||
// In various cases such as simulation and during the genesis block, we do not
|
||||
// meter any gas utilization.
|
||||
if simulate || ctx.BlockHeight() == 0 {
|
||||
return ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
}
|
||||
|
||||
return ctx.WithGasMeter(sdk.NewGasMeter(gasLimit))
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
)
|
||||
|
||||
func (suite *AnteTestSuite) TestSetup() {
|
||||
suite.SetupTest(true) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
|
||||
// msg and signatures
|
||||
msg := testdata.NewTestMsg(addr1)
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
sud := ante.NewSetUpContextDecorator()
|
||||
antehandler := sdk.ChainAnteDecorators(sud)
|
||||
|
||||
// Set height to non-zero value for GasMeter to be set
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
// Context GasMeter Limit not set
|
||||
suite.Require().Equal(uint64(0), suite.ctx.GasMeter().Limit(), "GasMeter set with limit before setup")
|
||||
|
||||
newCtx, err := antehandler(suite.ctx, tx, false)
|
||||
suite.Require().Nil(err, "SetUpContextDecorator returned error")
|
||||
|
||||
// Context GasMeter Limit should be set after SetUpContextDecorator runs
|
||||
suite.Require().Equal(gasLimit, newCtx.GasMeter().Limit(), "GasMeter not set correctly")
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestRecoverPanic() {
|
||||
suite.SetupTest(true) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
|
||||
// msg and signatures
|
||||
msg := testdata.NewTestMsg(addr1)
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msg))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1}, []uint64{0}, []uint64{0}
|
||||
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
sud := ante.NewSetUpContextDecorator()
|
||||
antehandler := sdk.ChainAnteDecorators(sud, OutOfGasDecorator{})
|
||||
|
||||
// Set height to non-zero value for GasMeter to be set
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
newCtx, err := antehandler(suite.ctx, tx, false)
|
||||
|
||||
suite.Require().NotNil(err, "Did not return error on OutOfGas panic")
|
||||
|
||||
suite.Require().True(sdkerrors.ErrOutOfGas.Is(err), "Returned error is not an out of gas error")
|
||||
suite.Require().Equal(gasLimit, newCtx.GasMeter().Limit())
|
||||
|
||||
antehandler = sdk.ChainAnteDecorators(sud, PanicDecorator{})
|
||||
suite.Require().Panics(func() { antehandler(suite.ctx, tx, false) }, "Recovered from non-Out-of-Gas panic") // nolint:errcheck
|
||||
}
|
||||
|
||||
type OutOfGasDecorator struct{}
|
||||
|
||||
// AnteDecorator that will throw OutOfGas panic
|
||||
func (ogd OutOfGasDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
overLimit := ctx.GasMeter().Limit() + 1
|
||||
|
||||
// Should panic with outofgas error
|
||||
ctx.GasMeter().ConsumeGas(overLimit, "test panic")
|
||||
|
||||
// not reached
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
type PanicDecorator struct{}
|
||||
|
||||
func (pd PanicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
panic("random error")
|
||||
}
|
||||
@@ -0,0 +1,510 @@
|
||||
package ante
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
|
||||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
var (
|
||||
// simulation signature values used to estimate gas consumption
|
||||
key = make([]byte, secp256k1.PubKeySize)
|
||||
simSecp256k1Pubkey = &secp256k1.PubKey{Key: key}
|
||||
simSecp256k1Sig [64]byte
|
||||
|
||||
_ authsigning.SigVerifiableTx = (*legacytx.StdTx)(nil) // assert StdTx implements SigVerifiableTx
|
||||
)
|
||||
|
||||
func init() {
|
||||
// This decodes a valid hex string into a sepc256k1Pubkey for use in transaction simulation
|
||||
bz, _ := hex.DecodeString("035AD6810A47F073553FF30D2FCC7E0D3B1C0B74B61A1AAA2582344037151E143A")
|
||||
copy(key, bz)
|
||||
simSecp256k1Pubkey.Key = key
|
||||
}
|
||||
|
||||
// SignatureVerificationGasConsumer is the type of function that is used to both
|
||||
// consume gas when verifying signatures and also to accept or reject different types of pubkeys
|
||||
// This is where apps can define their own PubKey
|
||||
type SignatureVerificationGasConsumer = func(meter sdk.GasMeter, sig signing.SignatureV2, params types.Params) error
|
||||
|
||||
// SetPubKeyDecorator sets PubKeys in context for any signer which does not already have pubkey set
|
||||
// PubKeys must be set in context for all signers before any other sigverify decorators run
|
||||
// CONTRACT: Tx must implement SigVerifiableTx interface
|
||||
type SetPubKeyDecorator struct {
|
||||
ak AccountKeeper
|
||||
}
|
||||
|
||||
func NewSetPubKeyDecorator(ak AccountKeeper) SetPubKeyDecorator {
|
||||
return SetPubKeyDecorator{
|
||||
ak: ak,
|
||||
}
|
||||
}
|
||||
|
||||
func (spkd SetPubKeyDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
sigTx, ok := tx.(authsigning.SigVerifiableTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid tx type")
|
||||
}
|
||||
|
||||
pubkeys, err := sigTx.GetPubKeys()
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
signers := sigTx.GetSigners()
|
||||
|
||||
for i, pk := range pubkeys {
|
||||
// PublicKey was omitted from slice since it has already been set in context
|
||||
if pk == nil {
|
||||
if !simulate {
|
||||
continue
|
||||
}
|
||||
pk = simSecp256k1Pubkey
|
||||
}
|
||||
// Only make check if simulate=false
|
||||
if !simulate && !bytes.Equal(pk.Address(), signers[i]) {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey,
|
||||
"pubKey does not match signer address %s with signer index: %d", signers[i], i)
|
||||
}
|
||||
|
||||
acc, err := GetSignerAcc(ctx, spkd.ak, signers[i])
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
// account already has pubkey set,no need to reset
|
||||
if acc.GetPubKey() != nil {
|
||||
continue
|
||||
}
|
||||
err = acc.SetPubKey(pk)
|
||||
if err != nil {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, err.Error())
|
||||
}
|
||||
spkd.ak.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
// Also emit the following events, so that txs can be indexed by these
|
||||
// indices:
|
||||
// - signature (via `tx.signature='<sig_as_base64>'`),
|
||||
// - concat(address,"/",sequence) (via `tx.acc_seq='cosmos1abc...def/42'`).
|
||||
sigs, err := sigTx.GetSignaturesV2()
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
var events sdk.Events
|
||||
for i, sig := range sigs {
|
||||
events = append(events, sdk.NewEvent(sdk.EventTypeTx,
|
||||
sdk.NewAttribute(sdk.AttributeKeyAccountSequence, fmt.Sprintf("%s/%d", signers[i], sig.Sequence)),
|
||||
))
|
||||
|
||||
sigBzs, err := signatureDataToBz(sig.Data)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
for _, sigBz := range sigBzs {
|
||||
events = append(events, sdk.NewEvent(sdk.EventTypeTx,
|
||||
sdk.NewAttribute(sdk.AttributeKeySignature, base64.StdEncoding.EncodeToString(sigBz)),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
ctx.EventManager().EmitEvents(events)
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// Consume parameter-defined amount of gas for each signature according to the passed-in SignatureVerificationGasConsumer function
|
||||
// before calling the next AnteHandler
|
||||
// CONTRACT: Pubkeys are set in context for all signers before this decorator runs
|
||||
// CONTRACT: Tx must implement SigVerifiableTx interface
|
||||
type SigGasConsumeDecorator struct {
|
||||
ak AccountKeeper
|
||||
sigGasConsumer SignatureVerificationGasConsumer
|
||||
}
|
||||
|
||||
func NewSigGasConsumeDecorator(ak AccountKeeper, sigGasConsumer SignatureVerificationGasConsumer) SigGasConsumeDecorator {
|
||||
return SigGasConsumeDecorator{
|
||||
ak: ak,
|
||||
sigGasConsumer: sigGasConsumer,
|
||||
}
|
||||
}
|
||||
|
||||
func (sgcd SigGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
sigTx, ok := tx.(authsigning.SigVerifiableTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
|
||||
}
|
||||
|
||||
params := sgcd.ak.GetParams(ctx)
|
||||
sigs, err := sigTx.GetSignaturesV2()
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
// stdSigs contains the sequence number, account number, and signatures.
|
||||
// When simulating, this would just be a 0-length slice.
|
||||
signerAddrs := sigTx.GetSigners()
|
||||
|
||||
for i, sig := range sigs {
|
||||
signerAcc, err := GetSignerAcc(ctx, sgcd.ak, signerAddrs[i])
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
pubKey := signerAcc.GetPubKey()
|
||||
|
||||
// In simulate mode the transaction comes with no signatures, thus if the
|
||||
// account's pubkey is nil, both signature verification and gasKVStore.Set()
|
||||
// shall consume the largest amount, i.e. it takes more gas to verify
|
||||
// secp256k1 keys than ed25519 ones.
|
||||
if simulate && pubKey == nil {
|
||||
pubKey = simSecp256k1Pubkey
|
||||
}
|
||||
|
||||
// make a SignatureV2 with PubKey filled in from above
|
||||
sig = signing.SignatureV2{
|
||||
PubKey: pubKey,
|
||||
Data: sig.Data,
|
||||
Sequence: sig.Sequence,
|
||||
}
|
||||
|
||||
err = sgcd.sigGasConsumer(ctx.GasMeter(), sig, params)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// Verify all signatures for a tx and return an error if any are invalid. Note,
|
||||
// the SigVerificationDecorator decorator will not get executed on ReCheck.
|
||||
//
|
||||
// CONTRACT: Pubkeys are set in context for all signers before this decorator runs
|
||||
// CONTRACT: Tx must implement SigVerifiableTx interface
|
||||
type SigVerificationDecorator struct {
|
||||
ak AccountKeeper
|
||||
signModeHandler authsigning.SignModeHandler
|
||||
}
|
||||
|
||||
func NewSigVerificationDecorator(ak AccountKeeper, signModeHandler authsigning.SignModeHandler) SigVerificationDecorator {
|
||||
return SigVerificationDecorator{
|
||||
ak: ak,
|
||||
signModeHandler: signModeHandler,
|
||||
}
|
||||
}
|
||||
|
||||
// OnlyLegacyAminoSigners checks SignatureData to see if all
|
||||
// signers are using SIGN_MODE_LEGACY_AMINO_JSON. If this is the case
|
||||
// then the corresponding SignatureV2 struct will not have account sequence
|
||||
// explicitly set, and we should skip the explicit verification of sig.Sequence
|
||||
// in the SigVerificationDecorator's AnteHandler function.
|
||||
func OnlyLegacyAminoSigners(sigData signing.SignatureData) bool {
|
||||
switch v := sigData.(type) {
|
||||
case *signing.SingleSignatureData:
|
||||
return v.SignMode == signing.SignMode_SIGN_MODE_LEGACY_AMINO_JSON
|
||||
case *signing.MultiSignatureData:
|
||||
for _, s := range v.Signatures {
|
||||
if !OnlyLegacyAminoSigners(s) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (svd SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
// no need to verify signatures on recheck tx
|
||||
if ctx.IsReCheckTx() {
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
sigTx, ok := tx.(authsigning.SigVerifiableTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
|
||||
}
|
||||
|
||||
// stdSigs contains the sequence number, account number, and signatures.
|
||||
// When simulating, this would just be a 0-length slice.
|
||||
sigs, err := sigTx.GetSignaturesV2()
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
signerAddrs := sigTx.GetSigners()
|
||||
|
||||
// check that signer length and signature length are the same
|
||||
if len(sigs) != len(signerAddrs) {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs))
|
||||
}
|
||||
|
||||
for i, sig := range sigs {
|
||||
acc, err := GetSignerAcc(ctx, svd.ak, signerAddrs[i])
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
// retrieve pubkey
|
||||
pubKey := acc.GetPubKey()
|
||||
if !simulate && pubKey == nil {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
|
||||
}
|
||||
|
||||
// Check account sequence number.
|
||||
if sig.Sequence != acc.GetSequence() {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrWrongSequence,
|
||||
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
|
||||
)
|
||||
}
|
||||
|
||||
// retrieve signer data
|
||||
genesis := ctx.BlockHeight() == 0
|
||||
chainID := ctx.ChainID()
|
||||
var accNum uint64
|
||||
if !genesis {
|
||||
accNum = acc.GetAccountNumber()
|
||||
}
|
||||
signerData := authsigning.SignerData{
|
||||
ChainID: chainID,
|
||||
AccountNumber: accNum,
|
||||
Sequence: acc.GetSequence(),
|
||||
}
|
||||
|
||||
if !simulate {
|
||||
err := authsigning.VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, tx)
|
||||
if err != nil {
|
||||
var errMsg string
|
||||
if OnlyLegacyAminoSigners(sig.Data) {
|
||||
// If all signers are using SIGN_MODE_LEGACY_AMINO, we rely on VerifySignature to check account sequence number,
|
||||
// and therefore communicate sequence number as a potential cause of error.
|
||||
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d), sequence (%d) and chain-id (%s)", accNum, acc.GetSequence(), chainID)
|
||||
} else {
|
||||
errMsg = fmt.Sprintf("signature verification failed; please verify account number (%d) and chain-id (%s)", accNum, chainID)
|
||||
}
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// IncrementSequenceDecorator handles incrementing sequences of all signers.
|
||||
// Use the IncrementSequenceDecorator decorator to prevent replay attacks. Note,
|
||||
// there is no need to execute IncrementSequenceDecorator on RecheckTX since
|
||||
// CheckTx would already bump the sequence number.
|
||||
//
|
||||
// NOTE: Since CheckTx and DeliverTx state are managed separately, subsequent and
|
||||
// sequential txs orginating from the same account cannot be handled correctly in
|
||||
// a reliable way unless sequence numbers are managed and tracked manually by a
|
||||
// client. It is recommended to instead use multiple messages in a tx.
|
||||
type IncrementSequenceDecorator struct {
|
||||
ak AccountKeeper
|
||||
}
|
||||
|
||||
func NewIncrementSequenceDecorator(ak AccountKeeper) IncrementSequenceDecorator {
|
||||
return IncrementSequenceDecorator{
|
||||
ak: ak,
|
||||
}
|
||||
}
|
||||
|
||||
func (isd IncrementSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
sigTx, ok := tx.(authsigning.SigVerifiableTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "invalid transaction type")
|
||||
}
|
||||
|
||||
// increment sequence of all signers
|
||||
for _, addr := range sigTx.GetSigners() {
|
||||
acc := isd.ak.GetAccount(ctx, addr)
|
||||
if err := acc.SetSequence(acc.GetSequence() + 1); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
isd.ak.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// ValidateSigCountDecorator takes in Params and returns errors if there are too many signatures in the tx for the given params
|
||||
// otherwise it calls next AnteHandler
|
||||
// Use this decorator to set parameterized limit on number of signatures in tx
|
||||
// CONTRACT: Tx must implement SigVerifiableTx interface
|
||||
type ValidateSigCountDecorator struct {
|
||||
ak AccountKeeper
|
||||
}
|
||||
|
||||
func NewValidateSigCountDecorator(ak AccountKeeper) ValidateSigCountDecorator {
|
||||
return ValidateSigCountDecorator{
|
||||
ak: ak,
|
||||
}
|
||||
}
|
||||
|
||||
func (vscd ValidateSigCountDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
||||
sigTx, ok := tx.(authsigning.SigVerifiableTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a sigTx")
|
||||
}
|
||||
|
||||
params := vscd.ak.GetParams(ctx)
|
||||
pubKeys, err := sigTx.GetPubKeys()
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
sigCount := 0
|
||||
for _, pk := range pubKeys {
|
||||
sigCount += CountSubKeys(pk)
|
||||
if uint64(sigCount) > params.TxSigLimit {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrTooManySignatures,
|
||||
"signatures: %d, limit: %d", sigCount, params.TxSigLimit)
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
// DefaultSigVerificationGasConsumer is the default implementation of SignatureVerificationGasConsumer. It consumes gas
|
||||
// for signature verification based upon the public key type. The cost is fetched from the given params and is matched
|
||||
// by the concrete type.
|
||||
func DefaultSigVerificationGasConsumer(
|
||||
meter sdk.GasMeter, sig signing.SignatureV2, params types.Params,
|
||||
) error {
|
||||
pubkey := sig.PubKey
|
||||
switch pubkey := pubkey.(type) {
|
||||
case *ed25519.PubKey:
|
||||
meter.ConsumeGas(params.SigVerifyCostED25519, "ante verify: ed25519")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "ED25519 public keys are unsupported")
|
||||
|
||||
case *secp256k1.PubKey:
|
||||
meter.ConsumeGas(params.SigVerifyCostSecp256k1, "ante verify: secp256k1")
|
||||
return nil
|
||||
|
||||
case *secp256r1.PubKey:
|
||||
meter.ConsumeGas(params.SigVerifyCostSecp256r1(), "ante verify: secp256r1")
|
||||
return nil
|
||||
|
||||
case multisig.PubKey:
|
||||
multisignature, ok := sig.Data.(*signing.MultiSignatureData)
|
||||
if !ok {
|
||||
return fmt.Errorf("expected %T, got, %T", &signing.MultiSignatureData{}, sig.Data)
|
||||
}
|
||||
err := ConsumeMultisignatureVerificationGas(meter, multisignature, pubkey, params, sig.Sequence)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
default:
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidPubKey, "unrecognized public key type: %T", pubkey)
|
||||
}
|
||||
}
|
||||
|
||||
// ConsumeMultisignatureVerificationGas consumes gas from a GasMeter for verifying a multisig pubkey signature
|
||||
func ConsumeMultisignatureVerificationGas(
|
||||
meter sdk.GasMeter, sig *signing.MultiSignatureData, pubkey multisig.PubKey,
|
||||
params types.Params, accSeq uint64,
|
||||
) error {
|
||||
|
||||
size := sig.BitArray.Count()
|
||||
sigIndex := 0
|
||||
|
||||
for i := 0; i < size; i++ {
|
||||
if !sig.BitArray.GetIndex(i) {
|
||||
continue
|
||||
}
|
||||
sigV2 := signing.SignatureV2{
|
||||
PubKey: pubkey.GetPubKeys()[i],
|
||||
Data: sig.Signatures[sigIndex],
|
||||
Sequence: accSeq,
|
||||
}
|
||||
err := DefaultSigVerificationGasConsumer(meter, sigV2, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sigIndex++
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSignerAcc returns an account for a given address that is expected to sign
|
||||
// a transaction.
|
||||
func GetSignerAcc(ctx sdk.Context, ak AccountKeeper, addr sdk.AccAddress) (types.AccountI, error) {
|
||||
if acc := ak.GetAccount(ctx, addr); acc != nil {
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "account %s does not exist", addr)
|
||||
}
|
||||
|
||||
// CountSubKeys counts the total number of keys for a multi-sig public key.
|
||||
func CountSubKeys(pub cryptotypes.PubKey) int {
|
||||
v, ok := pub.(*kmultisig.LegacyAminoPubKey)
|
||||
if !ok {
|
||||
return 1
|
||||
}
|
||||
|
||||
numKeys := 0
|
||||
for _, subkey := range v.GetPubKeys() {
|
||||
numKeys += CountSubKeys(subkey)
|
||||
}
|
||||
|
||||
return numKeys
|
||||
}
|
||||
|
||||
// signatureDataToBz converts a SignatureData into raw bytes signature.
|
||||
// For SingleSignatureData, it returns the signature raw bytes.
|
||||
// For MultiSignatureData, it returns an array of all individual signatures,
|
||||
// as well as the aggregated signature.
|
||||
func signatureDataToBz(data signing.SignatureData) ([][]byte, error) {
|
||||
if data == nil {
|
||||
return nil, fmt.Errorf("got empty SignatureData")
|
||||
}
|
||||
|
||||
switch data := data.(type) {
|
||||
case *signing.SingleSignatureData:
|
||||
return [][]byte{data.Signature}, nil
|
||||
case *signing.MultiSignatureData:
|
||||
sigs := [][]byte{}
|
||||
var err error
|
||||
|
||||
for _, d := range data.Signatures {
|
||||
nestedSigs, err := signatureDataToBz(d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sigs = append(sigs, nestedSigs...)
|
||||
}
|
||||
|
||||
multisig := cryptotypes.MultiSignature{
|
||||
Signatures: sigs,
|
||||
}
|
||||
aggregatedSig, err := multisig.Marshal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sigs = append(sigs, aggregatedSig)
|
||||
|
||||
return sigs, nil
|
||||
default:
|
||||
return nil, sdkerrors.ErrInvalidType.Wrapf("unexpected signature data type %T", data)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
tmcrypto "github.com/tendermint/tendermint/crypto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
|
||||
)
|
||||
|
||||
// This benchmark is used to asses the ante.Secp256k1ToR1GasFactor value
|
||||
func BenchmarkSig(b *testing.B) {
|
||||
require := require.New(b)
|
||||
msg := tmcrypto.CRandBytes(1000)
|
||||
|
||||
skK := secp256k1.GenPrivKey()
|
||||
pkK := skK.PubKey()
|
||||
skR, _ := secp256r1.GenPrivKey()
|
||||
pkR := skR.PubKey()
|
||||
|
||||
sigK, err := skK.Sign(msg)
|
||||
require.NoError(err)
|
||||
sigR, err := skR.Sign(msg)
|
||||
require.NoError(err)
|
||||
b.ResetTimer()
|
||||
|
||||
b.Run("secp256k1", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ok := pkK.VerifySignature(msg, sigK)
|
||||
require.True(ok)
|
||||
}
|
||||
})
|
||||
|
||||
b.Run("secp256r1", func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
ok := pkR.VerifySignature(msg, sigR)
|
||||
require.True(ok)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,390 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
|
||||
kmultisig "github.com/cosmos/cosmos-sdk/crypto/keys/multisig"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256r1"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/types/multisig"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
func (suite *AnteTestSuite) TestSetPubKey() {
|
||||
suite.SetupTest(true) // setup
|
||||
require := suite.Require()
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
// keys and addresses
|
||||
priv1, pub1, addr1 := testdata.KeyTestPubAddr()
|
||||
priv2, pub2, addr2 := testdata.KeyTestPubAddr()
|
||||
priv3, pub3, addr3 := testdata.KeyTestPubAddrSecp256R1(require)
|
||||
|
||||
addrs := []sdk.AccAddress{addr1, addr2, addr3}
|
||||
pubs := []cryptotypes.PubKey{pub1, pub2, pub3}
|
||||
|
||||
msgs := make([]sdk.Msg, len(addrs))
|
||||
// set accounts and create msg for each address
|
||||
for i, addr := range addrs {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
|
||||
require.NoError(acc.SetAccountNumber(uint64(i)))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
msgs[i] = testdata.NewTestMsg(addr)
|
||||
}
|
||||
require.NoError(suite.txBuilder.SetMsgs(msgs...))
|
||||
suite.txBuilder.SetFeeAmount(testdata.NewTestFeeAmount())
|
||||
suite.txBuilder.SetGasLimit(testdata.NewTestGasLimit())
|
||||
|
||||
privs, accNums, accSeqs := []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}
|
||||
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
require.NoError(err)
|
||||
|
||||
spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper)
|
||||
antehandler := sdk.ChainAnteDecorators(spkd)
|
||||
|
||||
ctx, err := antehandler(suite.ctx, tx, false)
|
||||
require.NoError(err)
|
||||
|
||||
// Require that all accounts have pubkey set after Decorator runs
|
||||
for i, addr := range addrs {
|
||||
pk, err := suite.app.AccountKeeper.GetPubKey(ctx, addr)
|
||||
require.NoError(err, "Error on retrieving pubkey from account")
|
||||
require.True(pubs[i].Equals(pk),
|
||||
"Wrong Pubkey retrieved from AccountKeeper, idx=%d\nexpected=%s\n got=%s", i, pubs[i], pk)
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestConsumeSignatureVerificationGas() {
|
||||
params := types.DefaultParams()
|
||||
msg := []byte{1, 2, 3, 4}
|
||||
cdc := simapp.MakeTestEncodingConfig().Amino
|
||||
|
||||
p := types.DefaultParams()
|
||||
skR1, _ := secp256r1.GenPrivKey()
|
||||
pkSet1, sigSet1 := generatePubKeysAndSignatures(5, msg, false)
|
||||
multisigKey1 := kmultisig.NewLegacyAminoPubKey(2, pkSet1)
|
||||
multisignature1 := multisig.NewMultisig(len(pkSet1))
|
||||
expectedCost1 := expectedGasCostByKeys(pkSet1)
|
||||
for i := 0; i < len(pkSet1); i++ {
|
||||
stdSig := legacytx.StdSignature{PubKey: pkSet1[i], Signature: sigSet1[i]}
|
||||
sigV2, err := legacytx.StdSignatureToSignatureV2(cdc, stdSig)
|
||||
suite.Require().NoError(err)
|
||||
err = multisig.AddSignatureV2(multisignature1, sigV2, pkSet1)
|
||||
suite.Require().NoError(err)
|
||||
}
|
||||
|
||||
type args struct {
|
||||
meter sdk.GasMeter
|
||||
sig signing.SignatureData
|
||||
pubkey cryptotypes.PubKey
|
||||
params types.Params
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
gasConsumed uint64
|
||||
shouldErr bool
|
||||
}{
|
||||
{"PubKeyEd25519", args{sdk.NewInfiniteGasMeter(), nil, ed25519.GenPrivKey().PubKey(), params}, p.SigVerifyCostED25519, true},
|
||||
{"PubKeySecp256k1", args{sdk.NewInfiniteGasMeter(), nil, secp256k1.GenPrivKey().PubKey(), params}, p.SigVerifyCostSecp256k1, false},
|
||||
{"PubKeySecp256r1", args{sdk.NewInfiniteGasMeter(), nil, skR1.PubKey(), params}, p.SigVerifyCostSecp256r1(), false},
|
||||
{"Multisig", args{sdk.NewInfiniteGasMeter(), multisignature1, multisigKey1, params}, expectedCost1, false},
|
||||
{"unknown key", args{sdk.NewInfiniteGasMeter(), nil, nil, params}, 0, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
sigV2 := signing.SignatureV2{
|
||||
PubKey: tt.args.pubkey,
|
||||
Data: tt.args.sig,
|
||||
Sequence: 0, // Arbitrary account sequence
|
||||
}
|
||||
err := ante.DefaultSigVerificationGasConsumer(tt.args.meter, sigV2, tt.args.params)
|
||||
|
||||
if tt.shouldErr {
|
||||
suite.Require().NotNil(err)
|
||||
} else {
|
||||
suite.Require().Nil(err)
|
||||
suite.Require().Equal(tt.gasConsumed, tt.args.meter.GasConsumed(), fmt.Sprintf("%d != %d", tt.gasConsumed, tt.args.meter.GasConsumed()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestSigVerification() {
|
||||
suite.SetupTest(true) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
// make block height non-zero to ensure account numbers part of signBytes
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
priv2, _, addr2 := testdata.KeyTestPubAddr()
|
||||
priv3, _, addr3 := testdata.KeyTestPubAddr()
|
||||
|
||||
addrs := []sdk.AccAddress{addr1, addr2, addr3}
|
||||
|
||||
msgs := make([]sdk.Msg, len(addrs))
|
||||
// set accounts and create msg for each address
|
||||
for i, addr := range addrs {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
|
||||
suite.Require().NoError(acc.SetAccountNumber(uint64(i)))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
msgs[i] = testdata.NewTestMsg(addr)
|
||||
}
|
||||
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
|
||||
spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper)
|
||||
svd := ante.NewSigVerificationDecorator(suite.app.AccountKeeper, suite.clientCtx.TxConfig.SignModeHandler())
|
||||
antehandler := sdk.ChainAnteDecorators(spkd, svd)
|
||||
|
||||
type testCase struct {
|
||||
name string
|
||||
privs []cryptotypes.PrivKey
|
||||
accNums []uint64
|
||||
accSeqs []uint64
|
||||
recheck bool
|
||||
shouldErr bool
|
||||
}
|
||||
testCases := []testCase{
|
||||
{"no signers", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, false, true},
|
||||
{"not enough signers", []cryptotypes.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{0, 0}, false, true},
|
||||
{"wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{2, 1, 0}, []uint64{0, 0, 0}, false, true},
|
||||
{"wrong accnums", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{7, 8, 9}, []uint64{0, 0, 0}, false, true},
|
||||
{"wrong sequences", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{3, 4, 5}, false, true},
|
||||
{"valid tx", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}, false, false},
|
||||
{"no err on recheck", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, true, false},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
suite.ctx = suite.ctx.WithIsReCheckTx(tc.recheck)
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() // Create new txBuilder for each test
|
||||
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
tx, err := suite.CreateTestTx(tc.privs, tc.accNums, tc.accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
_, err = antehandler(suite.ctx, tx, false)
|
||||
if tc.shouldErr {
|
||||
suite.Require().NotNil(err, "TestCase %d: %s did not error as expected", i, tc.name)
|
||||
} else {
|
||||
suite.Require().Nil(err, "TestCase %d: %s errored unexpectedly. Err: %v", i, tc.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This test is exactly like the one above, but we set the codec explicitly to
|
||||
// Amino.
|
||||
// Once https://github.com/cosmos/cosmos-sdk/issues/6190 is in, we can remove
|
||||
// this, since it'll be handled by the test matrix.
|
||||
// In the meantime, we want to make double-sure amino compatibility works.
|
||||
// ref: https://github.com/cosmos/cosmos-sdk/issues/7229
|
||||
func (suite *AnteTestSuite) TestSigVerification_ExplicitAmino() {
|
||||
suite.app, suite.ctx = createTestApp(true)
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
// Set up TxConfig.
|
||||
aminoCdc := codec.NewLegacyAmino()
|
||||
// We're using TestMsg amino encoding in some tests, so register it here.
|
||||
txConfig := legacytx.StdTxConfig{Cdc: aminoCdc}
|
||||
|
||||
suite.clientCtx = client.Context{}.
|
||||
WithTxConfig(txConfig)
|
||||
|
||||
anteHandler, err := ante.NewAnteHandler(
|
||||
ante.HandlerOptions{
|
||||
AccountKeeper: suite.app.AccountKeeper,
|
||||
BankKeeper: suite.app.BankKeeper,
|
||||
FeegrantKeeper: suite.app.FeeGrantKeeper,
|
||||
SignModeHandler: txConfig.SignModeHandler(),
|
||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||
},
|
||||
)
|
||||
|
||||
suite.Require().NoError(err)
|
||||
suite.anteHandler = anteHandler
|
||||
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
// make block height non-zero to ensure account numbers part of signBytes
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
priv1, _, addr1 := testdata.KeyTestPubAddr()
|
||||
priv2, _, addr2 := testdata.KeyTestPubAddr()
|
||||
priv3, _, addr3 := testdata.KeyTestPubAddr()
|
||||
|
||||
addrs := []sdk.AccAddress{addr1, addr2, addr3}
|
||||
|
||||
msgs := make([]sdk.Msg, len(addrs))
|
||||
// set accounts and create msg for each address
|
||||
for i, addr := range addrs {
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
|
||||
suite.Require().NoError(acc.SetAccountNumber(uint64(i)))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
msgs[i] = testdata.NewTestMsg(addr)
|
||||
}
|
||||
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
|
||||
spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper)
|
||||
svd := ante.NewSigVerificationDecorator(suite.app.AccountKeeper, suite.clientCtx.TxConfig.SignModeHandler())
|
||||
antehandler := sdk.ChainAnteDecorators(spkd, svd)
|
||||
|
||||
type testCase struct {
|
||||
name string
|
||||
privs []cryptotypes.PrivKey
|
||||
accNums []uint64
|
||||
accSeqs []uint64
|
||||
recheck bool
|
||||
shouldErr bool
|
||||
}
|
||||
testCases := []testCase{
|
||||
{"no signers", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, false, true},
|
||||
{"not enough signers", []cryptotypes.PrivKey{priv1, priv2}, []uint64{0, 1}, []uint64{0, 0}, false, true},
|
||||
{"wrong order signers", []cryptotypes.PrivKey{priv3, priv2, priv1}, []uint64{2, 1, 0}, []uint64{0, 0, 0}, false, true},
|
||||
{"wrong accnums", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{7, 8, 9}, []uint64{0, 0, 0}, false, true},
|
||||
{"wrong sequences", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{3, 4, 5}, false, true},
|
||||
{"valid tx", []cryptotypes.PrivKey{priv1, priv2, priv3}, []uint64{0, 1, 2}, []uint64{0, 0, 0}, false, false},
|
||||
{"no err on recheck", []cryptotypes.PrivKey{}, []uint64{}, []uint64{}, true, false},
|
||||
}
|
||||
for i, tc := range testCases {
|
||||
suite.ctx = suite.ctx.WithIsReCheckTx(tc.recheck)
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder() // Create new txBuilder for each test
|
||||
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
tx, err := suite.CreateTestTx(tc.privs, tc.accNums, tc.accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
_, err = antehandler(suite.ctx, tx, false)
|
||||
if tc.shouldErr {
|
||||
suite.Require().NotNil(err, "TestCase %d: %s did not error as expected", i, tc.name)
|
||||
} else {
|
||||
suite.Require().Nil(err, "TestCase %d: %s errored unexpectedly. Err: %v", i, tc.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestSigIntegration() {
|
||||
// generate private keys
|
||||
privs := []cryptotypes.PrivKey{
|
||||
secp256k1.GenPrivKey(),
|
||||
secp256k1.GenPrivKey(),
|
||||
secp256k1.GenPrivKey(),
|
||||
}
|
||||
|
||||
params := types.DefaultParams()
|
||||
initialSigCost := params.SigVerifyCostSecp256k1
|
||||
initialCost, err := suite.runSigDecorators(params, false, privs...)
|
||||
suite.Require().Nil(err)
|
||||
|
||||
params.SigVerifyCostSecp256k1 *= 2
|
||||
doubleCost, err := suite.runSigDecorators(params, false, privs...)
|
||||
suite.Require().Nil(err)
|
||||
|
||||
suite.Require().Equal(initialSigCost*uint64(len(privs)), doubleCost-initialCost)
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) runSigDecorators(params types.Params, _ bool, privs ...cryptotypes.PrivKey) (sdk.Gas, error) {
|
||||
suite.SetupTest(true) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
// Make block-height non-zero to include accNum in SignBytes
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
suite.app.AccountKeeper.SetParams(suite.ctx, params)
|
||||
|
||||
msgs := make([]sdk.Msg, len(privs))
|
||||
accNums := make([]uint64, len(privs))
|
||||
accSeqs := make([]uint64, len(privs))
|
||||
// set accounts and create msg for each address
|
||||
for i, priv := range privs {
|
||||
addr := sdk.AccAddress(priv.PubKey().Address())
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
|
||||
suite.Require().NoError(acc.SetAccountNumber(uint64(i)))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
msgs[i] = testdata.NewTestMsg(addr)
|
||||
accNums[i] = uint64(i)
|
||||
accSeqs[i] = uint64(0)
|
||||
}
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
|
||||
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
spkd := ante.NewSetPubKeyDecorator(suite.app.AccountKeeper)
|
||||
svgc := ante.NewSigGasConsumeDecorator(suite.app.AccountKeeper, ante.DefaultSigVerificationGasConsumer)
|
||||
svd := ante.NewSigVerificationDecorator(suite.app.AccountKeeper, suite.clientCtx.TxConfig.SignModeHandler())
|
||||
antehandler := sdk.ChainAnteDecorators(spkd, svgc, svd)
|
||||
|
||||
// Determine gas consumption of antehandler with default params
|
||||
before := suite.ctx.GasMeter().GasConsumed()
|
||||
ctx, err := antehandler(suite.ctx, tx, false)
|
||||
after := ctx.GasMeter().GasConsumed()
|
||||
|
||||
return after - before, err
|
||||
}
|
||||
|
||||
func (suite *AnteTestSuite) TestIncrementSequenceDecorator() {
|
||||
suite.SetupTest(true) // setup
|
||||
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()
|
||||
|
||||
priv, _, addr := testdata.KeyTestPubAddr()
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
|
||||
suite.Require().NoError(acc.SetAccountNumber(uint64(50)))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
msgs := []sdk.Msg{testdata.NewTestMsg(addr)}
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
|
||||
privs := []cryptotypes.PrivKey{priv}
|
||||
accNums := []uint64{suite.app.AccountKeeper.GetAccount(suite.ctx, addr).GetAccountNumber()}
|
||||
accSeqs := []uint64{suite.app.AccountKeeper.GetAccount(suite.ctx, addr).GetSequence()}
|
||||
feeAmount := testdata.NewTestFeeAmount()
|
||||
gasLimit := testdata.NewTestGasLimit()
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
isd := ante.NewIncrementSequenceDecorator(suite.app.AccountKeeper)
|
||||
antehandler := sdk.ChainAnteDecorators(isd)
|
||||
|
||||
testCases := []struct {
|
||||
ctx sdk.Context
|
||||
simulate bool
|
||||
expectedSeq uint64
|
||||
}{
|
||||
{suite.ctx.WithIsReCheckTx(true), false, 1},
|
||||
{suite.ctx.WithIsCheckTx(true).WithIsReCheckTx(false), false, 2},
|
||||
{suite.ctx.WithIsReCheckTx(true), false, 3},
|
||||
{suite.ctx.WithIsReCheckTx(true), false, 4},
|
||||
{suite.ctx.WithIsReCheckTx(true), true, 5},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
_, err := antehandler(tc.ctx, tx, tc.simulate)
|
||||
suite.Require().NoError(err, "unexpected error; tc #%d, %v", i, tc)
|
||||
suite.Require().Equal(tc.expectedSeq, suite.app.AccountKeeper.GetAccount(suite.ctx, addr).GetSequence())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package ante_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/testutil/testdata"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
xauthsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
// TestAccount represents an account used in the tests in x/auth/ante.
|
||||
type TestAccount struct {
|
||||
acc types.AccountI
|
||||
priv cryptotypes.PrivKey
|
||||
}
|
||||
|
||||
// AnteTestSuite is a test suite to be used with ante handler tests.
|
||||
type AnteTestSuite struct {
|
||||
suite.Suite
|
||||
|
||||
app *simapp.SimApp
|
||||
anteHandler sdk.AnteHandler
|
||||
ctx sdk.Context
|
||||
clientCtx client.Context
|
||||
txBuilder client.TxBuilder
|
||||
}
|
||||
|
||||
// returns context and app with params set on account keeper
|
||||
func createTestApp(isCheckTx bool) (*simapp.SimApp, sdk.Context) {
|
||||
app := simapp.Setup(isCheckTx)
|
||||
ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{})
|
||||
app.AccountKeeper.SetParams(ctx, authtypes.DefaultParams())
|
||||
|
||||
return app, ctx
|
||||
}
|
||||
|
||||
// SetupTest setups a new test, with new app, context, and anteHandler.
|
||||
func (suite *AnteTestSuite) SetupTest(isCheckTx bool) {
|
||||
suite.app, suite.ctx = createTestApp(isCheckTx)
|
||||
suite.ctx = suite.ctx.WithBlockHeight(1)
|
||||
|
||||
// Set up TxConfig.
|
||||
encodingConfig := simapp.MakeTestEncodingConfig()
|
||||
// We're using TestMsg encoding in some tests, so register it here.
|
||||
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
|
||||
testdata.RegisterInterfaces(encodingConfig.InterfaceRegistry)
|
||||
|
||||
suite.clientCtx = client.Context{}.
|
||||
WithTxConfig(encodingConfig.TxConfig)
|
||||
|
||||
anteHandler, err := ante.NewAnteHandler(
|
||||
ante.HandlerOptions{
|
||||
AccountKeeper: suite.app.AccountKeeper,
|
||||
BankKeeper: suite.app.BankKeeper,
|
||||
FeegrantKeeper: suite.app.FeeGrantKeeper,
|
||||
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
|
||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||
},
|
||||
)
|
||||
|
||||
suite.Require().NoError(err)
|
||||
suite.anteHandler = anteHandler
|
||||
}
|
||||
|
||||
// CreateTestAccounts creates `numAccs` accounts, and return all relevant
|
||||
// information about them including their private keys.
|
||||
func (suite *AnteTestSuite) CreateTestAccounts(numAccs int) []TestAccount {
|
||||
var accounts []TestAccount
|
||||
|
||||
for i := 0; i < numAccs; i++ {
|
||||
priv, _, addr := testdata.KeyTestPubAddr()
|
||||
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr)
|
||||
err := acc.SetAccountNumber(uint64(i))
|
||||
suite.Require().NoError(err)
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
someCoins := sdk.Coins{
|
||||
sdk.NewInt64Coin("atom", 10000000),
|
||||
}
|
||||
err = suite.app.BankKeeper.MintCoins(suite.ctx, minttypes.ModuleName, someCoins)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
err = suite.app.BankKeeper.SendCoinsFromModuleToAccount(suite.ctx, minttypes.ModuleName, addr, someCoins)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
accounts = append(accounts, TestAccount{acc, priv})
|
||||
}
|
||||
|
||||
return accounts
|
||||
}
|
||||
|
||||
// CreateTestTx is a helper function to create a tx given multiple inputs.
|
||||
func (suite *AnteTestSuite) CreateTestTx(privs []cryptotypes.PrivKey, accNums []uint64, accSeqs []uint64, chainID string) (xauthsigning.Tx, error) {
|
||||
// First round: we gather all the signer infos. We use the "set empty
|
||||
// signature" hack to do that.
|
||||
var sigsV2 []signing.SignatureV2
|
||||
for i, priv := range privs {
|
||||
sigV2 := signing.SignatureV2{
|
||||
PubKey: priv.PubKey(),
|
||||
Data: &signing.SingleSignatureData{
|
||||
SignMode: suite.clientCtx.TxConfig.SignModeHandler().DefaultMode(),
|
||||
Signature: nil,
|
||||
},
|
||||
Sequence: accSeqs[i],
|
||||
}
|
||||
|
||||
sigsV2 = append(sigsV2, sigV2)
|
||||
}
|
||||
err := suite.txBuilder.SetSignatures(sigsV2...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Second round: all signer infos are set, so each signer can sign.
|
||||
sigsV2 = []signing.SignatureV2{}
|
||||
for i, priv := range privs {
|
||||
signerData := xauthsigning.SignerData{
|
||||
ChainID: chainID,
|
||||
AccountNumber: accNums[i],
|
||||
Sequence: accSeqs[i],
|
||||
}
|
||||
sigV2, err := tx.SignWithPrivKey(
|
||||
suite.clientCtx.TxConfig.SignModeHandler().DefaultMode(), signerData,
|
||||
suite.txBuilder, priv, suite.clientCtx.TxConfig, accSeqs[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sigsV2 = append(sigsV2, sigV2)
|
||||
}
|
||||
err = suite.txBuilder.SetSignatures(sigsV2...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return suite.txBuilder.GetTx(), nil
|
||||
}
|
||||
|
||||
// TestCase represents a test case used in test tables.
|
||||
type TestCase struct {
|
||||
desc string
|
||||
malleate func()
|
||||
simulate bool
|
||||
expPass bool
|
||||
expErr error
|
||||
}
|
||||
|
||||
// CreateTestTx is a helper function to create a tx given multiple inputs.
|
||||
func (suite *AnteTestSuite) RunTestCase(privs []cryptotypes.PrivKey, msgs []sdk.Msg, feeAmount sdk.Coins, gasLimit uint64, accNums, accSeqs []uint64, chainID string, tc TestCase) {
|
||||
suite.Run(fmt.Sprintf("Case %s", tc.desc), func() {
|
||||
suite.Require().NoError(suite.txBuilder.SetMsgs(msgs...))
|
||||
suite.txBuilder.SetFeeAmount(feeAmount)
|
||||
suite.txBuilder.SetGasLimit(gasLimit)
|
||||
|
||||
// Theoretically speaking, ante handler unit tests should only test
|
||||
// ante handlers, but here we sometimes also test the tx creation
|
||||
// process.
|
||||
tx, txErr := suite.CreateTestTx(privs, accNums, accSeqs, chainID)
|
||||
newCtx, anteErr := suite.anteHandler(suite.ctx, tx, tc.simulate)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(txErr)
|
||||
suite.Require().NoError(anteErr)
|
||||
suite.Require().NotNil(newCtx)
|
||||
|
||||
suite.ctx = newCtx
|
||||
} else {
|
||||
switch {
|
||||
case txErr != nil:
|
||||
suite.Require().Error(txErr)
|
||||
suite.Require().True(errors.Is(txErr, tc.expErr))
|
||||
|
||||
case anteErr != nil:
|
||||
suite.Require().Error(anteErr)
|
||||
suite.Require().True(errors.Is(anteErr, tc.expErr))
|
||||
|
||||
default:
|
||||
suite.Fail("expected one of txErr,anteErr to be an error")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestAnteTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(AnteTestSuite))
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package keeper
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
||||
"github.com/palantir/stacktrace"
|
||||
authante "github.com/tharsis/ethermint/x/auth/ante"
|
||||
|
||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user