Merge pull request #35 from vulcanize/sai/upgrade_cosmos_v0.46

upgrade: upgrade to vulcanize cosmos v0.46 SMT
This commit is contained in:
Ian Norden 2022-05-23 09:42:49 -05:00 committed by GitHub
commit 007e27dcbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
109 changed files with 3377 additions and 1874 deletions

View File

@ -88,18 +88,23 @@ ifeq (boltdb,$(findstring boltdb,$(COSMOS_BUILD_OPTIONS)))
ldflags += -X github.com/cosmos/cosmos-sdk/types.DBBackend=boltdb
endif
BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
# Check for debug option
ifeq (debug,$(findstring debug,$(COSMOS_BUILD_OPTIONS)))
BUILD_FLAGS += -gcflags 'all=-N -l'
COSMOS_BUILD_OPTIONS += nostrip
endif
# check for nostrip option
ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
BUILD_FLAGS += -trimpath
ldflags += -w -s
endif
ldflags += $(LDFLAGS)
ldflags := $(strip $(ldflags))
BUILD_FLAGS := -tags "$(build_tags)" -ldflags '$(ldflags)'
# check for nostrip option
ifeq (,$(findstring nostrip,$(COSMOS_BUILD_OPTIONS)))
BUILD_FLAGS += -trimpath
endif
all: tools build lint test
# # The below include contains the tools and runsim targets.
# include contrib/devtools/Makefile
@ -111,14 +116,16 @@ BUILD_TARGETS := build install
build: BUILD_ARGS=-o $(BUILDDIR)/
build-linux:
GOOS=linux GOARCH=amd64 LEDGER_ENABLED=false $(MAKE) build
GOOS=linux GOARCH=$(if $(findstring aarch64,$(shell uname -m)) || $(findstring arm64,$(shell uname -m)),arm64,amd64) LEDGER_ENABLED=false $(MAKE) build
$(BUILD_TARGETS): go.sum $(BUILDDIR)/
go $@ $(BUILD_FLAGS) $(BUILD_ARGS) ./...
go $@ -mod=readonly $(BUILD_FLAGS) $(BUILD_ARGS) ./...
$(BUILDDIR)/:
mkdir -p $(BUILDDIR)/
.PHONY: build build-linux cosmovisor
docker-build:
# TODO replace with kaniko
docker build -t ${DOCKER_IMAGE}:${DOCKER_TAG} .

View File

@ -1,103 +0,0 @@
package ante
import (
"fmt"
"runtime/debug"
tmlog "github.com/tendermint/tendermint/libs/log"
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"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
)
const (
secp256k1VerifyCost uint64 = 21000
)
// NewAnteHandler returns an ante handler responsible for attempting to route an
// Ethereum or SDK transaction to an internal ante handler for performing
// transaction-level processing (e.g. fee payment, signature verification) before
// being passed onto it's respective handler.
func NewAnteHandler(options HandlerOptions) sdk.AnteHandler {
return func(
ctx sdk.Context, tx sdk.Tx, sim bool,
) (newCtx sdk.Context, err error) {
var anteHandler sdk.AnteHandler
defer Recover(ctx.Logger(), &err)
txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx)
if ok {
opts := txWithExtensions.GetExtensionOptions()
if len(opts) > 0 {
switch typeURL := opts[0].GetTypeUrl(); typeURL {
case "/ethermint.evm.v1.ExtensionOptionsEthereumTx":
// handle as *evmtypes.MsgEthereumTx
anteHandler = newEthAnteHandler(options)
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
anteHandler = newCosmosAnteHandlerEip712(options)
default:
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrUnknownExtensionOptions,
"rejecting tx with unsupported extension option: %s", typeURL,
)
}
return anteHandler(ctx, tx, sim)
}
}
// handle as totally normal Cosmos SDK tx
switch tx.(type) {
case sdk.Tx:
anteHandler = newCosmosAnteHandler(options)
default:
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx)
}
return anteHandler(ctx, tx, sim)
}
}
func Recover(logger tmlog.Logger, err *error) {
if r := recover(); r != nil {
*err = sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r)
if e, ok := r.(error); ok {
logger.Error(
"ante handler panicked",
"error", e,
"stack trace", string(debug.Stack()),
)
} else {
logger.Error(
"ante handler panicked",
"recover", fmt.Sprintf("%v", r),
)
}
}
}
var _ authante.SignatureVerificationGasConsumer = DefaultSigVerificationGasConsumer
// 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 authtypes.Params,
) error {
// support for ethereum ECDSA secp256k1 keys
_, ok := sig.PubKey.(*ethsecp256k1.PubKey)
if ok {
meter.ConsumeGas(secp256k1VerifyCost, "ante verify: eth_secp256k1")
return nil
}
return authante.DefaultSigVerificationGasConsumer(meter, sig, params)
}

View File

@ -1,11 +0,0 @@
/*Package ante defines the SDK auth module's AnteHandler as well as an internal
AnteHandler for an Ethereum transaction (i.e MsgEthereumTx).
During CheckTx, the transaction is passed through a series of
pre-message execution validation checks such as signature and account
verification in addition to minimum fees being checked. Otherwise, during
DeliverTx, the transaction is simply passed to the EVM which will also
perform the same series of checks. The distinction is made in CheckTx to
prevent spam and DoS attacks.
*/
package ante

View File

@ -1,534 +0,0 @@
package ante
import (
"errors"
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
ethermint "github.com/tharsis/ethermint/types"
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
"github.com/tharsis/ethermint/x/evm/statedb"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
// EthSigVerificationDecorator validates an ethereum signatures
type EthSigVerificationDecorator struct {
evmKeeper EVMKeeper
}
// NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator
func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator {
return EthSigVerificationDecorator{
evmKeeper: ek,
}
}
// AnteHandle validates checks that the registered chain id is the same as the one on the message, and
// that the signer address matches the one defined on the message.
// It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work.
// Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user
// won't see the error message.
func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
chainID := esvd.evmKeeper.ChainID()
params := esvd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(chainID)
blockNum := big.NewInt(ctx.BlockHeight())
signer := ethtypes.MakeSigner(ethCfg, blockNum)
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
sender, err := signer.Sender(msgEthTx.AsTransaction())
if err != nil {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrorInvalidSigner,
"couldn't retrieve sender address ('%s') from the ethereum transaction: %s",
msgEthTx.From,
err.Error(),
)
}
// set up the sender to the transaction field if not already
msgEthTx.From = sender.Hex()
}
return next(ctx, tx, simulate)
}
// EthAccountVerificationDecorator validates an account balance checks
type EthAccountVerificationDecorator struct {
ak evmtypes.AccountKeeper
bankKeeper evmtypes.BankKeeper
evmKeeper EVMKeeper
}
// NewEthAccountVerificationDecorator creates a new EthAccountVerificationDecorator
func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, bankKeeper evmtypes.BankKeeper, ek EVMKeeper) EthAccountVerificationDecorator {
return EthAccountVerificationDecorator{
ak: ak,
bankKeeper: bankKeeper,
evmKeeper: ek,
}
}
// AnteHandle validates checks that the sender balance is greater than the total transaction cost.
// The account will be set to store if it doesn't exis, i.e cannot be found on store.
// This AnteHandler decorator will fail if:
// - any of the msgs is not a MsgEthereumTx
// - from address is empty
// - account balance is lower than the transaction cost
func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if !ctx.IsCheckTx() {
return next(ctx, tx, simulate)
}
for i, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to unpack tx data any for tx %d", i)
}
// sender address should be in the tx cache from the previous AnteHandle call
from := msgEthTx.GetFrom()
if from.Empty() {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "from address cannot be empty")
}
// check whether the sender address is EOA
fromAddr := common.BytesToAddress(from)
acct := avd.evmKeeper.GetAccount(ctx, fromAddr)
if acct == nil {
acc := avd.ak.NewAccountWithAddress(ctx, from)
avd.ak.SetAccount(ctx, acc)
acct = statedb.NewEmptyAccount()
} else if acct.IsContract() {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
"the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
}
if err := evmkeeper.CheckSenderBalance(sdk.NewIntFromBigInt(acct.Balance), txData); err != nil {
return ctx, sdkerrors.Wrap(err, "failed to check sender balance")
}
}
return next(ctx, tx, simulate)
}
// EthGasConsumeDecorator validates enough intrinsic gas for the transaction and
// gas consumption.
type EthGasConsumeDecorator struct {
evmKeeper EVMKeeper
maxGasWanted uint64
}
// NewEthGasConsumeDecorator creates a new EthGasConsumeDecorator
func NewEthGasConsumeDecorator(
evmKeeper EVMKeeper,
maxGasWanted uint64,
) EthGasConsumeDecorator {
return EthGasConsumeDecorator{
evmKeeper,
maxGasWanted,
}
}
// AnteHandle validates that the Ethereum tx message has enough to cover intrinsic gas
// (during CheckTx only) and that the sender has enough balance to pay for the gas cost.
//
// Intrinsic gas for a transaction is the amount of gas that the transaction uses before the
// transaction is executed. The gas is a constant value plus any cost inccured by additional bytes
// of data supplied with the transaction.
//
// This AnteHandler decorator will fail if:
// - the message is not a MsgEthereumTx
// - sender account cannot be found
// - transaction's gas limit is lower than the intrinsic gas
// - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
// - transaction or block gas meter runs out of gas
// - sets the gas meter limit
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
params := egcd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(egcd.evmKeeper.ChainID())
blockHeight := big.NewInt(ctx.BlockHeight())
homestead := ethCfg.IsHomestead(blockHeight)
istanbul := ethCfg.IsIstanbul(blockHeight)
london := ethCfg.IsLondon(blockHeight)
evmDenom := params.EvmDenom
gasWanted := uint64(0)
var events sdk.Events
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
}
if ctx.IsCheckTx() {
// We can't trust the tx gas limit, because we'll refund the unused gas.
if txData.GetGas() > egcd.maxGasWanted {
gasWanted += egcd.maxGasWanted
} else {
gasWanted += txData.GetGas()
}
} else {
gasWanted += txData.GetGas()
}
fees, err := egcd.evmKeeper.DeductTxCostsFromUserBalance(
ctx,
*msgEthTx,
txData,
evmDenom,
homestead,
istanbul,
london,
)
if err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to deduct transaction costs from user balance")
}
events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String())))
}
// TODO: change to typed events
ctx.EventManager().EmitEvents(events)
// TODO: deprecate after https://github.com/cosmos/cosmos-sdk/issues/9514 is fixed on SDK
blockGasLimit := ethermint.BlockGasLimit(ctx)
// NOTE: safety check
if blockGasLimit > 0 {
// generate a copy of the gas pool (i.e block gas meter) to see if we've run out of gas for this block
// if current gas consumed is greater than the limit, this funcion panics and the error is recovered on the Baseapp
gasPool := sdk.NewGasMeter(blockGasLimit)
gasPool.ConsumeGas(ctx.GasMeter().GasConsumedToLimit(), "gas pool check")
}
// Set ctx.GasMeter with a limit of GasWanted (gasLimit)
gasConsumed := ctx.GasMeter().GasConsumed()
ctx = ctx.WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted))
ctx.GasMeter().ConsumeGas(gasConsumed, "copy gas consumed")
// we know that we have enough gas on the pool to cover the intrinsic gas
return next(ctx, tx, simulate)
}
// CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block
// context rules.
type CanTransferDecorator struct {
evmKeeper EVMKeeper
}
// NewCanTransferDecorator creates a new CanTransferDecorator instance.
func NewCanTransferDecorator(evmKeeper EVMKeeper) CanTransferDecorator {
return CanTransferDecorator{
evmKeeper: evmKeeper,
}
}
// AnteHandle creates an EVM from the message and calls the BlockContext CanTransfer function to
// see if the address can execute the transaction.
func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
params := ctd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(ctd.evmKeeper.ChainID())
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight()))
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
baseFee := ctd.evmKeeper.BaseFee(ctx, ethCfg)
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
if err != nil {
return ctx, sdkerrors.Wrapf(
err,
"failed to create an ethereum core.Message from signer %T", signer,
)
}
// NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below
cfg := &evmtypes.EVMConfig{
ChainConfig: ethCfg,
Params: params,
CoinBase: common.Address{},
BaseFee: baseFee,
}
stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())))
evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB)
// check that caller has enough balance to cover asset transfer for **topmost** call
// NOTE: here the gas consumed is from the context with the infinite gas meter
if coreMsg.Value().Sign() > 0 && !evm.Context.CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFunds,
"failed to transfer %s from address %s using the EVM block context transfer function",
coreMsg.Value(),
coreMsg.From(),
)
}
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) {
if baseFee == nil {
return ctx, sdkerrors.Wrap(
evmtypes.ErrInvalidBaseFee,
"base fee is supported but evm block context value is nil",
)
}
if coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFee,
"max fee per gas less than block base fee (%s < %s)",
coreMsg.GasFeeCap(), baseFee,
)
}
}
}
return next(ctx, tx, simulate)
}
// EthIncrementSenderSequenceDecorator increments the sequence of the signers.
type EthIncrementSenderSequenceDecorator struct {
ak evmtypes.AccountKeeper
}
// NewEthIncrementSenderSequenceDecorator creates a new EthIncrementSenderSequenceDecorator.
func NewEthIncrementSenderSequenceDecorator(ak evmtypes.AccountKeeper) EthIncrementSenderSequenceDecorator {
return EthIncrementSenderSequenceDecorator{
ak: ak,
}
}
// AnteHandle handles incrementing the sequence of the signer (i.e sender). If the transaction is a
// contract creation, the nonce will be incremented during the transaction execution and not within
// this AnteHandler decorator.
func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
for _, msg := range tx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
}
// increase sequence of sender
acc := issd.ak.GetAccount(ctx, msgEthTx.GetFrom())
if acc == nil {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrUnknownAddress,
"account %s is nil", common.BytesToAddress(msgEthTx.GetFrom().Bytes()),
)
}
nonce := acc.GetSequence()
// we merged the nonce verification to nonce increment, so when tx includes multiple messages
// with same sender, they'll be accepted.
if txData.GetNonce() != nonce {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInvalidSequence,
"invalid nonce; got %d, expected %d", txData.GetNonce(), nonce,
)
}
if err := acc.SetSequence(nonce + 1); err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
}
issd.ak.SetAccount(ctx, acc)
}
return next(ctx, tx, simulate)
}
// EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures
type EthValidateBasicDecorator struct {
evmKeeper EVMKeeper
}
// NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator
func NewEthValidateBasicDecorator(ek EVMKeeper) EthValidateBasicDecorator {
return EthValidateBasicDecorator{
evmKeeper: ek,
}
}
// AnteHandle handles basic validation of tx
func (vbd EthValidateBasicDecorator) 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)
}
err := tx.ValidateBasic()
// ErrNoSignatures is fine with eth tx
if err != nil && !errors.Is(err, sdkerrors.ErrNoSignatures) {
return ctx, sdkerrors.Wrap(err, "tx basic validation failed")
}
// For eth type cosmos tx, some fields should be veified as zero values,
// since we will only verify the signature against the hash of the MsgEthereumTx.Data
if wrapperTx, ok := tx.(protoTxProvider); ok {
protoTx := wrapperTx.GetProtoTx()
body := protoTx.Body
if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty")
}
if len(body.ExtensionOptions) != 1 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1")
}
txFee := sdk.Coins{}
txGasLimit := uint64(0)
for _, msg := range protoTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txGasLimit += msgEthTx.GetGas()
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, sdkerrors.Wrap(err, "failed to unpack MsgEthereumTx Data")
}
params := vbd.evmKeeper.GetParams(ctx)
chainID := vbd.evmKeeper.ChainID()
ethCfg := params.ChainConfig.EthereumConfig(chainID)
baseFee := vbd.evmKeeper.BaseFee(ctx, ethCfg)
if baseFee == nil && txData.TxType() == ethtypes.DynamicFeeTxType {
return ctx, sdkerrors.Wrap(ethtypes.ErrTxTypeNotSupported, "dynamic fee tx not supported")
}
txFee = txFee.Add(sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(txData.Fee())))
}
authInfo := protoTx.AuthInfo
if len(authInfo.SignerInfos) > 0 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty")
}
if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty")
}
if !authInfo.Fee.Amount.IsEqual(txFee) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee Amount (%s != %s)", authInfo.Fee.Amount, txFee)
}
if authInfo.Fee.GasLimit != txGasLimit {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee GasLimit (%d != %d)", authInfo.Fee.GasLimit, txGasLimit)
}
sigs := protoTx.Signatures
if len(sigs) > 0 {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty")
}
}
return next(ctx, tx, simulate)
}
// EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption
// by setting the gas meter to infinite
type EthSetupContextDecorator struct {
evmKeeper EVMKeeper
}
func NewEthSetUpContextDecorator(evmKeeper EVMKeeper) EthSetupContextDecorator {
return EthSetupContextDecorator{
evmKeeper: evmKeeper,
}
}
func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
// all transactions must implement GasTx
_, ok := tx.(authante.GasTx)
if !ok {
return newCtx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
}
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
// Reset transient gas used to prepare the execution of current cosmos tx.
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
esc.evmKeeper.ResetTransientGasUsed(ctx)
return next(newCtx, tx, simulate)
}
// EthMempoolFeeDecorator will check if the transaction's effective 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 EthMempoolFeeDecorator struct {
evmKeeper EVMKeeper
}
func NewEthMempoolFeeDecorator(ek EVMKeeper) EthMempoolFeeDecorator {
return EthMempoolFeeDecorator{
evmKeeper: ek,
}
}
// AnteHandle ensures 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.
// It only do the check if london hardfork not enabled or feemarket not enabled, because in that case feemarket will take over the task.
func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
if ctx.IsCheckTx() && !simulate {
params := mfd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(mfd.evmKeeper.ChainID())
baseFee := mfd.evmKeeper.BaseFee(ctx, ethCfg)
if baseFee == nil {
for _, msg := range tx.GetMsgs() {
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
evmDenom := params.EvmDenom
feeAmt := ethMsg.GetFee()
glDec := sdk.NewDec(int64(ethMsg.GetGas()))
requiredFee := ctx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)
if sdk.NewDecFromBigInt(feeAmt).LT(requiredFee) {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeAmt, requiredFee)
}
}
}
}
return next(ctx, tx, simulate)
}

View File

@ -1,105 +0,0 @@
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"
"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"
ibcante "github.com/cosmos/ibc-go/v3/modules/core/ante"
ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
// HandlerOptions extend the SDK's AnteHandler options by requiring the IBC
// channel keeper, EVM Keeper and Fee Market Keeper.
type HandlerOptions struct {
AccountKeeper evmtypes.AccountKeeper
BankKeeper evmtypes.BankKeeper
IBCKeeper *ibckeeper.Keeper
FeeMarketKeeper evmtypes.FeeMarketKeeper
EvmKeeper EVMKeeper
FeegrantKeeper ante.FeegrantKeeper
SignModeHandler authsigning.SignModeHandler
SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error
MaxTxGasWanted uint64
}
func (options HandlerOptions) Validate() error {
if options.AccountKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler")
}
if options.BankKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for AnteHandler")
}
if options.SignModeHandler == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder")
}
if options.FeeMarketKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "fee market keeper is required for AnteHandler")
}
if options.EvmKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "evm keeper is required for AnteHandler")
}
return nil
}
func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first
NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against minimal-gas-prices
NewEthValidateBasicDecorator(options.EvmKeeper),
NewEthSigVerificationDecorator(options.EvmKeeper),
NewEthAccountVerificationDecorator(options.AccountKeeper, options.BankKeeper, options.EvmKeeper),
NewEthGasConsumeDecorator(options.EvmKeeper, options.MaxTxGasWanted),
NewCanTransferDecorator(options.EvmKeeper),
NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), // innermost AnteDecorator.
)
}
func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
RejectMessagesDecorator{}, // reject MsgEthereumTxs
ante.NewSetUpContextDecorator(),
ante.NewRejectExtensionOptionsDecorator(),
ante.NewMempoolFeeDecorator(),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
ante.NewValidateMemoDecorator(options.AccountKeeper),
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper),
// SetPubKeyDecorator must be called before all signature verification decorators
ante.NewSetPubKeyDecorator(options.AccountKeeper),
ante.NewValidateSigCountDecorator(options.AccountKeeper),
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
ibcante.NewAnteDecorator(options.IBCKeeper),
)
}
func newCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler {
return sdk.ChainAnteDecorators(
RejectMessagesDecorator{}, // reject MsgEthereumTxs
ante.NewSetUpContextDecorator(),
// NOTE: extensions option decorator removed
// ante.NewRejectExtensionOptionsDecorator(),
ante.NewMempoolFeeDecorator(),
ante.NewValidateBasicDecorator(),
ante.NewTxTimeoutHeightDecorator(),
ante.NewValidateMemoDecorator(options.AccountKeeper),
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper),
// SetPubKeyDecorator must be called before all signature verification decorators
ante.NewSetPubKeyDecorator(options.AccountKeeper),
ante.NewValidateSigCountDecorator(options.AccountKeeper),
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer),
// Note: signature verification uses EIP instead of the cosmos signature validator
NewEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
ibcante.NewAnteDecorator(options.IBCKeeper),
)
}

View File

@ -1,25 +0,0 @@
package ante
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
// RejectMessagesDecorator prevents invalid msg types from being executed
type RejectMessagesDecorator struct{}
// AnteHandle rejects messages that requires ethereum-specific authentication.
// For example `MsgEthereumTx` requires fee to be deducted in the antehandler in
// order to perform the refund.
func (rmd RejectMessagesDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
for _, msg := range tx.GetMsgs() {
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
return ctx, sdkerrors.Wrapf(
sdkerrors.ErrInvalidType,
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
)
}
}
return next(ctx, tx, simulate)
}

View File

@ -11,27 +11,32 @@ import (
"github.com/rakyll/statik/fs"
"github.com/spf13/cast"
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/tharsis/ethermint/app/middleware"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
"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/db"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
"github.com/cosmos/cosmos-sdk/server/config"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/simapp"
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/store/streaming"
storetypes "github.com/cosmos/cosmos-sdk/store/v2alpha1"
"github.com/cosmos/cosmos-sdk/store/v2alpha1/multi"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authmiddleware "github.com/cosmos/cosmos-sdk/x/auth/middleware"
authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
@ -62,8 +67,10 @@ import (
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
"github.com/cosmos/cosmos-sdk/x/gov"
govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
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"
"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"
@ -83,6 +90,10 @@ import (
upgradekeeper "github.com/cosmos/cosmos-sdk/x/upgrade/keeper"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
"github.com/cosmos/ibc-go/v3/modules/apps/transfer"
ibctransferkeeper "github.com/cosmos/ibc-go/v3/modules/apps/transfer/keeper"
ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"
@ -96,13 +107,12 @@ 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"
"github.com/tharsis/ethermint/x/evm"
evmrest "github.com/tharsis/ethermint/x/evm/client/rest"
// evmrest "github.com/tharsis/ethermint/x/evm/client/rest"
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
"github.com/tharsis/ethermint/x/feemarket"
feemarketkeeper "github.com/tharsis/ethermint/x/feemarket/keeper"
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
@ -149,8 +159,8 @@ var (
mint.AppModuleBasic{},
distr.AppModuleBasic{},
gov.NewAppModuleBasic(
paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.ProposalHandler, upgradeclient.CancelProposalHandler,
ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler,
[]govclient.ProposalHandler{paramsclient.ProposalHandler, distrclient.ProposalHandler, upgradeclient.LegacyProposalHandler, upgradeclient.LegacyCancelProposalHandler,
ibcclientclient.UpdateClientProposalHandler, ibcclientclient.UpgradeProposalHandler},
),
params.AppModuleBasic{},
crisis.AppModuleBasic{},
@ -181,7 +191,6 @@ var (
govtypes.ModuleName: {authtypes.Burner},
ibctransfertypes.ModuleName: {authtypes.Minter, authtypes.Burner},
evmtypes.ModuleName: {authtypes.Minter, authtypes.Burner}, // used for secure addition and subtraction of balance using module account
auctiontypes.ModuleName: nil,
auctiontypes.AuctionBurnModuleAccountName: nil,
nameservicetypes.ModuleName: nil,
@ -210,13 +219,14 @@ type EthermintApp struct {
cdc *codec.LegacyAmino
appCodec codec.Codec
interfaceRegistry types.InterfaceRegistry
MsgSvcRouter *authmiddleware.MsgServiceRouter
LegacyRouter sdk.Router
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]*storetypes.KVStoreKey
tkeys map[string]*storetypes.TransientStoreKey
memKeys map[string]*storetypes.MemoryStoreKey
// keepers
AccountKeeper authkeeper.AccountKeeper
@ -263,7 +273,7 @@ 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,
@ -271,31 +281,19 @@ func NewEthermintApp(
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,
minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey,
govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey,
govtypes.StoreKey, paramstypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey,
evidencetypes.StoreKey, capabilitytypes.StoreKey,
feegrant.StoreKey, authzkeeper.StoreKey,
authzkeeper.StoreKey,
// ibc keys
ibchost.StoreKey, ibctransfertypes.StoreKey,
// ethermint keys
@ -310,12 +308,67 @@ 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 := storetypes.StoreKeyToType(key)
if err != nil {
return err
}
if err = config.RegisterSubstore(key, typ); err != nil {
return err
}
}
for _, key := range memKeys {
typ, err := storetypes.StoreKeyToType(key)
if err != nil {
return err
}
if err = config.RegisterSubstore(key, typ); err != nil {
return err
}
}
for _, key := range tkeys {
typ, err := storetypes.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)
evmtypes.RegisterInterfaces(interfaceRegistry)
bApp.SetInterfaceRegistry(interfaceRegistry)
// configure state listening capabilities using AppOptions
// we are doing nothing with the returned streamingServices and waitGroup in this case
if _, _, err := streaming.LoadStreamingServices(bApp, appOpts, appCodec, keys); err != nil {
tmos.Exit(err.Error())
}
app := &EthermintApp{
BaseApp: bApp,
cdc: cdc,
appCodec: appCodec,
interfaceRegistry: interfaceRegistry,
invCheckPeriod: invCheckPeriod,
LegacyRouter: authmiddleware.NewLegacyRouter(),
MsgSvcRouter: authmiddleware.NewMsgServiceRouter(interfaceRegistry),
keys: keys,
tkeys: tkeys,
memKeys: memKeys,
@ -324,7 +377,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])
@ -338,7 +391,7 @@ func NewEthermintApp(
// use custom Ethermint account for contracts
app.AccountKeeper = authkeeper.NewAccountKeeper(
appCodec, keys[authtypes.StoreKey], app.GetSubspace(authtypes.ModuleName), ethermint.ProtoAccount, maccPerms,
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(),
@ -352,7 +405,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),
@ -361,7 +414,7 @@ func NewEthermintApp(
app.GetSubspace(crisistypes.ModuleName), invCheckPeriod, app.BankKeeper, authtypes.FeeCollectorName,
)
app.FeeGrantKeeper = feegrantkeeper.NewKeeper(appCodec, keys[feegrant.StoreKey], app.AccountKeeper)
app.UpgradeKeeper = upgradekeeper.NewKeeper(skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp)
app.UpgradeKeeper = upgradekeeper.NewKeeper(skipUpgradeHeights, keys[upgradetypes.StoreKey], appCodec, homePath, app.BaseApp, authtypes.NewModuleAddress(govtypes.ModuleName).String())
// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
@ -369,7 +422,7 @@ 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))
@ -411,16 +464,22 @@ 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))
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(
@ -438,7 +497,7 @@ func NewEthermintApp(
transferModule := transfer.NewAppModule(app.TransferKeeper)
transferIBCModule := transfer.NewIBCModule(app.TransferKeeper)
// Create static IBC router, add transfer route, then set and seal it
//Create static IBC router, add transfer route, then set and seal it
ibcRouter := porttypes.NewRouter()
ibcRouter.AddRoute(ibctransfertypes.ModuleName, transferIBCModule)
app.IBCKeeper.SetRouter(ibcRouter)
@ -470,7 +529,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),
@ -479,7 +538,6 @@ func NewEthermintApp(
params.NewAppModule(app.ParamsKeeper),
feegrantmodule.NewAppModule(appCodec, app.AccountKeeper, app.BankKeeper, app.FeeGrantKeeper, app.interfaceRegistry),
authzmodule.NewAppModule(appCodec, app.AuthzKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry),
// ibc modules
ibc.NewAppModule(app.IBCKeeper),
transferModule,
@ -592,8 +650,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
@ -608,7 +666,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),
@ -624,49 +682,48 @@ 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
maxGasWanted := cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted))
options := ante.HandlerOptions{
options := middleware.HandlerOptions{
Codec: app.appCodec,
Debug: app.Trace(),
LegacyRouter: app.LegacyRouter,
MsgServiceRouter: app.MsgSvcRouter,
AccountKeeper: app.AccountKeeper,
BankKeeper: app.BankKeeper,
EvmKeeper: app.EvmKeeper,
FeegrantKeeper: app.FeeGrantKeeper,
IBCKeeper: app.IBCKeeper,
FeeMarketKeeper: app.FeeMarketKeeper,
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
SigGasConsumer: middleware.DefaultSigVerificationGasConsumer,
MaxTxGasWanted: maxGasWanted,
TxDecoder: encodingConfig.TxConfig.TxDecoder(),
}
if err := options.Validate(); err != nil {
panic(err)
}
app.SetAnteHandler(ante.NewAnteHandler(options))
app.setTxHandler(options, 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(options middleware.HandlerOptions, txConfig client.TxConfig, indexEventsStr []string) {
indexEvents := map[string]struct{}{}
for _, e := range indexEventsStr {
indexEvents[e] = struct{}{}
}
options.IndexEvents = indexEvents
txHandler := middleware.NewTxHandler(options)
app.SetTxHandler(txHandler)
}
// Name returns the name of the App
func (app *EthermintApp) Name() string { return app.BaseApp.Name() }
@ -692,7 +749,8 @@ 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 app.LoadVersion(height)
return nil
}
// ModuleAccountAddrs returns all the app's module account addresses.
@ -740,21 +798,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) *storetypes.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) *storetypes.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) *storetypes.MemoryStoreKey {
return app.memKeys[storeKey]
}
@ -775,9 +833,9 @@ 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)
// NOTE: in v0.46 legacy routes are removed
// rpc.RegisterRoutes(clientCtx, apiSvr.Router)
// evmrest.RegisterTxRoutes(clientCtx, apiSvr.Router)
// Register new tx routes from grpc-gateway.
authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSvr.GRPCGatewayRouter)
@ -825,7 +883,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,
appCodec codec.BinaryCodec, legacyAmino *codec.LegacyAmino, key, tkey storetypes.StoreKey,
) paramskeeper.Keeper {
paramsKeeper := paramskeeper.NewKeeper(appCodec, legacyAmino, key, tkey)
@ -836,7 +894,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(govv1.ParamKeyTable())
paramsKeeper.Subspace(crisistypes.ModuleName)
paramsKeeper.Subspace(ibctransfertypes.ModuleName)
paramsKeeper.Subspace(ibchost.ModuleName)

View File

@ -1,41 +1,45 @@
package app
import (
"encoding/json"
"os"
"testing"
memdb "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{})
encCfg := encoding.MakeConfig(ModuleBasics)
db := memdb.NewDB()
logger, _ := log.NewDefaultLogger("plain", "info", false)
app := NewTestAppWithCustomOptions(t, false, SetupOptions{
Logger: logger,
DB: db,
InvCheckPeriod: 0,
EncConfig: encCfg,
HomePath: DefaultNodeHome,
SkipUpgradeHeights: map[int64]bool{},
AppOpts: EmptyAppOptions{},
})
genesisState := NewDefaultGenesisState()
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
app.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
AppStateBytes: stateBytes,
},
for acc := range allowedReceivingModAcc {
// check module account is not blocked in bank
require.False(
t,
app.BankKeeper.BlockedAddr(app.AccountKeeper.GetModuleAddress(acc)),
"ensure that blocked addresses %s are properly set in bank keeper",
)
}
app.Commit()
logger2, _ := log.NewDefaultLogger("plain", "info", false)
// 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{})
_, err = app2.ExportAppStateAndValidators(false, []string{})
app2 := NewEthermintApp(logger2, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})
require.NoError(t, app2.Init())
_, err := app2.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}

View File

@ -2,21 +2,21 @@ 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()
logger, _ := log.NewDefaultLogger("plain", "info", false)
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
genesisState := NewDefaultGenesisState()
genesisState := NewDefaultGenesisState(app.appCodec)
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
if err != nil {
b.Fatal(err)
@ -36,7 +36,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(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encoding.MakeConfig(ModuleBasics), simapp.EmptyAppOptions{})
if _, err := app2.ExportAppStateAndValidators(false, []string{}); err != nil {
b.Fatal(err)
}

View File

@ -6,20 +6,18 @@ import (
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/tharsis/ethermint/encoding"
)
// NewDefaultGenesisState generates the default state for the application.
func NewDefaultGenesisState() simapp.GenesisState {
encCfg := encoding.MakeConfig(ModuleBasics)
return ModuleBasics.DefaultGenesis(encCfg.Marshaler)
func NewDefaultGenesisState(cdc codec.JSONCodec) simapp.GenesisState {
return ModuleBasics.DefaultGenesis(cdc)
}
// ExportAppStateAndValidators exports the state of the application for a genesis

View File

@ -1,107 +1,104 @@
package ante
package middleware
import (
context "context"
"fmt"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
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"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
"github.com/cosmos/cosmos-sdk/x/auth/middleware"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
"github.com/tharsis/ethermint/ethereum/eip712"
ethermint "github.com/tharsis/ethermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
var ethermintCodec codec.ProtoCodecMarshaler
func init() {
registry := codectypes.NewInterfaceRegistry()
ethermint.RegisterInterfaces(registry)
ethermintCodec = codec.NewProtoCodec(registry)
}
// Eip712SigVerificationDecorator Verify all signatures for a tx and return an error if any are invalid. Note,
// the Eip712SigVerificationDecorator decorator will not get executed on ReCheck.
// Eip712SigVerificationMiddleware Verify all signatures for a tx and return an error if any are invalid. Note,
// the Eip712SigVerificationMiddleware middleware will not get executed on ReCheck.
//
// CONTRACT: Pubkeys are set in context for all signers before this decorator runs
// CONTRACT: Pubkeys are set in context for all signers before this middleware runs
// CONTRACT: Tx must implement SigVerifiableTx interface
type Eip712SigVerificationDecorator struct {
type Eip712SigVerificationMiddleware struct {
appCodec codec.Codec
next tx.Handler
ak evmtypes.AccountKeeper
signModeHandler authsigning.SignModeHandler
}
// NewEip712SigVerificationDecorator creates a new Eip712SigVerificationDecorator
func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandler authsigning.SignModeHandler) Eip712SigVerificationDecorator {
return Eip712SigVerificationDecorator{
var _ tx.Handler = Eip712SigVerificationMiddleware{}
// NewEip712SigVerificationMiddleware creates a new Eip712SigVerificationMiddleware
func NewEip712SigVerificationMiddleware(appCodec codec.Codec, ak evmtypes.AccountKeeper, signModeHandler authsigning.SignModeHandler) tx.Middleware {
return func(h tx.Handler) tx.Handler {
return Eip712SigVerificationMiddleware{
appCodec: appCodec,
next: h,
ak: ak,
signModeHandler: signModeHandler,
}
}
}
// AnteHandle handles validation of EIP712 signed cosmos txs.
// it is not run on RecheckTx
func (svd Eip712SigVerificationDecorator) 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)
func eipSigVerification(svd Eip712SigVerificationMiddleware, cx context.Context, req tx.Request) (tx.Response, error) {
ctx := sdk.UnwrapSDKContext(cx)
reqTx := req.Tx
sigTx, ok := reqTx.(authsigning.SigVerifiableTx)
if !ok {
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement authsigning.SigVerifiableTx", reqTx)
}
sigTx, ok := tx.(authsigning.SigVerifiableTx)
authSignTx, ok := reqTx.(authsigning.Tx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement authsigning.SigVerifiableTx", tx)
}
authSignTx, ok := tx.(authsigning.Tx)
if !ok {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement the authsigning.Tx interface", tx)
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement the authsigning.Tx interface", reqTx)
}
// 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
return tx.Response{}, err
}
signerAddrs := sigTx.GetSigners()
// EIP712 allows just one signature
if len(sigs) != 1 {
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signers (%d); EIP712 signatures allows just one signature", len(sigs))
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signers (%d); EIP712 signatures allows just one signature", len(sigs))
}
// 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))
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs))
}
// EIP712 has just one signature, avoid looping here and only read index 0
i := 0
sig := sigs[i]
acc, err := authante.GetSignerAcc(ctx, svd.ak, signerAddrs[i])
acc, err := middleware.GetSignerAcc(ctx, svd.ak, signerAddrs[i])
if err != nil {
return ctx, err
return tx.Response{}, err
}
// retrieve pubkey
pubKey := acc.GetPubKey()
if !simulate && pubKey == nil {
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
if pubKey == nil {
return tx.Response{}, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
}
// Check account sequence number.
if sig.Sequence != acc.GetSequence() {
return ctx, sdkerrors.Wrapf(
return tx.Response{}, sdkerrors.Wrapf(
sdkerrors.ErrWrongSequence,
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
)
@ -122,21 +119,45 @@ func (svd Eip712SigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx,
Sequence: acc.GetSequence(),
}
if simulate {
return next(ctx, tx, simulate)
}
if err := VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, authSignTx); err != nil {
if err := VerifySignature(svd.appCodec, pubKey, signerData, sig.Data, svd.signModeHandler, authSignTx); err != nil {
errMsg := fmt.Errorf("signature verification failed; please verify account number (%d) and chain-id (%s): %w", accNum, chainID, err)
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg.Error())
return tx.Response{}, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg.Error())
}
return next(ctx, tx, simulate)
return tx.Response{}, nil
}
// CheckTx implements tx.Handler
func (svd Eip712SigVerificationMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
if _, err := eipSigVerification(svd, ctx, req); err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, err
}
return svd.next.CheckTx(ctx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (svd Eip712SigVerificationMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
if _, err := eipSigVerification(svd, ctx, req); err != nil {
return tx.Response{}, err
}
return svd.next.DeliverTx(ctx, req)
}
// SimulateTx implements tx.Handler
func (svd Eip712SigVerificationMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
if _, err := eipSigVerification(svd, ctx, req); err != nil {
return tx.Response{}, err
}
return svd.next.SimulateTx(ctx, req)
}
// VerifySignature verifies a transaction signature contained in SignatureData abstracting over different signing modes
// and single vs multi-signatures.
func VerifySignature(
appCodec codec.Codec,
pubKey cryptotypes.PubKey,
signerData authsigning.SignerData,
sigData signing.SignatureData,
@ -171,7 +192,7 @@ func VerifySignature(
Amount: tx.GetFee(),
Gas: tx.GetGas(),
},
msgs, tx.GetMemo(),
msgs, tx.GetMemo(), tx.GetTip(),
)
signerChainID, err := ethermint.ParseChainID(signerData.ChainID)
@ -179,7 +200,7 @@ func VerifySignature(
return sdkerrors.Wrapf(err, "failed to parse chainID: %s", signerData.ChainID)
}
txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx)
txWithExtensions, ok := tx.(middleware.HasExtensionOptionsTx)
if !ok {
return sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, "tx doesnt contain any extensions")
}
@ -190,7 +211,7 @@ func VerifySignature(
var optIface ethermint.ExtensionOptionsWeb3TxI
if err := ethermintCodec.UnpackAny(opts[0], &optIface); err != nil {
if err := appCodec.UnpackAny(opts[0], &optIface); err != nil {
return sdkerrors.Wrap(err, "failed to proto-unpack ExtensionOptionsWeb3Tx")
}
@ -215,7 +236,7 @@ func VerifySignature(
FeePayer: feePayer,
}
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
typedData, err := eip712.WrapTxToTypedData(appCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
if err != nil {
return sdkerrors.Wrap(err, "failed to pack tx data in EIP712 object")
}

757
app/middleware/eth.go Normal file
View File

@ -0,0 +1,757 @@
package middleware
import (
"context"
"errors"
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/middleware"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethermint "github.com/tharsis/ethermint/types"
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
"github.com/tharsis/ethermint/x/evm/statedb"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
// EthSetupContextMiddleware is adapted from SetUpContextMiddleware from cosmos-sdk, it ignores gas consumption
// by setting the gas meter to infinite
type EthSetupContextMiddleware struct {
next tx.Handler
evmKeeper EVMKeeper
}
// gasContext returns a new context with a gas meter set from a given context.
func gasContext(ctx sdk.Context, tx sdk.Tx, isSimulate bool) (sdk.Context, error) {
// all transactions must implement GasTx
gasTx, ok := tx.(middleware.GasTx)
if !ok {
// Set a gas meter with limit 0 as to prevent an infinite gas meter attack
// during runTx.
newCtx := setGasMeter(ctx, 0, isSimulate)
return newCtx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
}
return setGasMeter(ctx, gasTx.GetGas(), isSimulate), nil
}
// setGasMeter returns a new context with a gas meter set from a given context.
func setGasMeter(ctx sdk.Context, gasLimit uint64, simulate bool) 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(ethermint.NewInfiniteGasMeterWithLimit(gasLimit))
}
// CheckTx implements tx.Handler
func (esc EthSetupContextMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
if err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, err
}
// Reset transient gas used to prepare the execution of current cosmos tx.
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
esc.evmKeeper.ResetTransientGasUsed(sdkCtx)
return esc.next.CheckTx(sdkCtx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (esc EthSetupContextMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
if err != nil {
return tx.Response{}, err
}
// Reset transient gas used to prepare the execution of current cosmos tx.
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
esc.evmKeeper.ResetTransientGasUsed(sdkCtx)
return esc.next.DeliverTx(sdkCtx, req)
}
// SimulateTx implements tx.Handler
func (esc EthSetupContextMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
if err != nil {
return tx.Response{}, err
}
// Reset transient gas used to prepare the execution of current cosmos tx.
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
esc.evmKeeper.ResetTransientGasUsed(sdkCtx)
return esc.next.SimulateTx(sdkCtx, req)
}
var _ tx.Handler = EthSetupContextMiddleware{}
func NewEthSetUpContextMiddleware(evmKeeper EVMKeeper) tx.Middleware {
return func(txh tx.Handler) tx.Handler {
return EthSetupContextMiddleware{
next: txh,
evmKeeper: evmKeeper,
}
}
}
// EthMempoolFeeMiddleware will check if the transaction's effective fee is at least as large
// as the local validator's minimum gasFee (defined in validator config).
// If fee is too low, Middleware 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 MempoolFeeMiddleware
type EthMempoolFeeMiddleware struct {
next tx.Handler
evmKeeper EVMKeeper
}
// CheckTx implements tx.Handler
func (mfd EthMempoolFeeMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
sdkCtx := sdk.UnwrapSDKContext(ctx)
params := mfd.evmKeeper.GetParams(sdkCtx)
ethCfg := params.ChainConfig.EthereumConfig(mfd.evmKeeper.ChainID())
baseFee := mfd.evmKeeper.BaseFee(sdkCtx, ethCfg)
if baseFee == nil {
for _, msg := range req.Tx.GetMsgs() {
ethMsg, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
evmDenom := params.EvmDenom
feeAmt := ethMsg.GetFee()
glDec := sdk.NewDec(int64(ethMsg.GetGas()))
requiredFee := sdkCtx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)
if sdk.NewDecFromBigInt(feeAmt).LT(requiredFee) {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeAmt, requiredFee)
}
}
}
return mfd.next.CheckTx(ctx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (mfd EthMempoolFeeMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return mfd.next.DeliverTx(ctx, req)
}
// SimulateTx implements tx.Handler
func (mfd EthMempoolFeeMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return mfd.next.SimulateTx(ctx, req)
}
var _ tx.Handler = EthMempoolFeeMiddleware{}
func NewEthMempoolFeeMiddleware(ek EVMKeeper) tx.Middleware {
return func(txh tx.Handler) tx.Handler {
return EthMempoolFeeMiddleware{
next: txh,
evmKeeper: ek,
}
}
}
// EthValidateBasicMiddleware is adapted from ValidateBasicMiddleware from cosmos-sdk, it ignores ErrNoSignatures
type EthValidateBasicMiddleware struct {
next tx.Handler
evmKeeper EVMKeeper
}
// CheckTx implements tx.Handler
func (vbd EthValidateBasicMiddleware) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
ctx := sdk.UnwrapSDKContext(cx)
reqTx := req.Tx
// no need to validate basic on recheck tx, call next antehandler
if ctx.IsReCheckTx() {
return vbd.next.CheckTx(ctx, req, checkReq)
}
err := reqTx.ValidateBasic()
// ErrNoSignatures is fine with eth tx
if err != nil && !errors.Is(err, sdkerrors.ErrNoSignatures) {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(err, "tx basic validation failed")
}
// For eth type cosmos tx, some fields should be verified as zero values,
// since we will only verify the signature against the hash of the MsgEthereumTx.Data
if wrapperTx, ok := reqTx.(protoTxProvider); ok {
protoTx := wrapperTx.GetProtoTx()
body := protoTx.Body
if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty")
}
if len(body.ExtensionOptions) != 1 {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1")
}
txFee := sdk.Coins{}
txGasLimit := uint64(0)
for _, msg := range protoTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txGasLimit += msgEthTx.GetGas()
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(err, "failed to unpack MsgEthereumTx Data")
}
params := vbd.evmKeeper.GetParams(ctx)
chainID := vbd.evmKeeper.ChainID()
ethCfg := params.ChainConfig.EthereumConfig(chainID)
baseFee := vbd.evmKeeper.BaseFee(ctx, ethCfg)
if baseFee == nil && txData.TxType() == ethtypes.DynamicFeeTxType {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(ethtypes.ErrTxTypeNotSupported, "dynamic fee tx not supported")
}
txFee = txFee.Add(sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(txData.Fee())))
}
authInfo := protoTx.AuthInfo
if len(authInfo.SignerInfos) > 0 {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty")
}
if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty")
}
if !authInfo.Fee.Amount.IsEqual(txFee) {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee Amount (%s != %s)", authInfo.Fee.Amount, txFee)
}
if authInfo.Fee.GasLimit != txGasLimit {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid AuthInfo Fee GasLimit (%d != %d)", authInfo.Fee.GasLimit, txGasLimit)
}
sigs := protoTx.Signatures
if len(sigs) > 0 {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty")
}
}
return vbd.next.CheckTx(ctx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (vbd EthValidateBasicMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return vbd.next.DeliverTx(ctx, req)
}
// SimulateTx implements tx.Handler
func (vbd EthValidateBasicMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return vbd.next.SimulateTx(ctx, req)
}
var _ tx.Handler = EthValidateBasicMiddleware{}
// NewEthValidateBasicMiddleware creates a new EthValidateBasicMiddleware
func NewEthValidateBasicMiddleware(ek EVMKeeper) tx.Middleware {
return func(h tx.Handler) tx.Handler {
return EthValidateBasicMiddleware{
next: h,
evmKeeper: ek,
}
}
}
// EthSigVerificationMiddleware validates an ethereum signatures
type EthSigVerificationMiddleware struct {
next tx.Handler
evmKeeper EVMKeeper
}
func ethSigVerificationMiddleware(esvd EthSigVerificationMiddleware, cx context.Context, req tx.Request) (tx.Response, error) {
chainID := esvd.evmKeeper.ChainID()
ctx := sdk.UnwrapSDKContext(cx)
reqTx := req.Tx
params := esvd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(chainID)
blockNum := big.NewInt(ctx.BlockHeight())
signer := ethtypes.MakeSigner(ethCfg, blockNum)
for _, msg := range reqTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
sender, err := signer.Sender(msgEthTx.AsTransaction())
if err != nil {
return tx.Response{}, sdkerrors.Wrapf(
sdkerrors.ErrorInvalidSigner,
"couldn't retrieve sender address ('%s') from the ethereum transaction: %s",
msgEthTx.From,
err.Error(),
)
}
// set up the sender to the transaction field if not already
msgEthTx.From = sender.Hex()
}
return tx.Response{}, nil
}
// CheckTx implements tx.Handler
func (esvd EthSigVerificationMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
if _, err := ethSigVerificationMiddleware(esvd, ctx, req); err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, err
}
return esvd.next.CheckTx(ctx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (esvd EthSigVerificationMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
if _, err := ethSigVerificationMiddleware(esvd, ctx, req); err != nil {
return tx.Response{}, err
}
return esvd.next.DeliverTx(ctx, req)
}
// SimulateTx implements tx.Handler
func (esvd EthSigVerificationMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
if _, err := ethSigVerificationMiddleware(esvd, ctx, req); err != nil {
return tx.Response{}, err
}
return esvd.next.SimulateTx(ctx, req)
}
var _ tx.Handler = EthSigVerificationMiddleware{}
// NewEthSigVerificationMiddleware creates a new EthSigVerificationMiddleware
func NewEthSigVerificationMiddleware(ek EVMKeeper) tx.Middleware {
return func(h tx.Handler) tx.Handler {
return EthSigVerificationMiddleware{
next: h,
evmKeeper: ek,
}
}
}
// EthAccountVerificationMiddleware validates an account balance checks
type EthAccountVerificationMiddleware struct {
next tx.Handler
ak evmtypes.AccountKeeper
bankKeeper evmtypes.BankKeeper
evmKeeper EVMKeeper
}
// CheckTx implements tx.Handler
func (avd EthAccountVerificationMiddleware) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
reqTx := req.Tx
ctx := sdk.UnwrapSDKContext(cx)
if !ctx.IsCheckTx() {
return avd.next.CheckTx(cx, req, checkReq)
}
for i, msg := range reqTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(err, "failed to unpack tx data any for tx %d", i)
}
// sender address should be in the tx cache from the previous AnteHandle call
from := msgEthTx.GetFrom()
if from.Empty() {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "from address cannot be empty")
}
// check whether the sender address is EOA
fromAddr := common.BytesToAddress(from)
acct := avd.evmKeeper.GetAccount(ctx, fromAddr)
if acct == nil {
acc := avd.ak.NewAccountWithAddress(ctx, from)
avd.ak.SetAccount(ctx, acc)
acct = statedb.NewEmptyAccount()
} else if acct.IsContract() {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
"the sender is not EOA: address %s, codeHash <%s>", fromAddr, acct.CodeHash)
}
if err := evmkeeper.CheckSenderBalance(sdk.NewIntFromBigInt(acct.Balance), txData); err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(err, "failed to check sender balance")
}
}
return avd.next.CheckTx(ctx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (avd EthAccountVerificationMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return avd.next.DeliverTx(ctx, req)
}
// SimulateTx implements tx.Handler
func (avd EthAccountVerificationMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return avd.next.SimulateTx(ctx, req)
}
var _ tx.Handler = EthAccountVerificationMiddleware{}
// NewEthAccountVerificationMiddleware creates a new EthAccountVerificationMiddleware
func NewEthAccountVerificationMiddleware(ak evmtypes.AccountKeeper, bankKeeper evmtypes.BankKeeper, ek EVMKeeper) tx.Middleware {
return func(h tx.Handler) tx.Handler {
return EthAccountVerificationMiddleware{
next: h,
ak: ak,
bankKeeper: bankKeeper,
evmKeeper: ek,
}
}
}
// EthGasConsumeMiddleware validates enough intrinsic gas for the transaction and
// gas consumption.
type EthGasConsumeMiddleware struct {
next tx.Handler
evmKeeper EVMKeeper
maxGasWanted uint64
}
func ethGasMiddleware(egcd EthGasConsumeMiddleware, cx context.Context, req tx.Request) (context.Context, tx.Response, error) {
ctx := sdk.UnwrapSDKContext(cx)
reqTx := req.Tx
params := egcd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(egcd.evmKeeper.ChainID())
blockHeight := big.NewInt(ctx.BlockHeight())
homestead := ethCfg.IsHomestead(blockHeight)
istanbul := ethCfg.IsIstanbul(blockHeight)
london := ethCfg.IsLondon(blockHeight)
evmDenom := params.EvmDenom
gasWanted := uint64(0)
var events sdk.Events
for _, msg := range reqTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return ctx, tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return ctx, tx.Response{}, sdkerrors.Wrap(err, "failed to unpack tx data")
}
if ctx.IsCheckTx() {
// We can't trust the tx gas limit, because we'll refund the unused gas.
if txData.GetGas() > egcd.maxGasWanted {
gasWanted += egcd.maxGasWanted
} else {
gasWanted += txData.GetGas()
}
} else {
gasWanted += txData.GetGas()
}
fees, err := egcd.evmKeeper.DeductTxCostsFromUserBalance(
ctx,
*msgEthTx,
txData,
evmDenom,
homestead,
istanbul,
london,
)
if err != nil {
return ctx, tx.Response{}, sdkerrors.Wrapf(err, "failed to deduct transaction costs from user balance")
}
events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String())))
}
// TODO: change to typed events
ctx.EventManager().EmitEvents(events)
// TODO: deprecate after https://github.com/cosmos/cosmos-sdk/issues/9514 is fixed on SDK
blockGasLimit := ethermint.BlockGasLimit(ctx)
// NOTE: safety check
if blockGasLimit > 0 {
// generate a copy of the gas pool (i.e block gas meter) to see if we've run out of gas for this block
// if current gas consumed is greater than the limit, this funcion panics and the error is recovered on the Baseapp
gasPool := sdk.NewGasMeter(blockGasLimit)
gasPool.ConsumeGas(ctx.GasMeter().GasConsumedToLimit(), "gas pool check")
}
// Set ctx.GasMeter with a limit of GasWanted (gasLimit)
gasConsumed := ctx.GasMeter().GasConsumed()
ctx = ctx.WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted))
ctx.GasMeter().ConsumeGas(gasConsumed, "copy gas consumed")
return ctx, tx.Response{}, nil
}
// CheckTx implements tx.Handler
func (egcd EthGasConsumeMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
newCtx, _, err := ethGasMiddleware(egcd, ctx, req)
if err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, err
}
return egcd.next.CheckTx(newCtx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (egcd EthGasConsumeMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
newCtx, _, err := ethGasMiddleware(egcd, ctx, req)
if err != nil {
return tx.Response{}, err
}
return egcd.next.DeliverTx(newCtx, req)
}
// SimulateTx implements tx.Handler
func (egcd EthGasConsumeMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
newCtx, _, err := ethGasMiddleware(egcd, ctx, req)
if err != nil {
return tx.Response{}, err
}
return egcd.next.SimulateTx(newCtx, req)
}
var _ tx.Handler = EthGasConsumeMiddleware{}
// NewEthGasConsumeMiddleware creates a new EthGasConsumeMiddleware
func NewEthGasConsumeMiddleware(
evmKeeper EVMKeeper,
maxGasWanted uint64,
) tx.Middleware {
return func(h tx.Handler) tx.Handler {
return EthGasConsumeMiddleware{
h,
evmKeeper,
maxGasWanted,
}
}
}
// CanTransferMiddleware checks if the sender is allowed to transfer funds according to the EVM block
// context rules.
type CanTransferMiddleware struct {
next tx.Handler
evmKeeper EVMKeeper
}
func canTransfer(ctd CanTransferMiddleware, cx context.Context, req tx.Request) (tx.Response, error) {
ctx := sdk.UnwrapSDKContext(cx)
reqTx := req.Tx
params := ctd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(ctd.evmKeeper.ChainID())
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight()))
for _, msg := range reqTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
baseFee := ctd.evmKeeper.BaseFee(ctx, ethCfg)
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
if err != nil {
return tx.Response{}, sdkerrors.Wrapf(
err,
"failed to create an ethereum core.Message from signer %T", signer,
)
}
// NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below
cfg := &evmtypes.EVMConfig{
ChainConfig: ethCfg,
Params: params,
CoinBase: common.Address{},
BaseFee: baseFee,
}
stateDB := statedb.New(ctx, ctd.evmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(ctx.HeaderHash().Bytes())))
evm := ctd.evmKeeper.NewEVM(ctx, coreMsg, cfg, evmtypes.NewNoOpTracer(), stateDB)
// check that caller has enough balance to cover asset transfer for **topmost** call
// NOTE: here the gas consumed is from the context with the infinite gas meter
if coreMsg.Value().Sign() > 0 && !evm.Context.CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
return tx.Response{}, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFunds,
"failed to transfer %s from address %s using the EVM block context transfer function",
coreMsg.Value(),
coreMsg.From(),
)
}
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) {
if baseFee == nil {
return tx.Response{}, sdkerrors.Wrap(
evmtypes.ErrInvalidBaseFee,
"base fee is supported but evm block context value is nil",
)
}
if coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
return tx.Response{}, sdkerrors.Wrapf(
sdkerrors.ErrInsufficientFee,
"max fee per gas less than block base fee (%s < %s)",
coreMsg.GasFeeCap(), baseFee,
)
}
}
}
return tx.Response{}, nil
}
// CheckTx implements tx.Handler
func (ctd CanTransferMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
if _, err := canTransfer(ctd, ctx, req); err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, err
}
return ctd.next.CheckTx(ctx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (ctd CanTransferMiddleware) DeliverTx(cx context.Context, req tx.Request) (tx.Response, error) {
ctx := sdk.UnwrapSDKContext(cx)
if _, err := canTransfer(ctd, ctx, req); err != nil {
return tx.Response{}, err
}
return ctd.next.DeliverTx(ctx, req)
}
// SimulateTx implements tx.Handler
func (ctd CanTransferMiddleware) SimulateTx(cx context.Context, req tx.Request) (tx.Response, error) {
ctx := sdk.UnwrapSDKContext(cx)
if _, err := canTransfer(ctd, ctx, req); err != nil {
return tx.Response{}, err
}
return ctd.next.SimulateTx(ctx, req)
}
var _ tx.Handler = CanTransferMiddleware{}
// NewCanTransferMiddleware creates a new CanTransferMiddleware instance.
func NewCanTransferMiddleware(evmKeeper EVMKeeper) tx.Middleware {
return func(h tx.Handler) tx.Handler {
return CanTransferMiddleware{
next: h,
evmKeeper: evmKeeper,
}
}
}
// EthIncrementSenderSequenceMiddleware increments the sequence of the signers.
type EthIncrementSenderSequenceMiddleware struct {
next tx.Handler
ak evmtypes.AccountKeeper
}
func ethIncrementSenderSequence(issd EthIncrementSenderSequenceMiddleware, cx context.Context, req tx.Request) (tx.Response, error) {
ctx := sdk.UnwrapSDKContext(cx)
reqTx := req.Tx
for _, msg := range reqTx.GetMsgs() {
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
if !ok {
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
}
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
if err != nil {
return tx.Response{}, sdkerrors.Wrap(err, "failed to unpack tx data")
}
// increase sequence of sender
acc := issd.ak.GetAccount(ctx, msgEthTx.GetFrom())
if acc == nil {
return tx.Response{}, sdkerrors.Wrapf(
sdkerrors.ErrUnknownAddress,
"account %s is nil", common.BytesToAddress(msgEthTx.GetFrom().Bytes()),
)
}
nonce := acc.GetSequence()
// we merged the nonce verification to nonce increment, so when tx includes multiple messages
// with same sender, they'll be accepted.
if txData.GetNonce() != nonce {
return tx.Response{}, sdkerrors.Wrapf(
sdkerrors.ErrInvalidSequence,
"invalid nonce; got %d, expected %d", txData.GetNonce(), nonce,
)
}
if err := acc.SetSequence(nonce + 1); err != nil {
return tx.Response{}, sdkerrors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
}
issd.ak.SetAccount(ctx, acc)
}
return tx.Response{}, nil
}
// CheckTx implements tx.Handler
func (issd EthIncrementSenderSequenceMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
if _, err := ethIncrementSenderSequence(issd, ctx, req); err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, err
}
return issd.next.CheckTx(ctx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (issd EthIncrementSenderSequenceMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
if _, err := ethIncrementSenderSequence(issd, ctx, req); err != nil {
return tx.Response{}, err
}
return issd.next.DeliverTx(ctx, req)
}
// SimulateTx implements tx.Handler
func (issd EthIncrementSenderSequenceMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
if _, err := ethIncrementSenderSequence(issd, ctx, req); err != nil {
return tx.Response{}, err
}
return issd.next.SimulateTx(ctx, req)
}
var _ tx.Handler = EthIncrementSenderSequenceMiddleware{}
// NewEthIncrementSenderSequenceMiddleware creates a new EthIncrementSenderSequenceMiddleware.
func NewEthIncrementSenderSequenceMiddleware(ak evmtypes.AccountKeeper) tx.Middleware {
return func(h tx.Handler) tx.Handler {
return EthIncrementSenderSequenceMiddleware{
next: h,
ak: ak,
}
}
}

View File

@ -1,11 +1,13 @@
package ante_test
package middleware_test
import (
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tharsis/ethermint/app/ante"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/middleware"
ante "github.com/tharsis/ethermint/app/middleware"
"github.com/tharsis/ethermint/server/config"
"github.com/tharsis/ethermint/tests"
"github.com/tharsis/ethermint/x/evm/statedb"
@ -14,12 +16,8 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
func nextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
return ctx, nil
}
func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
dec := ante.NewEthSigVerificationDecorator(suite.app.EvmKeeper)
func (suite MiddlewareTestSuite) TestEthSigVerificationDecorator() {
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthSigVerificationMiddleware(suite.app.EvmKeeper))
addr, privKey := tests.NewAddrKey()
signedTx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
@ -46,7 +44,7 @@ func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
for _, tc := range testCases {
suite.Run(tc.name, func() {
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
if tc.expPass {
suite.Require().NoError(err)
@ -57,10 +55,10 @@ func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
}
}
func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
dec := ante.NewEthAccountVerificationDecorator(
func (suite MiddlewareTestSuite) TestNewEthAccountVerificationDecorator() {
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthAccountVerificationMiddleware(
suite.app.AccountKeeper, suite.app.BankKeeper, suite.app.EvmKeeper,
)
))
addr := tests.GenerateAddress()
@ -134,8 +132,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
tc.malleate()
suite.Require().NoError(vmdb.Commit())
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, nextFn)
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx.WithIsCheckTx(tc.checkTx)), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
if tc.expPass {
suite.Require().NoError(err)
} else {
@ -145,10 +142,9 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
}
}
func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
func (suite MiddlewareTestSuite) TestEthNonceVerificationDecorator() {
suite.SetupTest()
dec := ante.NewEthIncrementSenderSequenceDecorator(suite.app.AccountKeeper)
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthIncrementSenderSequenceMiddleware(suite.app.AccountKeeper))
addr := tests.GenerateAddress()
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
@ -190,7 +186,7 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
for _, tc := range testCases {
suite.Run(tc.name, func() {
tc.malleate()
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
if tc.expPass {
suite.Require().NoError(err)
@ -201,8 +197,8 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
}
}
func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
dec := ante.NewEthGasConsumeDecorator(suite.app.EvmKeeper, config.DefaultMaxTxGasWanted)
func (suite MiddlewareTestSuite) TestEthGasConsumeDecorator() {
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthGasConsumeMiddleware(suite.app.EvmKeeper, config.DefaultMaxTxGasWanted))
addr := tests.GenerateAddress()
@ -287,24 +283,24 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {
if tc.expPanic {
suite.Require().Panics(func() {
_, _ = dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewGasMeter(1)), tc.tx, false, nextFn)
_, _, _ = txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewGasMeter(1))), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
})
return
}
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewInfiniteGasMeter()), tc.tx, false, nextFn)
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewInfiniteGasMeter())), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
suite.Require().Equal(tc.gasLimit, ctx.GasMeter().Limit())
})
}
}
func (suite AnteTestSuite) TestCanTransferDecorator() {
dec := ante.NewCanTransferDecorator(suite.app.EvmKeeper)
func (suite MiddlewareTestSuite) TestCanTransferDecorator() {
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewCanTransferMiddleware(suite.app.EvmKeeper))
addr, privKey := tests.NewAddrKey()
@ -376,8 +372,7 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
tc.malleate()
suite.Require().NoError(vmdb.Commit())
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx.WithIsCheckTx(true)), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
if tc.expPass {
suite.Require().NoError(err)
} else {
@ -387,8 +382,8 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
}
}
func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
dec := ante.NewEthIncrementSenderSequenceDecorator(suite.app.AccountKeeper)
func (suite MiddlewareTestSuite) TestEthIncrementSenderSequenceDecorator() {
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthIncrementSenderSequenceMiddleware(suite.app.AccountKeeper))
addr, privKey := tests.NewAddrKey()
contract := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 0, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
@ -455,12 +450,17 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
if tc.expPanic {
suite.Require().Panics(func() {
_, _ = dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
_, _, _ = txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
})
return
}
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
if tc.expPass {
suite.Require().NoError(err)
@ -478,8 +478,8 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {
}
}
func (suite AnteTestSuite) TestEthSetupContextDecorator() {
dec := ante.NewEthSetUpContextDecorator(suite.app.EvmKeeper)
func (suite MiddlewareTestSuite) TestEthSetupContextDecorator() {
txHandler := middleware.ComposeMiddlewares(noopTxHandler, ante.NewEthSetUpContextMiddleware(suite.app.EvmKeeper))
tx := evmtypes.NewTxContract(suite.app.EvmKeeper.ChainID(), 1, big.NewInt(10), 1000, big.NewInt(1), nil, nil, nil, nil)
testCases := []struct {
@ -497,8 +497,7 @@ func (suite AnteTestSuite) TestEthSetupContextDecorator() {
for _, tc := range testCases {
suite.Run(tc.name, func() {
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
_, _, err := txHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.tx}, txtypes.RequestCheckTx{})
if tc.expPass {
suite.Require().NoError(err)
} else {

View File

@ -1,4 +1,4 @@
package ante
package middleware
import (
"math/big"

View File

@ -0,0 +1,116 @@
package middleware
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authmiddleware "github.com/cosmos/cosmos-sdk/x/auth/middleware"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
)
const (
secp256k1VerifyCost uint64 = 21000
)
type txRouter struct {
eth, cosmos, eip712 tx.Handler
}
var _ tx.Handler = txRouter{}
func NewTxHandler(options HandlerOptions) tx.Handler {
return authmiddleware.ComposeMiddlewares(
authmiddleware.NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
authmiddleware.NewTxDecoderMiddleware(options.TxDecoder),
NewTxRouterMiddleware(options),
)
}
func NewTxRouterMiddleware(options HandlerOptions) tx.Middleware {
ethMiddleware := newEthAuthMiddleware(options)
cosmoseip712 := newCosmosMiddlewareEip712(options)
cosmosMiddleware := newCosmosAuthMiddleware(options)
return func(txh tx.Handler) tx.Handler {
return txRouter{
eth: ethMiddleware(txh),
cosmos: cosmosMiddleware(txh),
eip712: cosmoseip712(txh),
}
}
}
// CheckTx implements tx.Handler
func (txh txRouter) route(req tx.Request) (tx.Handler, error) {
txWithExtensions, ok := req.Tx.(authmiddleware.HasExtensionOptionsTx)
if ok {
opts := txWithExtensions.GetExtensionOptions()
if len(opts) > 0 {
var next tx.Handler
switch typeURL := opts[0].GetTypeUrl(); typeURL {
case "/ethermint.evm.v1.ExtensionOptionsEthereumTx":
// handle as *evmtypes.MsgEthereumTx
next = txh.eth
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx":
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation
next = txh.eip712
default:
return nil, sdkerrors.Wrapf(
sdkerrors.ErrUnknownExtensionOptions,
"rejecting tx with unsupported extension option: %s", typeURL,
)
}
return next, nil
}
}
// handle as totally normal Cosmos SDK tx
return txh.cosmos, nil
}
// CheckTx implements tx.Handler
func (txh txRouter) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (res tx.Response, rct tx.ResponseCheckTx, err error) {
next, err := txh.route(req)
if err != nil {
return
}
return next.CheckTx(ctx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (txh txRouter) DeliverTx(ctx context.Context, req tx.Request) (res tx.Response, err error) {
next, err := txh.route(req)
if err != nil {
return
}
return next.DeliverTx(ctx, req)
}
// SimulateTx implements tx.Handler
func (txh txRouter) SimulateTx(ctx context.Context, req tx.Request) (res tx.Response, err error) {
next, err := txh.route(req)
if err != nil {
return
}
return next.SimulateTx(ctx, req)
}
var _ = DefaultSigVerificationGasConsumer
// 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 authtypes.Params,
) error {
// support for ethereum ECDSA secp256k1 keys
_, ok := sig.PubKey.(*ethsecp256k1.PubKey)
if ok {
meter.ConsumeGas(secp256k1VerifyCost, "ante verify: eth_secp256k1")
return nil
}
return authmiddleware.DefaultSigVerificationGasConsumer(meter, sig, params)
}

View File

@ -1,10 +1,13 @@
package ante_test
package middleware_test
import (
"github.com/cosmos/cosmos-sdk/types/tx/signing"
"math/big"
"strings"
"github.com/cosmos/cosmos-sdk/types/tx"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/core/types"
@ -13,7 +16,7 @@ import (
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
func (suite AnteTestSuite) TestAnteHandler() {
func (suite MiddlewareTestSuite) TestAnteHandler() {
suite.enableFeemarket = false
suite.SetupTest() // reset
@ -297,7 +300,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
"success - DeliverTx EIP712 signed Cosmos Tx with MsgSend",
func() sdk.Tx {
from := acc.GetAddress()
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9000-1", gas, amount)
return txBuilder.GetTx()
@ -307,7 +310,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
"success - DeliverTx EIP712 signed Cosmos Tx with DelegateMsg",
func() sdk.Tx {
from := acc.GetAddress()
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20))
coinAmount := sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000))
amount := sdk.NewCoins(coinAmount)
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712TxBuilderMsgDelegate(from, privKey, "ethermint_9000-1", gas, amount)
@ -318,7 +321,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
"fails - DeliverTx EIP712 signed Cosmos Tx with wrong Chain ID",
func() sdk.Tx {
from := acc.GetAddress()
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9002-1", gas, amount)
return txBuilder.GetTx()
@ -328,7 +331,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
"fails - DeliverTx EIP712 signed Cosmos Tx with different gas fees",
func() sdk.Tx {
from := acc.GetAddress()
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
txBuilder.SetGasLimit(uint64(300000))
@ -340,7 +343,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
"fails - DeliverTx EIP712 signed Cosmos Tx with empty signature",
func() sdk.Tx {
from := acc.GetAddress()
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
sigsV2 := signing.SignatureV2{}
@ -352,7 +355,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid sequence",
func() sdk.Tx {
from := acc.GetAddress()
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
@ -372,7 +375,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
"fails - DeliverTx EIP712 signed Cosmos Tx with invalid signMode",
func() sdk.Tx {
from := acc.GetAddress()
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
gas := uint64(200000)
txBuilder := suite.CreateTestEIP712TxBuilderMsgSend(from, privKey, "ethermint_9001-1", gas, amount)
nonce, err := suite.app.AccountKeeper.GetSequence(suite.ctx, acc.GetAddress())
@ -395,8 +398,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
suite.ctx = suite.ctx.WithIsCheckTx(tc.checkTx).WithIsReCheckTx(tc.reCheckTx)
// expConsumed := params.TxGasContractCreation + params.TxGas
_, err := suite.anteHandler(suite.ctx, tc.txFn(), false)
_, _, err := suite.anteHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.txFn()}, tx.RequestCheckTx{})
// suite.Require().Equal(consumed, ctx.GasMeter().GasConsumed())
if tc.expPass {
@ -409,7 +411,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
}
}
func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
func (suite MiddlewareTestSuite) TestAnteHandlerWithDynamicTxFee() {
addr, privKey := tests.NewAddrKey()
to := tests.GenerateAddress()
@ -674,7 +676,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
suite.ctx = suite.ctx.WithIsCheckTx(tc.checkTx).WithIsReCheckTx(tc.reCheckTx)
suite.app.EvmKeeper.SetBalance(suite.ctx, addr, big.NewInt((ethparams.InitialBaseFee+10)*100000))
_, err := suite.anteHandler(suite.ctx, tc.txFn(), false)
_, _, err := suite.anteHandler.CheckTx(sdk.WrapSDKContext(suite.ctx), txtypes.Request{Tx: tc.txFn()}, tx.RequestCheckTx{})
if tc.expPass {
suite.Require().NoError(err)
} else {

178
app/middleware/options.go Normal file
View File

@ -0,0 +1,178 @@
package middleware
import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authmiddleware "github.com/cosmos/cosmos-sdk/x/auth/middleware"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// HandlerOptions extend the SDK's TxHandler options by requiring the IBC
// channel keeper, EVM Keeper and Fee Market Keeper.
type HandlerOptions struct {
Debug bool
Codec codec.Codec
// TxDecoder is used to decode the raw tx bytes into a sdk.Tx.
TxDecoder sdk.TxDecoder
// IndexEvents defines the set of events in the form {eventType}.{attributeKey},
// which informs Tendermint what to index. If empty, all events will be indexed.
IndexEvents map[string]struct{}
LegacyRouter sdk.Router
MsgServiceRouter *authmiddleware.MsgServiceRouter
ExtensionOptionChecker authmiddleware.ExtensionOptionChecker
TxFeeChecker authmiddleware.TxFeeChecker
AccountKeeper evmtypes.AccountKeeper
BankKeeper evmtypes.BankKeeper
FeeMarketKeeper evmtypes.FeeMarketKeeper
EvmKeeper EVMKeeper
FeegrantKeeper authmiddleware.FeegrantKeeper
SignModeHandler authsigning.SignModeHandler
SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error
MaxTxGasWanted uint64
}
func (options HandlerOptions) Validate() error {
if options.TxDecoder == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "txDecoder is required for middlewares")
}
if options.SignModeHandler == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for middlewares")
}
if options.AccountKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for middlewares")
}
if options.BankKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for middlewares")
}
if options.SignModeHandler == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for middlewares")
}
if options.FeeMarketKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "fee market keeper is required for middlewares")
}
if options.EvmKeeper == nil {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "evm keeper is required for middlewares")
}
return nil
}
func newEthAuthMiddleware(options HandlerOptions) tx.Middleware {
stack := []tx.Middleware{
NewEthSetUpContextMiddleware(options.EvmKeeper),
NewEthMempoolFeeMiddleware(options.EvmKeeper),
authmiddleware.NewIndexEventsTxMiddleware(options.IndexEvents),
NewEthValidateBasicMiddleware(options.EvmKeeper),
NewEthSigVerificationMiddleware(options.EvmKeeper),
NewEthAccountVerificationMiddleware(options.AccountKeeper, options.BankKeeper, options.EvmKeeper),
NewEthGasConsumeMiddleware(options.EvmKeeper, options.MaxTxGasWanted),
NewCanTransferMiddleware(options.EvmKeeper),
NewEthIncrementSenderSequenceMiddleware(options.AccountKeeper),
}
return func(txh tx.Handler) tx.Handler {
return authmiddleware.ComposeMiddlewares(txh, stack...)
}
}
func newCosmosAuthMiddleware(options HandlerOptions) tx.Middleware {
stack := []tx.Middleware{
NewRejectMessagesMiddleware,
// Set a new GasMeter on sdk.Context.
//
// Make sure the Gas middleware is outside of all other middlewares
// that reads the GasMeter. In our case, the Recovery middleware reads
// the GasMeter to populate GasInfo.
authmiddleware.GasTxMiddleware,
// Recover from panics. Panics outside of this middleware won't be
// caught, be careful!
authmiddleware.RecoveryTxMiddleware,
// Choose which events to index in Tendermint. Make sure no events are
// emitted outside of this middleware.
authmiddleware.NewIndexEventsTxMiddleware(options.IndexEvents),
// Reject all extension options other than the ones needed by the feemarket.
authmiddleware.NewExtensionOptionsMiddleware(options.ExtensionOptionChecker),
authmiddleware.ValidateBasicMiddleware,
authmiddleware.TxTimeoutHeightMiddleware,
authmiddleware.ValidateMemoMiddleware(options.AccountKeeper),
authmiddleware.ConsumeTxSizeGasMiddleware(options.AccountKeeper),
// No gas should be consumed in any middleware above in a "post" handler part. See
// ComposeMiddlewares godoc for details.
// `DeductFeeMiddleware` and `IncrementSequenceMiddleware` should be put outside of `WithBranchedStore` middleware,
// so their storage writes are not discarded when tx fails.
authmiddleware.DeductFeeMiddleware(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
authmiddleware.SetPubKeyMiddleware(options.AccountKeeper),
authmiddleware.ValidateSigCountMiddleware(options.AccountKeeper),
authmiddleware.SigGasConsumeMiddleware(options.AccountKeeper, options.SigGasConsumer),
authmiddleware.SigVerificationMiddleware(options.AccountKeeper, options.SignModeHandler),
authmiddleware.IncrementSequenceMiddleware(options.AccountKeeper),
// Creates a new MultiStore branch, discards downstream writes if the downstream returns error.
// These kinds of middlewares should be put under this:
// - Could return error after messages executed succesfully.
// - Storage writes should be discarded together when tx failed.
authmiddleware.WithBranchedStore,
// Consume block gas. All middlewares whose gas consumption after their `next` handler
// should be accounted for, should go below this middleware.
authmiddleware.ConsumeBlockGasMiddleware,
authmiddleware.NewTipMiddleware(options.BankKeeper),
}
return func(txh tx.Handler) tx.Handler {
return authmiddleware.ComposeMiddlewares(txh, stack...)
}
}
func newCosmosMiddlewareEip712(options HandlerOptions) tx.Middleware {
stack := []tx.Middleware{
NewRejectMessagesMiddleware,
// Set a new GasMeter on sdk.Context.
//
// Make sure the Gas middleware is outside of all other middlewares
// that reads the GasMeter. In our case, the Recovery middleware reads
// the GasMeter to populate GasInfo.
authmiddleware.GasTxMiddleware,
// Recover from panics. Panics outside of this middleware won't be
// caught, be careful!
authmiddleware.RecoveryTxMiddleware,
// Choose which events to index in Tendermint. Make sure no events are
// emitted outside of this middleware.
authmiddleware.NewIndexEventsTxMiddleware(options.IndexEvents),
// Reject all extension options other than the ones needed by the feemarket.
// authmiddleware.NewExtensionOptionsMiddleware(options.ExtensionOptionChecker),
authmiddleware.ValidateBasicMiddleware,
authmiddleware.TxTimeoutHeightMiddleware,
authmiddleware.ValidateMemoMiddleware(options.AccountKeeper),
authmiddleware.ConsumeTxSizeGasMiddleware(options.AccountKeeper),
// No gas should be consumed in any middleware above in a "post" handler part. See
// ComposeMiddlewares godoc for details.
// `DeductFeeMiddleware` and `IncrementSequenceMiddleware` should be put outside of `WithBranchedStore` middleware,
// so their storage writes are not discarded when tx fails.
authmiddleware.DeductFeeMiddleware(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper, options.TxFeeChecker),
authmiddleware.SetPubKeyMiddleware(options.AccountKeeper),
authmiddleware.ValidateSigCountMiddleware(options.AccountKeeper),
authmiddleware.SigGasConsumeMiddleware(options.AccountKeeper, options.SigGasConsumer),
// Note: signature verification uses EIP instead of the cosmos signature validator
NewEip712SigVerificationMiddleware(options.Codec, options.AccountKeeper, options.SignModeHandler),
authmiddleware.IncrementSequenceMiddleware(options.AccountKeeper),
// Creates a new MultiStore branch, discards downstream writes if the downstream returns error.
// These kinds of middlewares should be put under this:
// - Could return error after messages executed succesfully.
// - Storage writes should be discarded together when tx failed.
authmiddleware.WithBranchedStore,
// Consume block gas. All middlewares whose gas consumption after their `next` handler
// should be accounted for, should go below this middleware.
authmiddleware.ConsumeBlockGasMiddleware,
authmiddleware.NewTipMiddleware(options.BankKeeper),
}
return func(txh tx.Handler) tx.Handler {
return authmiddleware.ComposeMiddlewares(txh, stack...)
}
}

67
app/middleware/reject.go Normal file
View File

@ -0,0 +1,67 @@
package middleware
import (
context "context"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/tx"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
// RejectMessagesMiddleware prevents invalid msg types from being executed
type RejectMessagesMiddleware struct {
next tx.Handler
}
func NewRejectMessagesMiddleware(txh tx.Handler) tx.Handler {
return RejectMessagesMiddleware{
next: txh,
}
}
// Middleware rejects messages that requires ethereum-specific authentication.
// For example `MsgEthereumTx` requires fee to be deducted in the antehandler in
// order to perform the refund.
// CheckTx implements tx.Handler
func (rmd RejectMessagesMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
if _, err := reject(req); err != nil {
return tx.Response{}, tx.ResponseCheckTx{}, err
}
return rmd.next.CheckTx(ctx, req, checkReq)
}
// DeliverTx implements tx.Handler
func (rmd RejectMessagesMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
if _, err := reject(req); err != nil {
return tx.Response{}, err
}
return rmd.next.DeliverTx(ctx, req)
}
// SimulateTx implements tx.Handler
func (rmd RejectMessagesMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
if _, err := reject(req); err != nil {
return tx.Response{}, err
}
return rmd.next.SimulateTx(ctx, req)
}
func reject(req tx.Request) (tx.Response, error) {
reqTx := req.Tx
for _, msg := range reqTx.GetMsgs() {
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
return tx.Response{}, sdkerrors.Wrapf(
sdkerrors.ErrInvalidType,
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
)
}
}
return tx.Response{}, nil
}
var _ tx.Handler = RejectMessagesMiddleware{}

View File

@ -1,4 +1,4 @@
package ante_test
package middleware_test
import (
"math/big"
@ -8,7 +8,7 @@ import (
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
func (suite AnteTestSuite) TestSignatures() {
func (suite MiddlewareTestSuite) TestSignatures() {
suite.enableFeemarket = false
suite.SetupTest() // reset

View File

@ -1,16 +1,21 @@
package ante_test
package middleware_test
import (
context "context"
"math"
"testing"
"time"
clientTx "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
types2 "github.com/cosmos/cosmos-sdk/x/bank/types"
types3 "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/spf13/cast"
"github.com/tharsis/ethermint/app/middleware"
"github.com/tharsis/ethermint/ethereum/eip712"
"github.com/tharsis/ethermint/server/config"
"github.com/tharsis/ethermint/types"
"github.com/ethereum/go-ethereum/common"
@ -19,48 +24,69 @@ import (
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/tx"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
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"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tharsis/ethermint/app"
ante "github.com/tharsis/ethermint/app/ante"
"github.com/tharsis/ethermint/encoding"
"github.com/tharsis/ethermint/tests"
"github.com/tharsis/ethermint/x/evm/statedb"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
type AnteTestSuite struct {
// customTxHandler is a test middleware that will run a custom function.
type customTxHandler struct {
fn func(context.Context, tx.Request) (tx.Response, error)
}
var _ tx.Handler = customTxHandler{}
func (h customTxHandler) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return h.fn(ctx, req)
}
func (h customTxHandler) CheckTx(ctx context.Context, req tx.Request, _ tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
res, err := h.fn(ctx, req)
return res, tx.ResponseCheckTx{}, err
}
func (h customTxHandler) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
return h.fn(ctx, req)
}
// noopTxHandler is a test middleware that returns an empty response.
var noopTxHandler = customTxHandler{func(_ context.Context, _ tx.Request) (tx.Response, error) {
return tx.Response{}, nil
}}
type MiddlewareTestSuite struct {
suite.Suite
ctx sdk.Context
app *app.EthermintApp
clientCtx client.Context
anteHandler sdk.AnteHandler
anteHandler tx.Handler
ethSigner ethtypes.Signer
enableFeemarket bool
enableLondonHF bool
}
func (suite *AnteTestSuite) StateDB() *statedb.StateDB {
func (suite *MiddlewareTestSuite) StateDB() *statedb.StateDB {
return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes())))
}
func (suite *AnteTestSuite) SetupTest() {
func (suite *MiddlewareTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
suite.app = app.Setup(suite.T(), checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
if suite.enableFeemarket {
// setup feemarketGenesis params
feemarketGenesis := feemarkettypes.DefaultGenesisState()
@ -95,32 +121,37 @@ func (suite *AnteTestSuite) SetupTest() {
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
maxGasWanted := cast.ToUint64(config.DefaultMaxTxGasWanted)
options := ante.HandlerOptions{
options := middleware.HandlerOptions{
TxDecoder: suite.clientCtx.TxConfig.TxDecoder(),
AccountKeeper: suite.app.AccountKeeper,
BankKeeper: suite.app.BankKeeper,
EvmKeeper: suite.app.EvmKeeper,
FeegrantKeeper: suite.app.FeeGrantKeeper,
IBCKeeper: suite.app.IBCKeeper,
Codec: suite.app.AppCodec(),
Debug: suite.app.Trace(),
LegacyRouter: suite.app.LegacyRouter,
MsgServiceRouter: suite.app.MsgSvcRouter,
FeeMarketKeeper: suite.app.FeeMarketKeeper,
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
SignModeHandler: suite.clientCtx.TxConfig.SignModeHandler(),
SigGasConsumer: middleware.DefaultSigVerificationGasConsumer,
MaxTxGasWanted: maxGasWanted,
}
suite.Require().NoError(options.Validate())
suite.anteHandler = ante.NewAnteHandler(options)
suite.anteHandler = middleware.NewTxHandler(options)
suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
}
func TestAnteTestSuite(t *testing.T) {
suite.Run(t, &AnteTestSuite{
func TestMiddlewareTestSuite(t *testing.T) {
suite.Run(t, &MiddlewareTestSuite{
enableLondonHF: true,
})
}
// CreateTestTx is a helper function to create a tx given multiple inputs.
func (suite *AnteTestSuite) CreateTestTx(
func (suite *MiddlewareTestSuite) CreateTestTx(
msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey, accNum uint64, signCosmosTx bool,
unsetExtensionOptions ...bool,
) authsigning.Tx {
@ -128,7 +159,7 @@ func (suite *AnteTestSuite) CreateTestTx(
}
// CreateTestTxBuilder is a helper function to create a tx builder given multiple inputs.
func (suite *AnteTestSuite) CreateTestTxBuilder(
func (suite *MiddlewareTestSuite) CreateTestTxBuilder(
msg *evmtypes.MsgEthereumTx, priv cryptotypes.PrivKey, accNum uint64, signCosmosTx bool,
unsetExtensionOptions ...bool,
) client.TxBuilder {
@ -184,7 +215,7 @@ func (suite *AnteTestSuite) CreateTestTxBuilder(
AccountNumber: accNum,
Sequence: txData.GetNonce(),
}
sigV2, err = tx.SignWithPrivKey(
sigV2, err = clientTx.SignWithPrivKey(
suite.clientCtx.TxConfig.SignModeHandler().DefaultMode(), signerData,
txBuilder, priv, suite.clientCtx.TxConfig, txData.GetNonce(),
)
@ -199,22 +230,22 @@ func (suite *AnteTestSuite) CreateTestTxBuilder(
return txBuilder
}
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgSend(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
func (suite *MiddlewareTestSuite) CreateTestEIP712TxBuilderMsgSend(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
// Build MsgSend
recipient := sdk.AccAddress(common.Address{}.Bytes())
msgSend := types2.NewMsgSend(from, recipient, sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(1))))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
}
func (suite *AnteTestSuite) CreateTestEIP712TxBuilderMsgDelegate(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
func (suite *MiddlewareTestSuite) CreateTestEIP712TxBuilderMsgDelegate(from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins) client.TxBuilder {
// Build MsgSend
valEthAddr := tests.GenerateAddress()
valAddr := sdk.ValAddress(valEthAddr.Bytes())
msgSend := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
msgSend := types3.NewMsgDelegate(from, valAddr, sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(200000)))
return suite.CreateTestEIP712CosmosTxBuilder(from, priv, chainId, gas, gasAmount, msgSend)
}
func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
func (suite *MiddlewareTestSuite) CreateTestEIP712CosmosTxBuilder(
from sdk.AccAddress, priv cryptotypes.PrivKey, chainId string, gas uint64, gasAmount sdk.Coins, msg sdk.Msg,
) client.TxBuilder {
var err error
@ -231,7 +262,7 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
fee := legacytx.NewStdFee(gas, gasAmount)
accNumber := suite.app.AccountKeeper.GetAccount(suite.ctx, from).GetAccountNumber()
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, []sdk.Msg{msg}, "")
data := legacytx.StdSignBytes(chainId, accNumber, nonce, 0, fee, []sdk.Msg{msg}, "", nil)
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, ethChainId, msg, data, &eip712.FeeDelegationOptions{
FeePayer: from,
})

View File

@ -13,7 +13,6 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
@ -27,12 +26,14 @@ import (
"github.com/cosmos/cosmos-sdk/x/simulation"
slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/cosmos-sdk/db/memdb"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
ibctransfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types"
ibchost "github.com/cosmos/ibc-go/v3/modules/core/24-host"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db"
evmenc "github.com/tharsis/ethermint/encoding"
)
@ -48,21 +49,22 @@ func init() {
const SimAppChainID = "simulation_777-1"
type storeKeysPrefixes struct {
A sdk.StoreKey
B sdk.StoreKey
A storetypes.StoreKey
B storetypes.StoreKey
Prefixes [][]byte
}
// fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
// an IAVLStore for faster simulation speed.
func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
var fauxMerkleModeOpt = baseapp.AppOptionFunc(func(bapp *baseapp.BaseApp) {
bapp.SetFauxMerkleMode()
}
})
// interBlockCacheOpt returns a BaseApp option function that sets the persistent
// inter-block write-through cache.
func interBlockCacheOpt() func(*baseapp.BaseApp) {
return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager())
// TODO: implement this cache as enhancement to v2 multistore
func interBlockCacheOpt() baseapp.AppOptionFunc {
return func(*baseapp.BaseApp) {}
}
func TestFullAppSimulation(t *testing.T) {
@ -310,7 +312,7 @@ func TestAppStateDeterminism(t *testing.T) {
logger = log.NewNopLogger()
}
db := dbm.NewMemDB()
db := memdb.NewDB()
app := NewEthermintApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, simapp.FlagPeriodValue, MakeEncodingConfig(), simapp.EmptyAppOptions{}, interBlockCacheOpt())
fmt.Printf(

View File

@ -1,26 +1,50 @@
package app
import (
"context"
"encoding/json"
"testing"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
"github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/tharsis/ethermint/encoding"
"github.com/cosmos/cosmos-sdk/testutil/mock"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/stretchr/testify/require"
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
"github.com/tharsis/ethermint/encoding"
ethermint "github.com/tharsis/ethermint/types"
"github.com/cosmos/cosmos-sdk/db/memdb"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/ed25519"
"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"
)
// GenesisState of the blockchain is represented here as a map of raw json
// messages key'd by a identifier string.
// The identifier is used to determine which module genesis information belongs
// to so it may be appropriately routed during init chain.
// Within this application default genesis information is retrieved from
// the ModuleBasicManager which populates json from each BasicModule
// object provided to it during init.
// 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
},
@ -36,22 +60,51 @@ var DefaultConsensusParams = &abci.ConsensusParams{
},
}
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
func Setup(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState) *EthermintApp {
db := dbm.NewMemDB()
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
genesisState := NewDefaultGenesisState()
if patchGenesis != nil {
genesisState = patchGenesis(app, genesisState)
// SetupOptions defines arguments that are passed into `Simapp` constructor.
type SetupOptions struct {
Logger log.Logger
DB *memdb.MemDB
InvCheckPeriod uint
HomePath string
SkipUpgradeHeights map[int64]bool
EncConfig params.EncodingConfig
AppOpts types.AppOptions
}
func NewTestAppWithCustomOptions(t *testing.T, isCheckTx bool, options SetupOptions) *EthermintApp {
t.Helper()
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey(context.TODO())
require.NoError(t, err)
// create validator set with single validator
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
// generate genesis account
priv, err := ethsecp256k1.GenerateKey()
require.NoError(t, err)
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
acc := &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0),
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
}
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
if err != nil {
panic(err)
balance := banktypes.Balance{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
}
app := NewEthermintApp(options.Logger, options.DB, nil, true, options.SkipUpgradeHeights, options.HomePath, options.InvCheckPeriod, options.EncConfig, options.AppOpts)
genesisState := NewDefaultGenesisState(app.appCodec)
genesisState = genesisStateWithValSet(t, app, genesisState, valSet, []authtypes.GenesisAccount{acc}, balance)
if !isCheckTx {
// init chain must be called to stop deliverState from being nil
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
app.InitChain(
abci.RequestInitChain{
@ -66,6 +119,149 @@ func Setup(isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState)
return app
}
// Setup initializes a new EthermintApp. A Nop logger is set in EthermintApp.
func Setup(t *testing.T, isCheckTx bool, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState) *EthermintApp {
t.Helper()
privVal := mock.NewPV()
pubKey, err := privVal.GetPubKey(context.TODO())
require.NoError(t, err)
// create validator set with single validator
validator := tmtypes.NewValidator(pubKey, 1)
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
priv, err := ethsecp256k1.GenerateKey()
require.NoError(t, err)
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
acc := &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0),
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
}
balance := banktypes.Balance{
Address: acc.GetAddress().String(),
Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100000000000000))),
}
app := SetupWithGenesisValSet(t, valSet, patchGenesis, []authtypes.GenesisAccount{acc}, balance)
return app
}
func setup(withGenesis bool, invCheckPeriod uint, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState) (*EthermintApp, simapp.GenesisState) {
encCdc := encoding.MakeConfig(ModuleBasics)
app := NewEthermintApp(log.NewNopLogger(), memdb.NewDB(), nil, true, map[int64]bool{}, DefaultNodeHome, invCheckPeriod, encCdc, EmptyAppOptions{})
if withGenesis {
genesisState := NewDefaultGenesisState(encCdc.Codec)
if patchGenesis != nil {
genesisState = patchGenesis(app, genesisState)
}
return app, genesisState
}
return app, simapp.GenesisState{}
}
// SetupWithGenesisValSet initializes a new SimApp with a validator set and genesis accounts
// that also act as delegators. For simplicity, each validator is bonded with a delegation
// of one consensus engine unit in the default token of the simapp from first genesis
// account. A Nop logger is set in SimApp.
func SetupWithGenesisValSet(t *testing.T, valSet *tmtypes.ValidatorSet, patchGenesis func(*EthermintApp, simapp.GenesisState) simapp.GenesisState, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) *EthermintApp {
t.Helper()
app, genesisState := setup(true, 5, patchGenesis)
genesisState = genesisStateWithValSet(t, app, genesisState, valSet, genAccs, balances...)
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// init chain will set the validator set and initialize the genesis accounts
app.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
ConsensusParams: DefaultConsensusParams,
AppStateBytes: stateBytes,
},
)
// commit genesis changes
// app.Commit()
// app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{
// ChainID: "ethermint_9000-1",
// Height: app.LastBlockHeight() + 1,
// AppHash: app.LastCommitID().Hash,
// ValidatorsHash: valSet.Hash(),
// NextValidatorsHash: valSet.Hash(),
// }})
return app
}
func genesisStateWithValSet(t *testing.T, app *EthermintApp, genesisState simapp.GenesisState,
valSet *tmtypes.ValidatorSet, genAccs []authtypes.GenesisAccount, balances ...banktypes.Balance) simapp.GenesisState {
// set genesis accounts
authGenesis := authtypes.NewGenesisState(authtypes.DefaultParams(), genAccs)
genesisState[authtypes.ModuleName] = app.AppCodec().MustMarshalJSON(authGenesis)
validators := make([]stakingtypes.Validator, 0, len(valSet.Validators))
delegations := make([]stakingtypes.Delegation, 0, len(valSet.Validators))
bondAmt := sdk.DefaultPowerReduction
for _, val := range valSet.Validators {
pk, err := cryptocodec.FromTmPubKeyInterface(val.PubKey)
require.NoError(t, err)
pkAny, err := codectypes.NewAnyWithValue(pk)
require.NoError(t, err)
validator := stakingtypes.Validator{
OperatorAddress: sdk.ValAddress(val.Address).String(),
ConsensusPubkey: pkAny,
Jailed: false,
Status: stakingtypes.Bonded,
Tokens: bondAmt,
DelegatorShares: sdk.OneDec(),
Description: stakingtypes.Description{},
UnbondingHeight: int64(0),
UnbondingTime: time.Unix(0, 0).UTC(),
Commission: stakingtypes.NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
MinSelfDelegation: sdk.ZeroInt(),
}
validators = append(validators, validator)
delegations = append(delegations, stakingtypes.NewDelegation(genAccs[0].GetAddress(), val.Address.Bytes(), sdk.OneDec()))
}
// set validators and delegations
stakingGenesis := stakingtypes.NewGenesisState(stakingtypes.DefaultParams(), validators, delegations)
genesisState[stakingtypes.ModuleName] = app.AppCodec().MustMarshalJSON(stakingGenesis)
totalSupply := sdk.NewCoins()
for _, b := range balances {
// add genesis acc tokens to total supply
totalSupply = totalSupply.Add(b.Coins...)
}
for range delegations {
// add delegated tokens to total supply
totalSupply = totalSupply.Add(sdk.NewCoin(sdk.DefaultBondDenom, bondAmt))
}
// add bonded amount to bonded pool module account
balances = append(balances, banktypes.Balance{
Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(),
Coins: sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, bondAmt)},
})
// update total supply
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, totalSupply, []banktypes.Metadata{})
genesisState[banktypes.ModuleName] = app.AppCodec().MustMarshalJSON(bankGenesis)
return genesisState
}
// CreateRandomAccounts will generate random accounts
func CreateRandomAccounts(accNum int) []sdk.AccAddress {
// createRandomAccounts is a strategy used by addTestAddrs() in order to generated addresses in random order.
@ -77,3 +273,11 @@ func CreateRandomAccounts(accNum int) []sdk.AccAddress {
return testAddrs
}
// EmptyAppOptions is a stub implementing AppOptions
type EmptyAppOptions struct{}
// Get implements AppOptions
func (ao EmptyAppOptions) Get(o string) interface{} {
return nil
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
"strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/crypto"
@ -30,12 +31,13 @@ func UnsafeExportEthKeyCommand() *cobra.Command {
keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
rootDir, _ := cmd.Flags().GetString(flags.FlagHome)
clientCtx := client.GetClientContextFromCmd(cmd)
kr, err := keyring.New(
sdk.KeyringServiceName(),
keyringBackend,
rootDir,
inBuf,
clientCtx.Codec,
hd.EthSecp256k1Option(),
)
if err != nil {

View File

@ -5,6 +5,7 @@ import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/input"
"github.com/cosmos/cosmos-sdk/crypto"
@ -31,12 +32,14 @@ func runImportCmd(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
rootDir, _ := cmd.Flags().GetString(flags.FlagHome)
clientCtx := client.GetClientContextFromCmd(cmd)
kb, err := keyring.New(
sdk.KeyringServiceName(),
keyringBackend,
rootDir,
inBuf,
clientCtx.Codec,
hd.EthSecp256k1Option(),
)
if err != nil {

View File

@ -92,7 +92,7 @@ func runAddCmd(cmd *cobra.Command, args []string) error {
dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun)
if dryRun {
kr, err = keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, clientCtx.KeyringDir, buf, hd.EthSecp256k1Option())
kr, err = keyring.New(sdk.KeyringServiceName(), keyring.BackendMemory, clientCtx.KeyringDir, buf, clientCtx.Codec, hd.EthSecp256k1Option())
clientCtx = clientCtx.WithKeyring(kr)
}

View File

@ -122,7 +122,7 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
if dryRun, _ := cmd.Flags().GetBool(flags.FlagDryRun); dryRun {
// use in memory keybase
kb = keyring.NewInMemory(etherminthd.EthSecp256k1Option())
kb = keyring.NewInMemory(ctx.Codec, etherminthd.EthSecp256k1Option())
} else {
_, err = kb.Key(name)
if err == nil {
@ -156,7 +156,9 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
return err
}
pks[i] = k.GetPubKey()
if pks[i], err = k.GetPubKey(); err != nil {
return err
}
}
if noSort, _ := cmd.Flags().GetBool(flagNoSort); !noSort {
@ -183,7 +185,7 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
return err
}
info, err := kb.SavePubKey(name, pk, algo.Name())
info, err := kb.SaveOfflineKey(name, pk)
if err != nil {
return err
}
@ -289,7 +291,7 @@ func RunAddCmd(ctx client.Context, cmd *cobra.Command, args []string, inBuf *buf
return printCreate(cmd, info, showMnemonic, mnemonic, outputFormat)
}
func printCreate(cmd *cobra.Command, info keyring.Info, showMnemonic bool, mnemonic, outputFormat string) error {
func printCreate(cmd *cobra.Command, info *keyring.Record, showMnemonic bool, mnemonic, outputFormat string) error {
switch outputFormat {
case OutputFormatText:
cmd.PrintErrln()

View File

@ -3,7 +3,6 @@ package keys
import (
"fmt"
"io"
"path/filepath"
yaml "gopkg.in/yaml.v2"
@ -20,19 +19,9 @@ const (
defaultKeyDBName = "keys"
)
type bechKeyOutFn func(keyInfo cryptokeyring.Info) (cryptokeyring.KeyOutput, error)
type bechKeyOutFn func(keyInfo *cryptokeyring.Record) (cryptokeyring.KeyOutput, error)
// NewLegacyKeyBaseFromDir initializes a legacy keybase at the rootDir directory. Keybase
// options can be applied when generating this new Keybase.
func NewLegacyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.LegacyKeybase, error) {
return getLegacyKeyBaseFromDir(rootDir, opts...)
}
func getLegacyKeyBaseFromDir(rootDir string, opts ...cryptokeyring.KeybaseOption) (cryptokeyring.LegacyKeybase, error) {
return cryptokeyring.NewLegacy(defaultKeyDBName, filepath.Join(rootDir, "keys"), opts...)
}
func printKeyInfo(w io.Writer, keyInfo cryptokeyring.Info, bechKeyOut bechKeyOutFn, output string) {
func printKeyInfo(w io.Writer, keyInfo *cryptokeyring.Record, bechKeyOut bechKeyOutFn, output string) {
ko, err := bechKeyOut(keyInfo)
if err != nil {
panic(err)

View File

@ -6,17 +6,18 @@ import (
"bufio"
"encoding/json"
"fmt"
"math/rand"
"net"
"os"
"path/filepath"
"time"
"github.com/ethereum/go-ethereum/common"
tmcfg "github.com/tendermint/tendermint/config"
"github.com/spf13/cobra"
tmconfig "github.com/tendermint/tendermint/config"
tmrand "github.com/tendermint/tendermint/libs/rand"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
@ -34,6 +35,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
mintypes "github.com/cosmos/cosmos-sdk/x/mint/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
@ -209,7 +212,7 @@ func initTestnetFiles(
args initArgs,
) error {
if args.chainID == "" {
args.chainID = fmt.Sprintf("ethermint_%d-1", tmrand.Int63n(9999999999999)+1)
args.chainID = fmt.Sprintf("ethermint_%d-1", rand.Int63n(9999999999999)+1)
}
nodeIDs := make([]string, args.numValidators)
@ -261,7 +264,7 @@ func initTestnetFiles(
memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip)
genFiles = append(genFiles, nodeConfig.GenesisFile())
kb, err := keyring.New(sdk.KeyringServiceName(), args.keyringBackend, nodeDir, inBuf, hd.EthSecp256k1Option())
kb, err := keyring.New(sdk.KeyringServiceName(), args.keyringBackend, nodeDir, inBuf, clientCtx.Codec, hd.EthSecp256k1Option())
if err != nil {
return err
}
@ -343,7 +346,8 @@ func initTestnetFiles(
customAppTemplate, customAppConfig := config.AppConfig(ethermint.AttoPhoton)
srvconfig.SetConfigTemplate(customAppTemplate)
if err := sdkserver.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig); err != nil {
customTmConfig := tmcfg.DefaultConfig()
if err := sdkserver.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customTmConfig); err != nil {
return err
}
@ -402,7 +406,7 @@ func initGenFiles(
stakingGenState.Params.BondDenom = coinDenom
appGenState[stakingtypes.ModuleName] = clientCtx.Codec.MustMarshalJSON(&stakingGenState)
var govGenState govtypes.GenesisState
var govGenState v1.GenesisState
clientCtx.Codec.MustUnmarshalJSON(appGenState[govtypes.ModuleName], &govGenState)
govGenState.DepositParams.MinDeposit[0].Denom = coinDenom
@ -452,7 +456,7 @@ func collectGenFiles(
outputDir, nodeDirPrefix, nodeDaemonHome string, genBalIterator banktypes.GenesisBalancesIterator,
) error {
var appState json.RawMessage
genTime := tmtime.Now()
genTime := time.Now()
for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)

View File

@ -23,6 +23,6 @@ func TestInitCmd(t *testing.T) {
fmt.Sprintf("--%s=%s", flags.FlagChainID, "ethermint_9000-1"),
})
err := svrcmd.Execute(rootCmd, app.DefaultNodeHome)
err := svrcmd.Execute(rootCmd, chibaclonkd.EnvPrefix, app.DefaultNodeHome)
require.NoError(t, err)
}

View File

@ -63,6 +63,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
keyringBackend,
clientCtx.HomeDir,
inBuf,
clientCtx.Codec,
hd.EthSecp256k1Option(),
)
if err != nil {
@ -77,7 +78,10 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
return fmt.Errorf("failed to get address from Keyring: %w", err)
}
addr = info.GetAddress()
addr, err = info.GetAddress()
if err != nil {
return fmt.Errorf("failed to get address from Keyring: %w", err)
}
}
coins, err := sdk.ParseCoinsNormalized(args[1])

View File

@ -12,7 +12,7 @@ import (
func main() {
rootCmd, _ := NewRootCmd()
if err := svrcmd.Execute(rootCmd, app.DefaultNodeHome); err != nil {
if err := svrcmd.Execute(rootCmd, "", app.DefaultNodeHome); err != nil {
switch e := err.(type) {
case server.ErrorCode:
os.Exit(e.Code)

View File

@ -6,18 +6,13 @@ import (
"os"
"path/filepath"
"github.com/spf13/cast"
"github.com/spf13/cobra"
tmcli "github.com/tendermint/tendermint/libs/cli"
tmlog "github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/rpc"
dbm "github.com/cosmos/cosmos-sdk/db"
"github.com/cosmos/cosmos-sdk/db/badgerdb"
sdkserver "github.com/cosmos/cosmos-sdk/server"
servertypes "github.com/cosmos/cosmos-sdk/server/types"
"github.com/cosmos/cosmos-sdk/simapp/params"
@ -29,6 +24,11 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/crisis"
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
"github.com/spf13/cast"
"github.com/spf13/cobra"
tmcfg "github.com/tendermint/tendermint/config"
tmcli "github.com/tendermint/tendermint/libs/cli"
tmlog "github.com/tendermint/tendermint/libs/log"
"github.com/tharsis/ethermint/app"
ethermintclient "github.com/tharsis/ethermint/client"
@ -48,7 +48,7 @@ const EnvPrefix = "CHIBACLONK"
func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
initClientCtx := client.Context{}.
WithCodec(encodingConfig.Marshaler).
WithCodec(encodingConfig.Codec).
WithInterfaceRegistry(encodingConfig.InterfaceRegistry).
WithTxConfig(encodingConfig.TxConfig).
WithLegacyAmino(encodingConfig.Amino).
@ -83,8 +83,9 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
// FIXME: replace AttoPhoton with bond denom
customAppTemplate, customAppConfig := servercfg.AppConfig(ethermint.AttoPhoton)
customTMConfig := initTendermintConfig()
return sdkserver.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig)
return sdkserver.InterceptConfigsPreRunHandler(cmd, customAppTemplate, customAppConfig, customTMConfig)
},
}
@ -126,7 +127,7 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) {
}
// add rosetta
rootCmd.AddCommand(sdkserver.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Marshaler))
rootCmd.AddCommand(sdkserver.RosettaCommand(encodingConfig.InterfaceRegistry, encodingConfig.Codec))
// Add flags for GQL server.
rootCmd = srvflags.AddGQLFlags(rootCmd)
@ -138,6 +139,18 @@ func addModuleInitFlags(startCmd *cobra.Command) {
crisis.AddModuleInitFlags(startCmd)
}
// initTendermintConfig helps to override default Tendermint Config values.
// return tmcfg.DefaultConfig if no custom configuration is required for the application.
func initTendermintConfig() *tmcfg.Config {
cfg := tmcfg.DefaultConfig()
// these values put a higher strain on node memory
// cfg.P2P.MaxNumInboundPeers = 100
// cfg.P2P.MaxNumOutboundPeers = 40
return cfg
}
func queryCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "query",
@ -193,7 +206,7 @@ type appCreator struct {
}
// newApp is an appCreator
func (a appCreator) newApp(logger tmlog.Logger, db dbm.DB, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application {
func (a appCreator) newApp(logger tmlog.Logger, db dbm.DBConnection, traceStore io.Writer, appOpts servertypes.AppOptions) servertypes.Application {
var cache sdk.MultiStorePersistentCache
if cast.ToBool(appOpts.Get(sdkserver.FlagInterBlockCache)) {
@ -211,7 +224,7 @@ func (a appCreator) newApp(logger tmlog.Logger, db dbm.DB, traceStore io.Writer,
}
snapshotDir := filepath.Join(cast.ToString(appOpts.Get(flags.FlagHome)), "data", "snapshots")
snapshotDB, err := sdk.NewLevelDB("metadata", snapshotDir)
snapshotDB, err := badgerdb.NewDB(filepath.Join(snapshotDir, "metadata"))
if err != nil {
panic(err)
}
@ -245,7 +258,7 @@ func (a appCreator) newApp(logger tmlog.Logger, db dbm.DB, traceStore io.Writer,
// appExport creates a new simapp (optionally at a given height)
// and exports state.
func (a appCreator) appExport(
logger tmlog.Logger, db dbm.DB, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string,
logger tmlog.Logger, db dbm.DBConnection, traceStore io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string,
appOpts servertypes.AppOptions,
) (servertypes.ExportedApp, error) {
var ethermintApp *app.EthermintApp

View File

@ -8,7 +8,7 @@ import (
const (
// Bech32Prefix defines the Bech32 prefix used for EthAccounts
Bech32Prefix = "ethm"
Bech32Prefix = ethermint.Bech32MainPrefix
// Bech32PrefixAccAddr defines the Bech32 prefix of an account's address
Bech32PrefixAccAddr = Bech32Prefix

View File

@ -10,4 +10,5 @@ import (
// RegisterInterfaces register the Ethermint key concrete types.
func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &ethsecp256k1.PubKey{})
registry.RegisterImplementations((*cryptotypes.PrivKey)(nil), &ethsecp256k1.PrivKey{})
}

View File

@ -4,6 +4,7 @@ import (
"strings"
"testing"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
@ -12,12 +13,14 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptocodec "github.com/tharsis/ethermint/crypto/codec"
ethermint "github.com/tharsis/ethermint/types"
)
var protoCodec codec.Codec
func init() {
protoCodec = codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
amino := codec.NewLegacyAmino()
cryptocodec.RegisterCrypto(amino)
}
@ -28,7 +31,7 @@ func TestKeyring(t *testing.T) {
dir := t.TempDir()
mockIn := strings.NewReader("")
kr, err := keyring.New("ethermint", keyring.BackendTest, dir, mockIn, EthSecp256k1Option())
kr, err := keyring.New("ethermint", keyring.BackendTest, dir, mockIn, protoCodec, EthSecp256k1Option())
require.NoError(t, err)
// fail in retrieving key
@ -40,9 +43,8 @@ func TestKeyring(t *testing.T) {
info, mnemonic, err := kr.NewMnemonic("foo", keyring.English, ethermint.BIP44HDPath, keyring.DefaultBIP39Passphrase, EthSecp256k1)
require.NoError(t, err)
require.NotEmpty(t, mnemonic)
require.Equal(t, "foo", info.GetName())
require.Equal(t, "foo", info.Name)
require.Equal(t, "local", info.GetType().String())
require.Equal(t, EthSecp256k1Type, info.GetAlgo())
hdPath := ethermint.BIP44HDPath

View File

@ -4,7 +4,6 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/std"
sdk "github.com/cosmos/cosmos-sdk/types"
cryptocodec "github.com/tharsis/ethermint/crypto/codec"
ethermint "github.com/tharsis/ethermint/types"
@ -12,9 +11,7 @@ import (
// RegisterLegacyAminoCodec registers Interfaces from types, crypto, and SDK std.
func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
sdk.RegisterLegacyAminoCodec(cdc)
cryptocodec.RegisterCrypto(cdc)
codec.RegisterEvidences(cdc)
std.RegisterLegacyAminoCodec(cdc)
}
// RegisterInterfaces registers Interfaces from types, crypto, and SDK std.

View File

@ -1,7 +1,7 @@
package encoding
import (
amino "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/types/module"
@ -12,15 +12,16 @@ import (
// MakeConfig creates an EncodingConfig for testing
func MakeConfig(mb module.BasicManager) params.EncodingConfig {
cdc := amino.NewLegacyAmino()
amino := codec.NewLegacyAmino()
interfaceRegistry := types.NewInterfaceRegistry()
marshaler := amino.NewProtoCodec(interfaceRegistry)
marshaler := codec.NewProtoCodec(interfaceRegistry)
txCfg := tx.NewTxConfig(marshaler, tx.DefaultSignModes)
encodingConfig := params.EncodingConfig{
InterfaceRegistry: interfaceRegistry,
Marshaler: marshaler,
TxConfig: tx.NewTxConfig(marshaler, tx.DefaultSignModes),
Amino: cdc,
Codec: marshaler,
TxConfig: txCfg,
Amino: amino,
}
enccodec.RegisterLegacyAminoCodec(encodingConfig.Amino)

108
go.mod
View File

@ -6,12 +6,13 @@ require (
github.com/99designs/gqlgen v0.17.2
github.com/btcsuite/btcd v0.22.0-beta
github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce
github.com/cosmos/cosmos-sdk v0.45.1
github.com/cosmos/cosmos-sdk v0.46.0-beta2
github.com/cosmos/cosmos-sdk/db v1.0.0-beta.1
github.com/cosmos/go-bip39 v1.0.0
github.com/cosmos/ibc-go/v3 v3.0.0
github.com/cosmos/ibc-go/v3 v3.0.0-alpha1.0.20220517190049-c4ce2b908a1e
github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set v1.8.0
github.com/ethereum/go-ethereum v1.10.16
github.com/ethereum/go-ethereum v1.10.17
github.com/gibson042/canonicaljson-go v1.0.3
github.com/gogo/protobuf v1.3.3
github.com/golang/protobuf v1.5.2
@ -28,13 +29,13 @@ require (
github.com/rakyll/statik v0.1.7
github.com/regen-network/cosmos-proto v0.3.1
github.com/rs/cors v1.8.2
github.com/rs/zerolog v1.26.1
github.com/spf13/cast v1.4.1
github.com/spf13/cobra v1.4.0
github.com/spf13/viper v1.10.1
github.com/status-im/keycard-go v0.0.0-20200402102358-957c09536969
github.com/stretchr/testify v1.7.1
github.com/tendermint/tendermint v0.34.14
github.com/tendermint/tm-db v0.6.7
github.com/tendermint/tendermint v0.35.2
github.com/tyler-smith/go-bip39 v1.1.0
github.com/vektah/gqlparser/v2 v2.4.1
google.golang.org/genproto v0.0.0-20220401170504-314d38edb7de
@ -45,31 +46,40 @@ require (
)
require (
filippo.io/edwards25519 v1.0.0-beta.2 // indirect
cloud.google.com/go v0.99.0 // indirect
cloud.google.com/go/storage v1.14.0 // indirect
filippo.io/edwards25519 v1.0.0-rc.1 // indirect
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.5 // indirect
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
github.com/Workiva/go-datastructures v1.0.52 // indirect
github.com/Workiva/go-datastructures v1.0.53 // indirect
github.com/agnivade/levenshtein v1.1.0 // indirect
github.com/armon/go-metrics v0.3.10 // indirect
github.com/aws/aws-sdk-go v1.40.45 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.1.2 // indirect
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/coinbase/rosetta-sdk-go v0.7.0 // indirect
github.com/cockroachdb/apd/v2 v2.0.2 // indirect
github.com/coinbase/rosetta-sdk-go v0.7.7 // indirect
github.com/confio/ics23/go v0.7.0 // indirect
github.com/cosmos/btcutil v1.0.4 // indirect
github.com/cosmos/cosmos-proto v1.0.0-alpha7 // indirect
github.com/cosmos/cosmos-sdk/api v0.1.0 // indirect
github.com/cosmos/cosmos-sdk/errors v1.0.0-beta.3 // indirect
github.com/cosmos/gorocksdb v1.2.0 // indirect
github.com/cosmos/iavl v0.17.3 // indirect
github.com/cosmos/iavl v0.18.0 // indirect
github.com/cosmos/ledger-cosmos-go v0.11.1 // indirect
github.com/cosmos/ledger-go v0.9.2 // indirect
github.com/danieljoos/wincred v1.0.2 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
github.com/dgraph-io/badger/v2 v2.2007.2 // indirect
github.com/dgraph-io/ristretto v0.0.3 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/badger/v3 v3.2103.2 // indirect
github.com/dgraph-io/ristretto v0.1.0 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/dvsekhvalnov/jose2go v0.0.0-20200901110807-248326c1351b // indirect
@ -77,49 +87,58 @@ require (
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
github.com/go-kit/kit v0.10.0 // indirect
github.com/go-logfmt/logfmt v0.5.0 // indirect
github.com/go-ole/go-ole v1.2.1 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gogo/gateway v1.1.0 // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/btree v1.0.0 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/flatbuffers v2.0.0+incompatible // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/gtank/ristretto255 v0.1.2 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-getter v1.5.11 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-safetemp v1.0.0 // indirect
github.com/hashicorp/go-version v1.2.1 // indirect
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hdevalence/ed25519consensus v0.0.0-20210204194344-59a8610d2b87 // indirect
github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/huin/goupnp v1.0.2 // indirect
github.com/huin/goupnp v1.0.3-0.20220313090229-ca81a64b4204 // 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
github.com/ipfs/go-ipfs-util v0.0.1 // indirect
github.com/ipfs/go-ipld-format v0.0.1 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jmhodges/levigo v1.0.0 // indirect
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d // indirect
github.com/klauspost/compress v1.11.7 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/lib/pq v1.10.2 // indirect
github.com/lazyledger/smt v0.2.1-0.20210709230900-03ea40719554 // indirect
github.com/lib/pq v1.10.4 // indirect
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 // indirect
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
github.com/minio/highwayhash v1.0.1 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/minio/sha256-simd v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.4.3 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect
github.com/mtibben/percent v0.2.1 // indirect
@ -127,23 +146,23 @@ require (
github.com/multiformats/go-multibase v0.0.1 // indirect
github.com/multiformats/go-varint v0.0.6 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/oasisprotocol/curve25519-voi v0.0.0-20210609091139-0a56a4bca00b // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992 // indirect
github.com/prometheus/client_golang v1.11.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.29.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/prometheus/common v0.33.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/prometheus/tsdb v0.7.1 // indirect
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
github.com/rjeczalik/notify v0.9.1 // indirect
github.com/rs/zerolog v1.23.0 // indirect
github.com/sasha-s/go-deadlock v0.2.1-0.20190427202633-1595213edefa // indirect
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.6.0 // indirect
github.com/spf13/afero v1.8.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
@ -151,29 +170,40 @@ require (
github.com/tendermint/btcd v0.1.1 // indirect
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 // indirect
github.com/tendermint/go-amino v0.16.0 // indirect
github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/tendermint/tm-db v0.6.7 // indirect
github.com/tklauser/go-sysconf v0.3.9 // indirect
github.com/tklauser/numcpus v0.3.0 // indirect
github.com/ulikunitz/xz v0.5.8 // indirect
github.com/whyrusleeping/cbor-gen v0.0.0-20200123233031-1cdf64d27158 // indirect
github.com/zondax/hid v0.9.0 // indirect
github.com/zondax/hid v0.9.1-0.20220302062450-5552068d2266 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
go.opencensus.io v0.23.0 // indirect
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.9 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
google.golang.org/api v0.63.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
gopkg.in/ini.v1 v1.66.3 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
lukechampine.com/blake3 v1.1.6 // indirect
nhooyr.io/websocket v1.8.6 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)
replace (
github.com/99designs/keyring => github.com/cosmos/keyring v1.1.7-0.20210622111912-ef00f8ac3d76
// replace cosmos
github.com/cosmos/cosmos-sdk => github.com/vulcanize/cosmos-sdk v0.46.0-smt-0.0.3-alpha
github.com/cosmos/cosmos-sdk/db => github.com/vulcanize/cosmos-sdk/db v1.0.0-beta.1
github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1
google.golang.org/grpc => google.golang.org/grpc v1.33.2
google.golang.org/grpc => google.golang.org/grpc v1.44.0
)

720
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -49,17 +49,17 @@ func getNetInfo(client client.Context) (string, []*PeerInfo, error) {
return "", nil, err
}
peers := netInfo.Peers
peersInfo := make([]*PeerInfo, len(peers))
for index, peer := range peers {
peersInfo := make([]*PeerInfo, netInfo.NPeers)
// TODO: find a way to get the peer information from nodeClient
for index, peer := range netInfo.Peers {
peersInfo[index] = &PeerInfo{
Node: &NodeInfo{
ID: string(peer.NodeInfo.ID()),
Moniker: peer.NodeInfo.Moniker,
Network: peer.NodeInfo.Network,
ID: string(peer.ID),
// Moniker: peer.Node.Moniker,
// Network: peer.Node.Network,
},
IsOutbound: peer.IsOutbound,
RemoteIP: peer.RemoteIP,
// IsOutbound: peer.IsOutbound,
// RemoteIP: peer.RemoteIP,
}
}

View File

@ -3,6 +3,8 @@
package rpc
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server"
@ -35,92 +37,96 @@ const (
apiVersion = "1.0"
)
// GetRPCAPIs returns the list of all APIs
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, selectedAPIs []string) []rpc.API {
// APICreator creates the json-rpc api implementations.
type APICreator = func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API
// apiCreators defines the json-rpc api namespaces.
var apiCreators map[string]APICreator
func init() {
apiCreators = map[string]APICreator{
EthNamespace: func(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API {
nonceLock := new(types.AddrLocker)
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
var apis []rpc.API
// remove duplicates
selectedAPIs = unique(selectedAPIs)
for index := range selectedAPIs {
switch selectedAPIs[index] {
case EthNamespace:
apis = append(apis,
rpc.API{
return []rpc.API{
{
Namespace: EthNamespace,
Version: apiVersion,
Service: eth.NewPublicAPI(ctx.Logger, clientCtx, evmBackend, nonceLock),
Public: true,
},
rpc.API{
{
Namespace: EthNamespace,
Version: apiVersion,
Service: filters.NewPublicAPI(ctx.Logger, clientCtx, tmWSClient, evmBackend),
Public: true,
},
)
case Web3Namespace:
apis = append(apis,
rpc.API{
}
},
Web3Namespace: func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API {
return []rpc.API{
{
Namespace: Web3Namespace,
Version: apiVersion,
Service: web3.NewPublicAPI(),
Public: true,
},
)
case NetNamespace:
apis = append(apis,
rpc.API{
}
},
NetNamespace: func(_ *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
return []rpc.API{
{
Namespace: NetNamespace,
Version: apiVersion,
Service: net.NewPublicAPI(clientCtx),
Public: true,
},
)
case PersonalNamespace:
apis = append(apis,
rpc.API{
}
},
PersonalNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
return []rpc.API{
{
Namespace: PersonalNamespace,
Version: apiVersion,
Service: personal.NewAPI(ctx.Logger, clientCtx, evmBackend),
Public: false,
},
)
case TxPoolNamespace:
apis = append(apis,
rpc.API{
}
},
TxPoolNamespace: func(ctx *server.Context, _ client.Context, _ *rpcclient.WSClient) []rpc.API {
return []rpc.API{
{
Namespace: TxPoolNamespace,
Version: apiVersion,
Service: txpool.NewPublicAPI(ctx.Logger),
Public: true,
},
)
case DebugNamespace:
apis = append(apis,
rpc.API{
}
},
DebugNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
return []rpc.API{
{
Namespace: DebugNamespace,
Version: apiVersion,
Service: debug.NewAPI(ctx, evmBackend, clientCtx),
Public: true,
},
)
case MinerNamespace:
apis = append(apis,
rpc.API{
}
},
MinerNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
return []rpc.API{
{
Namespace: MinerNamespace,
Version: apiVersion,
Service: miner.NewPrivateAPI(ctx, clientCtx, evmBackend),
Public: false,
},
)
default:
ctx.Logger.Error("invalid namespace value", "namespace", selectedAPIs[index])
}
},
}
return apis
}
func unique(intSlice []string) []string {
@ -134,3 +140,28 @@ func unique(intSlice []string) []string {
}
return list
}
// GetRPCAPIs returns the list of all APIs
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, selectedAPIs []string) []rpc.API {
var apis []rpc.API
for _, ns := range selectedAPIs {
if creator, ok := apiCreators[ns]; ok {
apis = append(apis, creator(ctx, clientCtx, tmWSClient)...)
} else {
ctx.Logger.Error("invalid namespace value", "namespace", ns)
}
}
return apis
}
// RegisterAPINamespace registers a new API namespace with the API creator.
// This function fails if the namespace is already registered.
func RegisterAPINamespace(ns string, creator APICreator) error {
if _, ok := apiCreators[ns]; ok {
return fmt.Errorf("duplicated api namespace %s", ns)
}
apiCreators[ns] = creator
return nil
}

View File

@ -1,7 +1,6 @@
package backend
import (
"bytes"
"context"
"encoding/json"
"fmt"
@ -15,7 +14,8 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
tmrpctypes "github.com/tendermint/tendermint/rpc/coretypes"
"google.golang.org/grpc"
"google.golang.org/grpc/metadata"
@ -334,8 +334,8 @@ func (e *EVMBackend) BlockBloom(height *int64) (ethtypes.Bloom, error) {
}
for _, attr := range event.Attributes {
if bytes.Equal(attr.Key, bAttributeKeyEthereumBloom) {
return ethtypes.BytesToBloom(attr.Value), nil
if attr.Key == string(bAttributeKeyEthereumBloom) {
return ethtypes.BytesToBloom([]byte(attr.Value)), nil
}
}
}

View File

@ -7,7 +7,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/rpc"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
tmrpctypes "github.com/tendermint/tendermint/rpc/coretypes"
rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)

View File

@ -238,12 +238,12 @@ func TxLogsFromEvents(events []abci.Event, msgIndex int) ([]*ethtypes.Log, error
func ParseTxLogsFromEvent(event abci.Event) ([]*ethtypes.Log, error) {
logs := make([]*evmtypes.Log, 0, len(event.Attributes))
for _, attr := range event.Attributes {
if !bytes.Equal(attr.Key, []byte(evmtypes.AttributeKeyTxLog)) {
if !bytes.Equal([]byte(attr.Key), []byte(evmtypes.AttributeKeyTxLog)) {
continue
}
var log evmtypes.Log
if err := json.Unmarshal(attr.Value, &log); err != nil {
if err := json.Unmarshal([]byte(attr.Value), &log); err != nil {
return nil, err
}

View File

@ -14,7 +14,7 @@ import (
"time"
"github.com/davecgh/go-spew/spew"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
tmrpctypes "github.com/tendermint/tendermint/rpc/coretypes"
evmtypes "github.com/tharsis/ethermint/x/evm/types"

View File

@ -20,7 +20,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/log"
tmrpctypes "github.com/tendermint/tendermint/rpc/core/types"
tmrpctypes "github.com/tendermint/tendermint/rpc/coretypes"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
@ -74,6 +74,7 @@ func NewPublicAPI(
viper.GetString(flags.FlagKeyringBackend),
clientCtx.KeyringDir,
clientCtx.Input,
clientCtx.Codec,
hd.EthSecp256k1Option(),
)
if err != nil {
@ -242,7 +243,11 @@ func (e *PublicAPI) Accounts() ([]common.Address, error) {
}
for _, info := range infos {
addressBytes := info.GetPubKey().Address().Bytes()
pubKey, err := info.GetPubKey()
if err != nil {
return addresses, err
}
addressBytes := pubKey.Address().Bytes()
addresses = append(addresses, common.BytesToAddress(addressBytes))
}

View File

@ -11,7 +11,7 @@ import (
"github.com/tendermint/tendermint/libs/log"
coretypes "github.com/tendermint/tendermint/rpc/core/types"
coretypes "github.com/tendermint/tendermint/rpc/coretypes"
rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
tmtypes "github.com/tendermint/tendermint/types"
@ -371,7 +371,13 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit filters.FilterCriteri
}
// filter only events from EVM module txs
_, isMsgEthereumTx := ev.Events[evmtypes.TypeMsgEthereumTx]
var isMsgEthereumTx bool
for _, event := range ev.Events {
if event.Type == evmtypes.TypeMsgEthereumTx {
isMsgEthereumTx = true
}
}
if !isMsgEthereumTx {
// ignore transaction as it's not from the evm module
@ -385,7 +391,7 @@ func (api *PublicFilterAPI) Logs(ctx context.Context, crit filters.FilterCriteri
continue
}
txResponse, err := evmtypes.DecodeTxResponse(dataTx.TxResult.Result.Data)
txResponse, err := evmtypes.DecodeTxResponse(dataTx.TxResult.Result.Data, api.clientCtx.Codec)
if err != nil {
return
}
@ -461,7 +467,7 @@ func (api *PublicFilterAPI) NewFilter(criteria filters.FilterCriteria) (rpc.ID,
continue
}
txResponse, err := evmtypes.DecodeTxResponse(dataTx.TxResult.Result.Data)
txResponse, err := evmtypes.DecodeTxResponse(dataTx.TxResult.Result.Data, api.clientCtx.Codec)
if err != nil {
return
}

View File

@ -11,7 +11,7 @@ import (
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/tendermint/tendermint/libs/log"
tmquery "github.com/tendermint/tendermint/libs/pubsub/query"
coretypes "github.com/tendermint/tendermint/rpc/core/types"
coretypes "github.com/tendermint/tendermint/rpc/coretypes"
rpcclient "github.com/tendermint/tendermint/rpc/jsonrpc/client"
tmtypes "github.com/tendermint/tendermint/types"
@ -27,9 +27,9 @@ import (
)
var (
txEvents = tmtypes.QueryForEvent(tmtypes.EventTx).String()
evmEvents = tmquery.MustParse(fmt.Sprintf("%s='%s' AND %s.%s='%s'", tmtypes.EventTypeKey, tmtypes.EventTx, sdk.EventTypeMessage, sdk.AttributeKeyModule, evmtypes.ModuleName)).String()
headerEvents = tmtypes.QueryForEvent(tmtypes.EventNewBlockHeader).String()
txEvents = tmtypes.QueryForEvent(tmtypes.EventTxValue).String()
evmEvents = tmquery.MustCompile(fmt.Sprintf("%s='%s' AND %s.%s='%s'", tmtypes.EventTypeKey, tmtypes.EventTxValue, sdk.EventTypeMessage, sdk.AttributeKeyModule, evmtypes.ModuleName)).String()
headerEvents = tmtypes.QueryForEvent(tmtypes.EventNewBlockHeaderValue).String()
)
// EventSystem creates subscriptions, processes events and broadcasts them to the

View File

@ -7,7 +7,7 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/rpc"
coretypes "github.com/tendermint/tendermint/rpc/core/types"
coretypes "github.com/tendermint/tendermint/rpc/coretypes"
)
// Subscription defines a wrapper for the private subscription

View File

@ -124,7 +124,7 @@ func (api *API) SetEtherbase(etherbase common.Address) bool {
return false
}
if err := tx.Sign(txFactory, keyInfo.GetName(), builder, false); err != nil {
if err := tx.Sign(txFactory, keyInfo.Name, builder, false); err != nil {
api.logger.Debug("failed to sign tx", "error", err.Error())
return false
}

View File

@ -102,7 +102,11 @@ func (api *PrivateAccountAPI) ListAccounts() ([]common.Address, error) {
}
for _, info := range list {
addrs = append(addrs, common.BytesToAddress(info.GetPubKey().Address()))
pubKey, err := info.GetPubKey()
if err != nil {
return nil, err
}
addrs = append(addrs, common.BytesToAddress(pubKey.Address()))
}
return addrs, nil
@ -131,7 +135,8 @@ func (api *PrivateAccountAPI) NewAccount(password string) (common.Address, error
return common.Address{}, err
}
addr := common.BytesToAddress(info.GetPubKey().Address().Bytes())
pubKeyAddr, err := info.GetAddress()
addr := common.BytesToAddress(pubKeyAddr.Bytes())
api.logger.Info("Your new key was generated", "address", addr.String())
api.logger.Info("Please backup your key file!", "path", os.Getenv("HOME")+"/.ethermint/"+name) // TODO: pass the correct binary
api.logger.Info("Please remember your password!")

View File

@ -6,7 +6,7 @@ import (
"github.com/pkg/errors"
coretypes "github.com/tendermint/tendermint/rpc/core/types"
coretypes "github.com/tendermint/tendermint/rpc/coretypes"
)
type UnsubscribeFunc func()

View File

@ -8,7 +8,7 @@ import (
"time"
"github.com/stretchr/testify/require"
coretypes "github.com/tendermint/tendermint/rpc/core/types"
coretypes "github.com/tendermint/tendermint/rpc/coretypes"
)
func TestAddTopic(t *testing.T) {

View File

@ -242,7 +242,7 @@ func BaseFeeFromEvents(events []abci.Event) *big.Int {
}
for _, attr := range event.Attributes {
if bytes.Equal(attr.Key, []byte(feemarkettypes.AttributeKeyBaseFee)) {
if attr.Key == feemarkettypes.AttributeKeyBaseFee {
result, success := new(big.Int).SetString(string(attr.Value), 10)
if success {
return result
@ -250,6 +250,14 @@ func BaseFeeFromEvents(events []abci.Event) *big.Int {
return nil
}
// if bytes.Equal(attr.Key, []byte(feemarkettypes.AttributeKeyBaseFee)) {
// result, success := new(big.Int).SetString(string(attr.Value), 10)
// if success {
// return result
// }
// return nil
// }
}
}
return nil
@ -310,10 +318,10 @@ func FindTxAttributesByIndex(events []abci.Event, txIndex uint64) int {
// FindAttribute find event attribute with specified key, if not found returns nil.
func FindAttribute(attrs []abci.EventAttribute, key []byte) []byte {
for _, attr := range attrs {
if !bytes.Equal(attr.Key, key) {
if !bytes.Equal([]byte(attr.Key), key) {
continue
}
return attr.Value
return []byte(attr.Value)
}
return nil
}

View File

@ -536,7 +536,7 @@ func (api *pubSubAPI) subscribeLogs(wsConn *wsConn, subID rpc.ID, extra interfac
continue
}
txResponse, err := evmtypes.DecodeTxResponse(dataTx.TxResult.Result.Data)
txResponse, err := evmtypes.DecodeTxResponse(dataTx.TxResult.Result.Data, api.clientCtx.Codec)
if err != nil {
api.logger.Error("failed to decode tx response", "error", err.Error())
return

View File

@ -35,7 +35,7 @@ cat $HOME/.chibaclonkd/config/genesis.json | jq '.app_state["mint"]["params"]["m
"$PWD"/build/chibaclonkd validate-genesis
# Start the node (remove the --pruning=nothing flag if historical queries are not needed) in background and log to file
"$PWD"/build/chibaclonkd start --pruning=nothing --rpc.unsafe --json-rpc.address="0.0.0.0:8545" --keyring-backend test > ethermintd.log 2>&1 &
"$PWD"/build/chibaclonkd start --pruning=nothing --mode validator --rpc.unsafe --json-rpc.address="0.0.0.0:8545" --keyring-backend test > ethermintd.log 2>&1 &
# Give ethermintd node enough time to launch
sleep 5

View File

@ -17,10 +17,10 @@ RPC_PORT="854"
IP_ADDR="0.0.0.0"
KEY="mykey"
CHAINID="ethermint_9000-1"
CHAINID="chibaclonk_9000-1"
MONIKER="mymoniker"
## default port prefixes for ethermintd
## default port prefixes for chibaclonkd
NODE_P2P_PORT="2660"
NODE_PORT="2663"
NODE_RPC_PORT="2666"
@ -32,6 +32,7 @@ usage() {
echo "-q <number> -- Quantity of nodes to run. eg: 3"
echo "-z <number> -- Quantity of nodes to run tests against eg: 3"
echo "-s <number> -- Sleep between operations in secs. eg: 5"
echo "-m <string> -- Mode for testing. eg: rpc"
echo "-r <string> -- Remove test dir after, eg: true, default is false"
exit 1
}
@ -52,15 +53,15 @@ done
set -euxo pipefail
DATA_DIR=$(mktemp -d -t ethermint-datadir.XXXXX)
DATA_DIR=$(mktemp -d -t chibaclonk-datadir.XXXXX)
if [[ ! "$DATA_DIR" ]]; then
echo "Could not create $DATA_DIR"
exit 1
fi
# Compile ethermint
echo "compiling ethermint"
# Compile chibaclonk
echo "compiling chibaclonk"
make build
# PID array declaration
@ -103,18 +104,22 @@ init_func() {
}
start_func() {
echo "starting ethermint node $i in background ..."
"$PWD"/build/chibaclonkd start --pruning=nothing --rpc.unsafe \
--p2p.laddr tcp://$IP_ADDR:$NODE_P2P_PORT"$i" --address tcp://$IP_ADDR:$NODE_PORT"$i" --rpc.laddr tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \
echo "starting chibaclonk node $i in background ..."
"$PWD"/build/chibaclonkd start \
--pruning=nothing --rpc.unsafe \
--p2p.laddr tcp://$IP_ADDR:$NODE_P2P_PORT"$i" \
--address tcp://$IP_ADDR:$NODE_PORT"$i" \
--rpc.laddr tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \
--json-rpc.address=$IP_ADDR:$RPC_PORT"$i" \
--json-rpc.api="eth,txpool,personal,net,debug,web3" \
--keyring-backend test --home "$DATA_DIR$i" \
--keyring-backend test --mode validator --home "$DATA_DIR$i" \
--log_level debug \
>"$DATA_DIR"/node"$i".log 2>&1 & disown
ETHERMINT_PID=$!
echo "started ethermint node, pid=$ETHERMINT_PID"
CHIBACLONK_PID=$!
echo "started chibaclonk node, pid=$CHIBACLONK_PID"
# add PID to array
arr+=("$ETHERMINT_PID")
arr+=("$CHIBACLONK_PID")
if [[ $MODE == "pending" ]]; then
echo "waiting for the first block..."
@ -144,7 +149,7 @@ if [[ -z $TEST || $TEST == "integration" ]] ; then
for i in $(seq 1 "$TEST_QTD"); do
HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i"
echo "going to test ethermint node $HOST_RPC ..."
echo "going to test chibaclonk node $HOST_RPC ..."
MODE=$MODE HOST=$HOST_RPC go test ./tests/e2e/... -timeout=$time_out -v -short
TEST_FAIL=$?
done
@ -158,21 +163,20 @@ if [[ -z $TEST || $TEST == "rpc" || $TEST == "pending" ]]; then
for i in $(seq 1 "$TEST_QTD"); do
HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i"
echo "going to test ethermint node $HOST_RPC ..."
echo "going to test chibaclonk node $HOST_RPC ..."
MODE=$MODE HOST=$HOST_RPC go test ./tests/rpc/... -timeout=$time_out -v -short
TEST_FAIL=$?
done
fi
stop_func() {
ETHERMINT_PID=$i
echo "shutting down node, pid=$ETHERMINT_PID ..."
CHIBACLONK_PID=$i
echo "shutting down node, pid=$CHIBACLONK_PID ..."
# Shutdown ethermint node
kill -9 "$ETHERMINT_PID"
wait "$ETHERMINT_PID"
# Shutdown chibaclonk node
kill -9 "$CHIBACLONK_PID"
wait "$CHIBACLONK_PID"
if [ $REMOVE_DATA_DIR == "true" ]
then

View File

@ -3,7 +3,7 @@ export GOPATH=~/go
export PATH=$PATH:$GOPATH/bin
# remove existing daemon
rm -rf ~/.ethermintd
rm -rf ~/.chibaclonk*
# build ethermint binary
make install

View File

@ -6,7 +6,8 @@ chibaclonkd validate-genesis --home /chibaclonk
echo "starting chibaclonk node $ID in background ..."
chibaclonkd start \
--home /chibaclonk \
--keyring-backend test
--keyring-backend test \
--mode validator
echo "started ethermint node"
tail -f /dev/null

View File

@ -61,8 +61,8 @@ if [[ ! "$DATA_CLI_DIR" ]]; then
exit 1
fi
# Compile ethermint
echo "compiling ethermint"
# Compile chibaclonk
echo "compiling chibaclonk"
make build
# PID array declaration
@ -89,15 +89,15 @@ init_func() {
}
start_func() {
echo "starting ethermint node $i in background ..."
echo "starting chibaclonk node $i in background ..."
"$PWD"/build/chibaclonkd start --pruning=nothing --rpc.unsafe \
--p2p.laddr tcp://$IP_ADDR:$NODE_P2P_PORT"$i" --address tcp://$IP_ADDR:$NODE_PORT"$i" --rpc.laddr tcp://$IP_ADDR:$NODE_RPC_PORT"$i" \
--json-rpc.address=$IP_ADDR:$RPC_PORT"$i" \
--keyring-backend test --home "$DATA_DIR$i" \
--keyring-backend test --mode validator --home "$DATA_DIR$i" \
>"$DATA_DIR"/node"$i".log 2>&1 & disown
ETHERMINT_PID=$!
echo "started ethermint node, pid=$ETHERMINT_PID"
echo "started chibaclonk node, pid=$ETHERMINT_PID"
# add PID to array
arr+=("$ETHERMINT_PID")
}
@ -123,7 +123,7 @@ if [[ -z $TEST || $TEST == "rpc" ]]; then
for i in $(seq 1 "$TEST_QTD"); do
HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i"
echo "going to test ethermint node $HOST_RPC ..."
echo "going to test chibaclonk node $HOST_RPC ..."
MODE=$MODE HOST=$HOST_RPC go test ./tests/e2e/... -timeout=300s -v -short
MODE=$MODE HOST=$HOST_RPC go test ./tests/rpc/... -timeout=300s -v -short
@ -136,7 +136,7 @@ stop_func() {
ETHERMINT_PID=$i
echo "shutting down node, pid=$ETHERMINT_PID ..."
# Shutdown ethermint node
# Shutdown chibaclonk node
kill -9 "$ETHERMINT_PID"
wait "$ETHERMINT_PID"
}

View File

@ -16,30 +16,27 @@ import (
"github.com/spf13/cobra"
tmservice "github.com/tendermint/tendermint/libs/service"
"google.golang.org/grpc"
abciserver "github.com/tendermint/tendermint/abci/server"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
tmos "github.com/tendermint/tendermint/libs/os"
"github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/p2p"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/rpc/client/local"
dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/server/rosetta"
crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
dbm "github.com/cosmos/cosmos-sdk/db"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
servergrpc "github.com/cosmos/cosmos-sdk/server/grpc"
"github.com/cosmos/cosmos-sdk/server/rosetta"
crgserver "github.com/cosmos/cosmos-sdk/server/rosetta/lib/server"
"github.com/cosmos/cosmos-sdk/server/types"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
abciclient "github.com/tendermint/tendermint/abci/client"
abciserver "github.com/tendermint/tendermint/abci/server"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
tmos "github.com/tendermint/tendermint/libs/os"
"github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/rpc/client/local"
tmtypes "github.com/tendermint/tendermint/types"
ethdebug "github.com/tharsis/ethermint/rpc/ethereum/namespaces/debug"
"github.com/tharsis/ethermint/server/config"
@ -48,6 +45,16 @@ import (
"github.com/tharsis/ethermint/gql"
)
const (
// gRPC-related flags
flagGRPCOnly = "grpc-only"
flagGRPCEnable = "grpc.enable"
flagGRPCAddress = "grpc.address"
flagGRPCWebEnable = "grpc-web.enable"
flagGRPCWebAddress = "grpc-web.address"
)
// StartCmd runs the service passed in, either stand-alone or in-process with
// Tendermint.
func StartCmd(appCreator types.AppCreator, defaultNodeHome string) *cobra.Command {
@ -141,7 +148,6 @@ which accepts a path for the resulting pprof file.
cmd.Flags().Bool(server.FlagTrace, false, "Provide full stack traces for errors in ABCI Log")
cmd.Flags().String(server.FlagPruning, storetypes.PruningOptionDefault, "Pruning strategy (default|nothing|everything|custom)")
cmd.Flags().Uint64(server.FlagPruningKeepRecent, 0, "Number of recent heights to keep on disk (ignored if pruning is not 'custom')")
cmd.Flags().Uint64(server.FlagPruningKeepEvery, 0, "Offset heights to keep on disk after 'keep-every' (ignored if pruning is not 'custom')")
cmd.Flags().Uint64(server.FlagPruningInterval, 0, "Height interval at which pruned heights are removed from disk (ignored if pruning is not 'custom')")
cmd.Flags().Uint(server.FlagInvCheckPeriod, 0, "Assert registered invariants every N blocks")
cmd.Flags().Uint64(server.FlagMinRetainBlocks, 0, "Minimum block height offset during ABCI commit to prune Tendermint blocks")
@ -186,10 +192,11 @@ func startStandAlone(ctx *server.Context, appCreator types.AppCreator) error {
transport := ctx.Viper.GetString(srvflags.Transport)
home := ctx.Viper.GetString(flags.FlagHome)
db, err := openDB(home)
db, err := openDB(home, server.GetAppDBBackend((ctx.Viper)))
if err != nil {
return err
}
defer func() {
if err := db.Close(); err != nil {
ctx.Logger.With("error", err).Error("error closing db")
@ -261,9 +268,8 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
}
traceWriterFile := ctx.Viper.GetString(srvflags.TraceStore)
db, err := openDB(home)
db, err := openDB(home, server.GetAppDBBackend(ctx.Viper))
if err != nil {
logger.Error("failed to open DB", "error", err.Error())
return err
}
defer func() {
@ -294,38 +300,46 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
app := appCreator(ctx.Logger, db, traceWriter, ctx.Viper)
nodeKey, err := p2p.LoadOrGenNodeKey(cfg.NodeKeyFile())
genDoc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile())
if err != nil {
logger.Error("failed load or gen node key", "error", err.Error())
return err
}
genDocProvider := node.DefaultGenesisDocProviderFunc(cfg)
tmNode, err := node.NewNode(
cfg,
pvm.LoadOrGenFilePV(cfg.PrivValidatorKeyFile(), cfg.PrivValidatorStateFile()),
nodeKey,
proxy.NewLocalClientCreator(app),
genDocProvider,
node.DefaultDBProvider,
node.DefaultMetricsProvider(cfg.Instrumentation),
ctx.Logger.With("server", "node"),
var (
tmNode tmservice.Service
gRPCOnly = ctx.Viper.GetBool(flagGRPCOnly)
)
if gRPCOnly {
ctx.Logger.Info("starting node in gRPC only mode; Tendermint is disabled")
config.GRPC.Enable = true
} else {
ctx.Logger.Info("starting node with ABCI Tendermint in-process")
tmNode, err = node.New(cfg, ctx.Logger, abciclient.NewLocalCreator(app), genDoc)
if err != nil {
logger.Error("failed init node", "error", err.Error())
return err
}
if err := tmNode.Start(); err != nil {
logger.Error("failed start tendermint server", "error", err.Error())
return err
}
}
// Add the tx service to the gRPC router. We only need to register this
// service if API or gRPC or JSONRPC is enabled, and avoid doing so in the general
// case, because it spawns a new local tendermint RPC client.
if config.API.Enable || config.GRPC.Enable || config.JSONRPC.Enable {
clientCtx = clientCtx.WithClient(local.New(tmNode))
node, ok := tmNode.(local.NodeService)
if !ok {
return fmt.Errorf("unable to set node type; please try re-installing the binary")
}
localNode, err := local.New(node)
if err != nil {
return err
}
clientCtx = clientCtx.WithClient(localNode)
app.RegisterTxService(clientCtx)
app.RegisterTendermintService(clientCtx)
@ -333,7 +347,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
var apiSrv *api.Server
if config.API.Enable {
genDoc, err := genDocProvider()
genDoc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile())
if err != nil {
return err
}
@ -419,7 +433,7 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
)
if config.JSONRPC.Enable {
genDoc, err := genDocProvider()
genDoc, err := tmtypes.GenesisDocFromFile(cfg.GenesisFile())
if err != nil {
return err
}
@ -481,9 +495,9 @@ func startInProcess(ctx *server.Context, clientCtx client.Context, appCreator ty
return server.WaitForQuitSignals()
}
func openDB(rootDir string) (dbm.DB, error) {
func openDB(rootDir string, backendType dbm.BackendType) (dbm.DBConnection, error) {
dataDir := filepath.Join(rootDir, "data")
return sdk.NewLevelDB("application", dataDir)
return dbm.NewDB("application", backendType, dataDir)
}
func openTraceWriter(traceWriterFile string) (w io.Writer, err error) {

View File

@ -43,15 +43,16 @@ func AddCommands(rootCmd *cobra.Command, defaultNodeHome string, appCreator type
}
func ConnectTmWS(tmRPCAddr, tmEndpoint string, logger tmlog.Logger) *rpcclient.WSClient {
tmWsClient, err := rpcclient.NewWS(tmRPCAddr, tmEndpoint,
rpcclient.MaxReconnectAttempts(256),
rpcclient.ReadWait(120*time.Second),
rpcclient.WriteWait(120*time.Second),
rpcclient.PingPeriod(50*time.Second),
rpcclient.OnReconnect(func() {
tmWsClient, err := rpcclient.NewWSWithOptions(tmRPCAddr, tmEndpoint, rpcclient.WSOptions{
MaxReconnectAttempts: 256, // first: 2 sec, last: 17 min.
WriteWait: 120 * time.Second,
ReadWait: 120 * time.Second,
PingPeriod: 50 * time.Second,
})
tmWsClient.OnReconnect(func() {
logger.Debug("EVM RPC reconnects to Tendermint WS", "address", tmRPCAddr+tmEndpoint)
}),
)
})
if err != nil {
logger.Error(
@ -59,7 +60,7 @@ func ConnectTmWS(tmRPCAddr, tmEndpoint string, logger tmlog.Logger) *rpcclient.W
"address", tmRPCAddr+tmEndpoint,
"error", err,
)
} else if err := tmWsClient.OnStart(); err != nil {
} else if err := tmWsClient.Start(); err != nil {
logger.Error(
"Tendermint WS client could not start",
"address", tmRPCAddr+tmEndpoint,

View File

@ -59,7 +59,7 @@ type ImporterTestSuite struct {
/// DoSetupTest setup test environment, it uses`require.TestingT` to support both `testing.T` and `testing.B`.
func (suite *ImporterTestSuite) DoSetupTest(t require.TestingT) {
checkTx := false
suite.app = app.Setup(checkTx, nil)
suite.app = app.Setup(suite.T(), checkTx, nil)
// consensus key
priv, err := ethsecp256k1.GenerateKey()
require.NoError(t, err)

View File

@ -301,17 +301,6 @@ func deployTestContract(t *testing.T) (hexutil.Bytes, map[string]interface{}) {
return hash, receipt
}
func getTransactionReceipt(t *testing.T, hash hexutil.Bytes) map[string]interface{} {
param := []string{hash.String()}
rpcRes := call(t, "eth_getTransactionReceipt", param)
receipt := make(map[string]interface{})
err := json.Unmarshal(rpcRes.Result, &receipt)
require.NoError(t, err)
return receipt
}
func waitForReceipt(t *testing.T, hash hexutil.Bytes) map[string]interface{} {
timeout := time.After(12 * time.Second)
ticker := time.Tick(500 * time.Millisecond)
@ -321,7 +310,7 @@ func waitForReceipt(t *testing.T, hash hexutil.Bytes) map[string]interface{} {
case <-timeout:
return nil
case <-ticker:
receipt := getTransactionReceipt(t, hash)
receipt := GetTransactionReceipt(t, hash)
if receipt != nil {
return receipt
}

View File

@ -58,4 +58,4 @@ chibaclonkd collect-gentxs
chibaclonkd validate-genesis
# Start the node (remove the --pruning=nothing flag if historical queries are not needed)
chibaclonkd start --pruning=nothing --rpc.unsafe --keyring-backend test --log_level info --json-rpc.api eth,txpool,personal,net,debug,web3 --api.enable
chibaclonkd start --pruning=nothing --rpc.unsafe --keyring-backend test --log_level info --json-rpc.api eth,txpool,personal,net,debug,web3 --api.enable --mode validator

View File

@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"math/rand"
"net/http"
"net/url"
"os"
@ -15,16 +16,14 @@ import (
"testing"
"time"
tmcfg "github.com/tendermint/tendermint/config"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/rs/zerolog"
"github.com/spf13/cobra"
tmcfg "github.com/tendermint/tendermint/config"
tmflags "github.com/tendermint/tendermint/libs/cli/flags"
"github.com/tendermint/tendermint/libs/log"
tmrand "github.com/tendermint/tendermint/libs/rand"
"github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/libs/service"
tmclient "github.com/tendermint/tendermint/rpc/client"
dbm "github.com/tendermint/tm-db"
"google.golang.org/grpc"
"github.com/cosmos/cosmos-sdk/baseapp"
@ -34,6 +33,7 @@ import (
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keyring"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/db/memdb"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/api"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
@ -68,7 +68,7 @@ type AppConstructor = func(val Validator) servertypes.Application
func NewAppConstructor(encodingCfg params.EncodingConfig) AppConstructor {
return func(val Validator) servertypes.Application {
return app.NewEthermintApp(
val.Ctx.Logger, dbm.NewMemDB(), nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0,
val.Ctx.Logger, memdb.NewDB(), nil, true, make(map[int64]bool), val.Ctx.Config.RootDir, 0,
encodingCfg,
simapp.EmptyAppOptions{},
baseapp.SetPruning(storetypes.NewPruningOptionsFromString(val.AppConfig.Pruning)),
@ -113,15 +113,15 @@ func DefaultConfig() Config {
encCfg := encoding.MakeConfig(app.ModuleBasics)
return Config{
Codec: encCfg.Marshaler,
Codec: encCfg.Codec,
TxConfig: encCfg.TxConfig,
LegacyAmino: encCfg.Amino,
InterfaceRegistry: encCfg.InterfaceRegistry,
AccountRetriever: authtypes.AccountRetriever{},
AppConstructor: NewAppConstructor(encCfg),
GenesisState: app.ModuleBasics.DefaultGenesis(encCfg.Marshaler),
GenesisState: app.ModuleBasics.DefaultGenesis(encCfg.Codec),
TimeoutCommit: 2 * time.Second,
ChainID: fmt.Sprintf("ethermint_%d-1", tmrand.Int63n(9999999999999)+1),
ChainID: fmt.Sprintf("ethermint_%d-1", rand.Int63n(9999999999999)+1),
NumValidators: 4,
BondDenom: ethermint.AttoPhoton,
MinGasPrices: fmt.Sprintf("0.000006%s", ethermint.AttoPhoton),
@ -174,7 +174,7 @@ type (
RPCClient tmclient.Client
JSONRPCClient *ethclient.Client
tmNode *node.Node
tmNode service.Service
api *api.Server
grpc *grpc.Server
grpcWeb *http.Server
@ -255,6 +255,7 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) {
ctx := server.NewDefaultContext()
tmCfg := ctx.Config
tmCfg.Consensus.TimeoutCommit = cfg.TimeoutCommit
tmCfg.Mode = tmcfg.ModeValidator
// Only allow the first validator to expose an RPC, API and gRPC
// server/client due to Tendermint in-process constraints.
@ -322,17 +323,18 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) {
appCfg.JSONRPC.API = config.GetAPINamespaces()
}
logger := log.NewNopLogger()
logger := server.ZeroLogWrapper{Logger: zerolog.Nop()}
if cfg.EnableTMLogging {
logger = log.NewTMLogger(log.NewSyncWriter(os.Stdout))
logger, _ = tmflags.ParseLogLevel("info", logger, tmcfg.DefaultLogLevel)
logWriter := zerolog.ConsoleWriter{Out: os.Stderr}
logger = server.ZeroLogWrapper{Logger: zerolog.New(logWriter).Level(zerolog.InfoLevel).With().Timestamp().Logger()}
}
ctx.Logger = logger
ctx.Logger = logger
nodeDirName := fmt.Sprintf("node%d", i)
nodeDir := filepath.Join(network.BaseDir, nodeDirName, "evmosd")
clientDir := filepath.Join(network.BaseDir, nodeDirName, "evmoscli")
nodeDir := filepath.Join(network.BaseDir, nodeDirName, "chibaclonkd")
clientDir := filepath.Join(network.BaseDir, nodeDirName, "chibaclonkcli")
gentxsDir := filepath.Join(network.BaseDir, "gentxs")
err := os.MkdirAll(filepath.Join(nodeDir, "config"), 0o750)
@ -370,7 +372,7 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) {
nodeIDs[i] = nodeID
valPubKeys[i] = pubKey
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.KeyringOptions...)
kb, err := keyring.New(sdk.KeyringServiceName(), keyring.BackendTest, clientDir, buf, cfg.Codec, cfg.KeyringOptions...)
if err != nil {
return nil, err
}
@ -527,6 +529,13 @@ func New(l Logger, baseDir string, cfg Config) (*Network, error) {
l.Log("started test network")
height, err := network.LatestHeight()
if err != nil {
return nil, err
}
l.Log("started test network at height:", height)
// Ensure we cleanup incase any test was abruptly halted (e.g. SIGINT) as any
// defer in a test would not be called.
server.TrapSignal(network.Cleanup)
@ -560,22 +569,22 @@ func (n *Network) WaitForHeight(h int64) (int64, error) {
// provide a custom timeout.
func (n *Network) WaitForHeightWithTimeout(h int64, t time.Duration) (int64, error) {
ticker := time.NewTicker(time.Second)
timeout := time.After(t)
defer ticker.Stop()
timeout := time.NewTimer(t)
defer timeout.Stop()
if len(n.Validators) == 0 {
return 0, errors.New("no validators available")
}
var latestHeight int64
val := n.Validators[0]
for {
select {
case <-timeout:
ticker.Stop()
case <-timeout.C:
return latestHeight, errors.New("timeout exceeded waiting for block")
case <-ticker.C:
status, err := val.RPCClient.Status(context.Background())
status, err := n.Validators[0].RPCClient.Status(context.Background())
if err == nil && status != nil {
latestHeight = status.SyncInfo.LatestBlockHeight
if latestHeight >= h {
@ -629,21 +638,6 @@ func (n *Network) Cleanup() {
_ = v.grpcWeb.Close()
}
}
if v.jsonrpc != nil {
shutdownCtx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second)
defer cancelFn()
if err := v.jsonrpc.Shutdown(shutdownCtx); err != nil {
v.tmNode.Logger.Error("HTTP server shutdown produced a warning", "error", err.Error())
} else {
v.tmNode.Logger.Info("HTTP server shut down, waiting 5 sec")
select {
case <-time.Tick(5 * time.Second):
case <-v.jsonrpcDone:
}
}
}
}
if n.Config.CleanupDir {

View File

@ -3,18 +3,17 @@ package network
import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"time"
"github.com/ethereum/go-ethereum/ethclient"
abciclient "github.com/tendermint/tendermint/abci/client"
tmos "github.com/tendermint/tendermint/libs/os"
tmtime "github.com/tendermint/tendermint/libs/time"
"github.com/tendermint/tendermint/node"
"github.com/tendermint/tendermint/p2p"
pvm "github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/rpc/client/local"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/cosmos/cosmos-sdk/server/api"
servergrpc "github.com/cosmos/cosmos-sdk/server/grpc"
@ -25,9 +24,9 @@ import (
"github.com/cosmos/cosmos-sdk/x/genutil"
genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
mintypes "github.com/cosmos/cosmos-sdk/x/mint/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/tharsis/ethermint/server"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)
@ -41,36 +40,35 @@ func startInProcess(cfg Config, val *Validator) error {
return err
}
nodeKey, err := p2p.LoadOrGenNodeKey(tmCfg.NodeKeyFile())
app := cfg.AppConstructor(*val)
genDoc, err := types.GenesisDocFromFile(tmCfg.GenesisFile())
if err != nil {
return err
}
app := cfg.AppConstructor(*val)
genDocProvider := node.DefaultGenesisDocProviderFunc(tmCfg)
tmNode, err := node.NewNode(
val.tmNode, err = node.New(
tmCfg,
pvm.LoadOrGenFilePV(tmCfg.PrivValidatorKeyFile(), tmCfg.PrivValidatorStateFile()),
nodeKey,
proxy.NewLocalClientCreator(app),
genDocProvider,
node.DefaultDBProvider,
node.DefaultMetricsProvider(tmCfg.Instrumentation),
logger.With("module", val.Moniker),
abciclient.NewLocalCreator(app),
genDoc,
)
if err != nil {
return err
}
if err := tmNode.Start(); err != nil {
if err := val.tmNode.Start(); err != nil {
return err
}
val.tmNode = tmNode
if val.RPCAddress != "" {
val.RPCClient = local.New(tmNode)
node, ok := val.tmNode.(local.NodeService)
if !ok {
panic("can't cast service.Service to NodeService")
}
val.RPCClient, err = local.New(node)
if err != nil {
panic("cant create a local node")
}
}
// We'll need a RPC client if the validator exposes a gRPC or REST endpoint.
@ -152,7 +150,7 @@ func collectGenFiles(cfg Config, vals []*Validator, outputDir string) error {
for i := 0; i < cfg.NumValidators; i++ {
tmCfg := vals[i].Ctx.Config
nodeDir := filepath.Join(outputDir, vals[i].Moniker, "evmosd")
nodeDir := filepath.Join(outputDir, vals[i].Moniker, "chibaclonkd")
gentxsDir := filepath.Join(outputDir, "gentxs")
tmCfg.Moniker = vals[i].Moniker
@ -206,7 +204,7 @@ func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalance
stakingGenState.Params.BondDenom = cfg.BondDenom
cfg.GenesisState[stakingtypes.ModuleName] = cfg.Codec.MustMarshalJSON(&stakingGenState)
var govGenState govtypes.GenesisState
var govGenState v1.GenesisState
cfg.Codec.MustUnmarshalJSON(cfg.GenesisState[govtypes.ModuleName], &govGenState)
govGenState.DepositParams.MinDeposit[0].Denom = cfg.BondDenom
@ -252,12 +250,18 @@ func initGenFiles(cfg Config, genAccounts []authtypes.GenesisAccount, genBalance
}
func WriteFile(name string, dir string, contents []byte) error {
file := filepath.Join(dir, name)
writePath := filepath.Join(dir)
file := filepath.Join(writePath, name)
err := tmos.EnsureDir(dir, 0o755)
err := tmos.EnsureDir(writePath, 0755)
if err != nil {
return err
}
return tmos.WriteFile(file, contents, 0o644)
err = ioutil.WriteFile(file, contents, 0644) // nolint: gosec
if err != nil {
return err
}
return nil
}

6
types/address.go Normal file
View File

@ -0,0 +1,6 @@
package types
const (
// Bech32MainPrefix defines the main SDK Bech32 prefix of an account's address
Bech32MainPrefix = "ethm"
)

View File

@ -19,7 +19,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
&EthAccount{},
)
registry.RegisterInterface(
"ethermint.v1.ExtensionOptionsWeb3Tx",
"ethermint.types.v1.ExtensionOptionsWeb3Tx",
(*ExtensionOptionsWeb3TxI)(nil),
&ExtensionOptionsWeb3Tx{},
)

View File

@ -26,7 +26,7 @@ type infiniteGasMeterWithLimit struct {
}
// NewInfiniteGasMeterWithLimit returns a reference to a new infiniteGasMeter.
func NewInfiniteGasMeterWithLimit(limit sdk.Gas) sdk.GasMeter {
func NewInfiniteGasMeterWithLimit(limit sdk.Gas) *infiniteGasMeterWithLimit {
return &infiniteGasMeterWithLimit{
consumed: 0,
limit: limit,
@ -45,6 +45,14 @@ func (g *infiniteGasMeterWithLimit) Limit() sdk.Gas {
return g.limit
}
// GasRemaining returns the gas left in the GasMeter.
func (g *infiniteGasMeterWithLimit) GasRemaining() sdk.Gas {
if g.IsPastLimit() {
return 0
}
return g.limit - g.consumed
}
// addUint64Overflow performs the addition operation on two uint64 integers and
// returns a boolean on whether or not the result overflows.
func addUint64Overflow(a, b uint64) (uint64, bool) {
@ -67,7 +75,7 @@ func (g *infiniteGasMeterWithLimit) ConsumeGas(amount sdk.Gas, descriptor string
// RefundGas will deduct the given amount from the gas consumed. If the amount is greater than the
// gas consumed, the function will panic.
//
// Use case: This functionality enables refunding gas to the trasaction or block gas pools so that
// Use case: This functionality enables refunding gas to the transaction or block gas pools so that
// EVM-compatible chains can fully support the go-ethereum StateDb interface.
// See https://github.com/cosmos/cosmos-sdk/pull/9403 for reference.
func (g *infiniteGasMeterWithLimit) RefundGas(amount sdk.Gas, descriptor string) {

View File

@ -36,6 +36,7 @@ func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
var err error
s.network, err = network.New(s.T(), s.T().TempDir(), s.cfg)
s.Require().NoError(err)
@ -61,9 +62,7 @@ func (s *IntegrationTestSuite) createAccountWithBalance(accountName string, acco
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.EthSecp256k1)
sr.NoError(err)
val.ClientCtx.Keyring.SavePubKey(accountName, info.GetPubKey(), hd.EthSecp256k1Type)
newAddr := sdk.AccAddress(info.GetPubKey().Address())
newAddr, _ := info.GetAddress()
_, err = banktestutil.MsgSendExec(
val.ClientCtx,
val.Address,

View File

@ -3,7 +3,7 @@ package testutil
import (
"fmt"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/testutil/rest"
auctiontypes "github.com/tharsis/ethermint/x/auction/types"
)

View File

@ -4,8 +4,8 @@ import (
"context"
"fmt"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank/testutil"
"github.com/tharsis/ethermint/app"
"github.com/tharsis/ethermint/x/auction/types"
)
@ -40,7 +40,7 @@ func (suite *KeeperTestSuite) TestGrpcGetAllAuctions() {
suite.Run(fmt.Sprintf("Case %s", test.msg), func() {
if test.createAuctions {
account := app.CreateRandomAccounts(1)[0]
err := simapp.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(
err := testutil.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(
sdk.Coin{Amount: sdk.NewInt(100), Denom: sdk.DefaultBondDenom},
))
@ -329,7 +329,7 @@ func (suite *KeeperTestSuite) createAuctionAndCommitBid(commitBid bool) (*types.
accounts := app.CreateRandomAccounts(accCount)
for _, account := range accounts {
err := simapp.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(
err := testutil.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(
sdk.Coin{Amount: sdk.NewInt(100), Denom: sdk.DefaultBondDenom},
))
if err != nil {

View File

@ -7,12 +7,12 @@ import (
"time"
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
auth "github.com/cosmos/cosmos-sdk/x/auth/keeper"
bank "github.com/cosmos/cosmos-sdk/x/bank/keeper"
params "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/tharsis/ethermint/x/auction/types"
wnsUtils "github.com/tharsis/ethermint/utils"
@ -43,7 +43,7 @@ type Keeper struct {
// Track auction usage in other cosmos-sdk modules (more like a usage tracker).
usageKeepers []types.AuctionUsageKeeper
storeKey sdk.StoreKey // Unexposed key to access store from sdk.Context
storeKey storetypes.StoreKey // Unexposed key to access store from sdk.Context
cdc codec.BinaryCodec // The wire codec for binary encoding/decoding.
@ -58,7 +58,7 @@ type AuctionClientKeeper interface {
}
// NewKeeper creates new instances of the auction Keeper
func NewKeeper(accountKeeper auth.AccountKeeper, bankKeeper bank.Keeper, storeKey sdk.StoreKey, cdc codec.BinaryCodec, ps params.Subspace) Keeper {
func NewKeeper(accountKeeper auth.AccountKeeper, bankKeeper bank.Keeper, storeKey storetypes.StoreKey, cdc codec.BinaryCodec, ps params.Subspace) Keeper {
if !ps.HasKeyTable() {
ps = ps.WithKeyTable(types.ParamKeyTable())
}

View File

@ -22,7 +22,7 @@ type KeeperTestSuite struct {
}
func (suite *KeeperTestSuite) SetupTest() {
testApp := app.Setup(false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
testApp := app.Setup(suite.T(), false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
return genesis
})
ctx := testApp.BaseApp.NewContext(false, tmproto.Header{})
@ -37,7 +37,7 @@ func (suite *KeeperTestSuite) SetupTest() {
}
func TestParams(t *testing.T) {
testApp := app.Setup(false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
testApp := app.Setup(t, false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
return genesis
})
ctx := testApp.BaseApp.NewContext(false, tmproto.Header{})

View File

@ -2,8 +2,9 @@ package testutil
import (
"fmt"
clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/types/rest"
"github.com/cosmos/cosmos-sdk/testutil/rest"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/tharsis/ethermint/x/bond/client/cli"
bondtypes "github.com/tharsis/ethermint/x/bond/types"

View File

@ -89,7 +89,7 @@ func (s *IntegrationTestSuite) createAccountWithBalance(accountName string) {
info, _, err := val.ClientCtx.Keyring.NewMnemonic(accountName, keyring.English, sdk.FullFundraiserPath, keyring.DefaultBIP39Passphrase, hd.Secp256k1)
sr.NoError(err)
newAddr := sdk.AccAddress(info.GetPubKey().Address())
newAddr, _ := info.GetAddress()
_, err = banktestutil.MsgSendExec(
val.ClientCtx,
val.Address,
@ -175,7 +175,7 @@ func (s *IntegrationTestSuite) TestGetQueryBondById() {
{
"invalid bond id",
[]string{
fmt.Sprint("not_found_bond_id"),
"not_found_bond_id",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,
@ -246,7 +246,7 @@ func (s *IntegrationTestSuite) TestGetQueryBondListsByOwner() {
{
"invalid owner address",
[]string{
fmt.Sprint("not_found_bond_id"),
"not_found_bond_id",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
true,

View File

@ -3,8 +3,9 @@ package keeper_test
import (
"context"
"fmt"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank/testutil"
"github.com/tharsis/ethermint/app"
"github.com/tharsis/ethermint/x/bond/types"
)
@ -39,7 +40,7 @@ func (suite *KeeperTestSuite) TestGrpcQueryBondsList() {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createBonds {
account := app.CreateRandomAccounts(1)[0]
err := simapp.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(sdk.Coin{
err := testutil.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(sdk.Coin{
Denom: sdk.DefaultBondDenom,
Amount: sdk.NewInt(1000),
}))
@ -102,7 +103,7 @@ func (suite *KeeperTestSuite) TestGrpcQueryBondBondId() {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createBonds {
account := app.CreateRandomAccounts(1)[0]
err := simapp.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(sdk.Coin{
err := testutil.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(sdk.Coin{
Denom: sdk.DefaultBondDenom,
Amount: sdk.NewInt(1000),
}))
@ -156,7 +157,7 @@ func (suite *KeeperTestSuite) TestGrpcGetBondsByOwner() {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createBonds {
account := app.CreateRandomAccounts(1)[0]
_ = simapp.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(sdk.Coin{
_ = testutil.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(sdk.Coin{
Denom: sdk.DefaultBondDenom,
Amount: sdk.NewInt(1000),
}))
@ -200,7 +201,7 @@ func (suite *KeeperTestSuite) TestGrpcGetModuleBalance() {
suite.Run(fmt.Sprintf("Case %s ", test.msg), func() {
if test.createBonds {
account := app.CreateRandomAccounts(1)[0]
_ = simapp.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(sdk.Coin{
_ = testutil.FundAccount(suite.app.BankKeeper, ctx, account, sdk.NewCoins(sdk.Coin{
Denom: sdk.DefaultBondDenom,
Amount: sdk.NewInt(1000),
}))

View File

@ -4,7 +4,9 @@ import (
"crypto/sha256"
"encoding/hex"
"fmt"
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
auth "github.com/cosmos/cosmos-sdk/x/auth/keeper"
@ -29,7 +31,7 @@ type Keeper struct {
// Track bond usage in other cosmos-sdk modules (more like a usage tracker).
usageKeepers []types.BondUsageKeeper
storeKey sdk.StoreKey
storeKey storetypes.StoreKey
cdc codec.BinaryCodec
@ -37,7 +39,7 @@ type Keeper struct {
}
// NewKeeper creates new instances of the bond Keeper
func NewKeeper(cdc codec.BinaryCodec, accountKeeper auth.AccountKeeper, bankKeeper bank.Keeper, usageKeepers []types.BondUsageKeeper, storeKey sdk.StoreKey, ps paramtypes.Subspace) Keeper {
func NewKeeper(cdc codec.BinaryCodec, accountKeeper auth.AccountKeeper, bankKeeper bank.Keeper, usageKeepers []types.BondUsageKeeper, storeKey storetypes.StoreKey, ps paramtypes.Subspace) Keeper {
// set KeyTable if it has not already been set
if !ps.HasKeyTable() {
ps = ps.WithKeyTable(types.ParamKeyTable())

View File

@ -22,7 +22,7 @@ type KeeperTestSuite struct {
}
func (suite *KeeperTestSuite) SetupTest() {
testApp := app.Setup(false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
testApp := app.Setup(suite.T(), false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
return genesis
})
ctx := testApp.BaseApp.NewContext(false, tmproto.Header{})
@ -37,7 +37,7 @@ func (suite *KeeperTestSuite) SetupTest() {
}
func TestParams(t *testing.T) {
testApp := app.Setup(false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
testApp := app.Setup(t, false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
return genesis
})
ctx := testApp.BaseApp.NewContext(false, tmproto.Header{})

View File

@ -5,23 +5,17 @@ import (
"github.com/cosmos/cosmos-sdk/simapp"
"github.com/stretchr/testify/require"
abcitypes "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
app "github.com/tharsis/ethermint/app"
bondtypes "github.com/tharsis/ethermint/x/bond/types"
)
func TestItCreatesModuleAccountOnInitBlock(t *testing.T) {
app := app.Setup(false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
app := app.Setup(t, false, func(ea *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
return genesis
})
ctx := app.BaseApp.NewContext(false, tmproto.Header{})
app.InitChain(abcitypes.RequestInitChain{
AppStateBytes: []byte("{}"),
ChainId: "test-chain-id",
})
acc := app.AccountKeeper.GetModuleAccount(ctx, bondtypes.ModuleName)
require.NotNil(t, acc)
}

View File

@ -1,116 +1,98 @@
package rest
import (
"context"
"encoding/hex"
"encoding/json"
"errors"
"math/big"
"net/http"
"strings"
// clientrest "github.com/cosmos/cosmos-sdk/client/rest"
// "github.com/cosmos/cosmos-sdk/types/rest"
// authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client"
clientrest "github.com/cosmos/cosmos-sdk/client/rest"
"github.com/cosmos/cosmos-sdk/types/rest"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
rpctypes "github.com/tharsis/ethermint/rpc/ethereum/types"
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
"github.com/ethereum/go-ethereum/common"
)
// RegisterTxRoutes - Central function to define routes that get registered by the main application
func RegisterTxRoutes(clientCtx client.Context, rtr *mux.Router) {
r := clientrest.WithHTTPDeprecationHeaders(rtr)
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(clientCtx)).Methods("GET")
r.HandleFunc("/txs", authrest.QueryTxsRequestHandlerFn(clientCtx)).Methods("GET")
r.HandleFunc("/txs/decode", authrest.DecodeTxRequestHandlerFn(clientCtx)).Methods("POST")
}
// // RegisterTxRoutes - Central function to define routes that get registered by the main application
// func RegisterTxRoutes(clientCtx client.Context, rtr *mux.Router) {
// r := testutil.GetRequestWithHeaders(rtr)
// r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(clientCtx)).Methods("GET")
// r.HandleFunc("/txs", testutil.QueryTxsRequestHandlerFn(clientCtx)).Methods("GET")
// r.HandleFunc("/txs/decode", testutil.DecodeTxRequestHandlerFn(clientCtx)).Methods("POST")
// }
// QueryTxRequestHandlerFn implements a REST handler that queries a transaction
// by hash in a committed block.
func QueryTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
hashHexStr := vars["hash"]
// func QueryTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
// return func(w http.ResponseWriter, r *http.Request) {
// vars := mux.Vars(r)
// hashHexStr := vars["hash"]
clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r)
if !ok {
return
}
// clientCtx, ok := testutil.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r)
// if !ok {
// return
// }
ethHashPrefix := "0x"
if !strings.HasPrefix(hashHexStr, ethHashPrefix) {
authrest.QueryTxRequestHandlerFn(clientCtx)
return
}
// ethHashPrefix := "0x"
// // if !strings.HasPrefix(hashHexStr, ethHashPrefix) {
// // authrest.QueryTxRequestHandlerFn(clientCtx)
// // return
// // }
// eth Tx
ethHashPrefixLength := len(ethHashPrefix)
output, err := getEthTransactionByHash(clientCtx, hashHexStr[ethHashPrefixLength:])
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
// // eth Tx
// ethHashPrefixLength := len(ethHashPrefix)
// output, err := getEthTransactionByHash(clientCtx, hashHexStr[ethHashPrefixLength:])
// if err != nil {
// rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
// return
// }
rest.PostProcessResponseBare(w, clientCtx, output)
}
}
// rest.PostProcessResponseBare(w, clientCtx, output)
// }
// }
// GetTransactionByHash returns the transaction identified by hash.
func getEthTransactionByHash(clientCtx client.Context, hashHex string) ([]byte, error) {
hash, err := hex.DecodeString(hashHex)
if err != nil {
return nil, err
}
node, err := clientCtx.GetNode()
if err != nil {
return nil, err
}
// // GetTransactionByHash returns the transaction identified by hash.
// func getEthTransactionByHash(clientCtx client.Context, hashHex string) ([]byte, error) {
// hash, err := hex.DecodeString(hashHex)
// if err != nil {
// return nil, err
// }
// node, err := clientCtx.GetNode()
// if err != nil {
// return nil, err
// }
tx, err := node.Tx(context.Background(), hash, false)
if err != nil {
return nil, err
}
// tx, err := node.Tx(context.Background(), hash, false)
// if err != nil {
// return nil, err
// }
// Can either cache or just leave this out if not necessary
block, err := node.Block(context.Background(), &tx.Height)
if err != nil {
return nil, err
}
// // Can either cache or just leave this out if not necessary
// block, err := node.Block(context.Background(), &tx.Height)
// if err != nil {
// return nil, err
// }
client := feemarkettypes.NewQueryClient(clientCtx)
res, err := client.BaseFee(context.Background(), &feemarkettypes.QueryBaseFeeRequest{})
if err != nil {
return nil, err
}
// client := feemarkettypes.NewQueryClient(clientCtx)
// res, err := client.BaseFee(context.Background(), &feemarkettypes.QueryBaseFeeRequest{})
// if err != nil {
// return nil, err
// }
var baseFee *big.Int
if res.BaseFee != nil {
baseFee = res.BaseFee.BigInt()
}
// var baseFee *big.Int
// if res.BaseFee != nil {
// baseFee = res.BaseFee.BigInt()
// }
blockHash := common.BytesToHash(block.Block.Header.Hash())
// blockHash := common.BytesToHash(block.Block.Header.Hash())
ethTxs, err := rpctypes.RawTxToEthTx(clientCtx, tx.Tx)
if err != nil {
return nil, err
}
// ethTxs, err := rpctypes.RawTxToEthTx(clientCtx, tx.Tx)
// if err != nil {
// return nil, err
// }
height := uint64(tx.Height)
// height := uint64(tx.Height)
for _, ethTx := range ethTxs {
if common.HexToHash(ethTx.Hash) == common.BytesToHash(hash) {
rpcTx, err := rpctypes.NewRPCTransaction(ethTx.AsTransaction(), blockHash, height, uint64(tx.Index), baseFee)
if err != nil {
return nil, err
}
return json.Marshal(rpcTx)
}
}
// for _, ethTx := range ethTxs {
// if common.HexToHash(ethTx.Hash) == common.BytesToHash(hash) {
// rpcTx, err := rpctypes.NewRPCTransaction(ethTx.AsTransaction(), blockHash, height, uint64(tx.Index), baseFee)
// if err != nil {
// return nil, err
// }
// return json.Marshal(rpcTx)
// }
// }
return nil, errors.New("eth tx not found")
}
// return nil, errors.New("eth tx not found")
// }

View File

@ -8,12 +8,9 @@ import (
"github.com/gogo/protobuf/proto"
abci "github.com/tendermint/tendermint/abci/types"
tmjson "github.com/tendermint/tendermint/libs/json"
"github.com/cosmos/cosmos-sdk/simapp"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/bank/testutil"
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
@ -75,7 +72,7 @@ func (suite *EvmTestSuite) DoSetupTest(t require.TestingT) {
require.NoError(t, err)
consAddress := sdk.ConsAddress(priv.PubKey().Address())
suite.app = app.Setup(checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
suite.app = app.Setup(suite.T(), checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
if suite.dynamicTxFee {
feemarketGenesis := feemarkettypes.DefaultGenesisState()
feemarketGenesis.Params.EnableHeight = 1
@ -85,36 +82,6 @@ func (suite *EvmTestSuite) DoSetupTest(t require.TestingT) {
return genesis
})
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdk.NewInt(100000000000000)))
genesisState := app.ModuleBasics.DefaultGenesis(suite.app.AppCodec())
b32address := sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), priv.PubKey().Address().Bytes())
balances := []banktypes.Balance{
{
Address: b32address,
Coins: coins,
},
{
Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(),
Coins: coins,
},
}
// update total supply
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdk.NewInt(200000000000000))), []banktypes.Metadata{})
genesisState[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(bankGenesis)
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
suite.app.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
ConsensusParams: simapp.DefaultConsensusParams,
AppStateBytes: stateBytes,
},
)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{
Height: 1,
ChainID: "ethermint_9000-1",
@ -139,10 +106,25 @@ func (suite *EvmTestSuite) DoSetupTest(t require.TestingT) {
LastResultsHash: tmhash.Sum([]byte("last_result")),
})
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdk.NewInt(100000000000000)))
b32address := sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), priv.PubKey().Address().Bytes())
accAddr, err := sdk.AccAddressFromBech32(b32address)
require.NoError(t, err)
acc := &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(accAddr.Bytes()), nil, 0, 0),
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
}
err = testutil.FundAccount(suite.app.BankKeeper, suite.ctx, accAddr, coins)
require.NoError(t, err)
err = testutil.FundModuleAccount(suite.app.BankKeeper, suite.ctx, authtypes.FeeCollectorName, coins)
require.NoError(t, err)
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.app.EvmKeeper)
acc := &ethermint.EthAccount{
acc = &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0),
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
}

View File

@ -7,9 +7,9 @@ import (
"github.com/stretchr/testify/require"
sdk "github.com/cosmos/cosmos-sdk/types"
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/ethereum/go-ethereum/common"
authmiddleware "github.com/cosmos/cosmos-sdk/x/auth/middleware"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethermint "github.com/tharsis/ethermint/types"
"github.com/tharsis/ethermint/x/evm/types"
@ -67,7 +67,7 @@ func DoBenchmark(b *testing.B, txBuilder TxBuilder) {
require.NoError(b, err)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdk.NewIntFromBigInt(txData.Fee()))}
err = authante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
err = authmiddleware.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
require.NoError(b, err)
rsp, err := suite.app.EvmKeeper.EthereumTx(sdk.WrapSDKContext(ctx), msg)
@ -134,7 +134,7 @@ func BenchmarkMessageCall(b *testing.B) {
require.NoError(b, err)
fees := sdk.Coins{sdk.NewCoin(suite.EvmDenom(), sdk.NewIntFromBigInt(txData.Fee()))}
err = authante.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
err = authmiddleware.DeductFees(suite.app.BankKeeper, suite.ctx, suite.app.AccountKeeper.GetAccount(ctx, msg.GetFrom()), fees)
require.NoError(b, err)
rsp, err := suite.app.EvmKeeper.EthereumTx(sdk.WrapSDKContext(ctx), msg)

View File

@ -5,6 +5,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
@ -29,10 +30,10 @@ type Keeper struct {
// - storing account's Code
// - storing transaction Logs
// - storing Bloom filters by block height. Needed for the Web3 API.
storeKey sdk.StoreKey
storeKey storetypes.StoreKey
// key to access the transient store, which is reset on every block during Commit
transientKey sdk.StoreKey
transientKey storetypes.StoreKey
// module specific parameter space that can be configured through governance
paramSpace paramtypes.Subspace
@ -58,7 +59,7 @@ type Keeper struct {
// NewKeeper generates new evm module keeper
func NewKeeper(
cdc codec.BinaryCodec,
storeKey, transientKey sdk.StoreKey, paramSpace paramtypes.Subspace,
storeKey, transientKey storetypes.StoreKey, paramSpace paramtypes.Subspace,
ak types.AccountKeeper, bankKeeper types.BankKeeper, sk types.StakingKeeper,
fmk types.FeeMarketKeeper,
tracer string,

View File

@ -18,9 +18,8 @@ import (
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/bank/testutil"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
tmjson "github.com/tendermint/tendermint/libs/json"
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
"github.com/tharsis/ethermint/app"
@ -86,7 +85,7 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
require.NoError(t, err)
suite.consAddress = sdk.ConsAddress(priv.PubKey().Address())
suite.app = app.Setup(checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
suite.app = app.Setup(suite.T(), checkTx, func(app *app.EthermintApp, genesis simapp.GenesisState) simapp.GenesisState {
feemarketGenesis := feemarkettypes.DefaultGenesisState()
if suite.enableFeemarket {
feemarketGenesis.Params.EnableHeight = 1
@ -106,37 +105,6 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
return genesis
})
if suite.mintFeeCollector {
// mint some coin to fee collector
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdk.NewInt(int64(params.TxGas)-1)))
genesisState := app.ModuleBasics.DefaultGenesis(suite.app.AppCodec())
balances := []banktypes.Balance{
{
Address: suite.app.AccountKeeper.GetModuleAddress(authtypes.FeeCollectorName).String(),
Coins: coins,
},
}
// update total supply
bankGenesis := banktypes.NewGenesisState(banktypes.DefaultGenesisState().Params, balances, sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdk.NewInt((int64(params.TxGas)-1)))), []banktypes.Metadata{})
bz := suite.app.AppCodec().MustMarshalJSON(bankGenesis)
require.NotNil(t, bz)
genesisState[banktypes.ModuleName] = suite.app.AppCodec().MustMarshalJSON(bankGenesis)
// we marshal the genesisState of all module to a byte array
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
require.NoError(t, err)
// Initialize the chain
suite.app.InitChain(
abci.RequestInitChain{
ChainId: "ethermint_9000-1",
Validators: []abci.ValidatorUpdate{},
ConsensusParams: simapp.DefaultConsensusParams,
AppStateBytes: stateBytes,
},
)
}
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{
Height: 1,
ChainID: "ethermint_9000-1",
@ -161,6 +129,12 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
LastResultsHash: tmhash.Sum([]byte("last_result")),
})
if suite.mintFeeCollector {
// mint some coin to fee collector
coins := sdk.NewCoins(sdk.NewCoin(types.DefaultEVMDenom, sdk.NewInt(int64(params.TxGas)-1)))
testutil.FundModuleAccount(suite.app.BankKeeper, suite.ctx, authtypes.FeeCollectorName, coins)
}
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.app.EvmKeeper)
suite.queryClient = types.NewQueryClient(queryHelper)
@ -183,7 +157,7 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
encodingConfig := encoding.MakeConfig(app.ModuleBasics)
suite.clientCtx = client.Context{}.WithTxConfig(encodingConfig.TxConfig)
suite.ethSigner = ethtypes.LatestSignerForChainID(suite.app.EvmKeeper.ChainID())
suite.appCodec = encodingConfig.Marshaler
suite.appCodec = encodingConfig.Codec
}
func (suite *KeeperTestSuite) SetupTest() {

View File

@ -19,8 +19,7 @@ var _ types.MsgServer = &Keeper{}
// EthereumTx implements the gRPC MsgServer interface. It receives a transaction which is then
// executed (i.e applied) against the go-ethereum EVM. The provided SDK Context is set to the Keeper
// so that it can implements and call the StateDB methods without receiving it as a function
// parameter.
// so that it can call the StateDB methods without receiving it as a function parameter.
func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

View File

@ -5,7 +5,8 @@ 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"
authmiddleware "github.com/cosmos/cosmos-sdk/x/auth/middleware"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
@ -24,7 +25,7 @@ func (k Keeper) DeductTxCostsFromUserBalance(
isContractCreation := txData.GetTo() == nil
// fetch sender account from signature
signerAcc, err := authante.GetSignerAcc(ctx, k.accountKeeper, msgEthTx.GetFrom())
signerAcc, err := authmiddleware.GetSignerAcc(ctx, k.accountKeeper, msgEthTx.GetFrom())
if err != nil {
return nil, sdkerrors.Wrapf(err, "account not found for sender %s", msgEthTx.From)
}
@ -74,7 +75,7 @@ func (k Keeper) DeductTxCostsFromUserBalance(
fees := sdk.Coins{sdk.NewCoin(denom, sdk.NewIntFromBigInt(feeAmt))}
// deduct the full gas cost from the user balance
if err := authante.DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil {
if err := authmiddleware.DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil {
return nil, sdkerrors.Wrapf(
err,
"failed to deduct full gas cost %s from the user %s balance",

View File

@ -170,11 +170,13 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw
// RandomizedParams creates randomized evm param changes for the simulator.
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
return nil
return simulation.ParamChanges(r)
}
// RegisterStoreDecoder registers a decoder for evm module's types
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {}
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[types.StoreKey] = simulation.NewDecodeStore()
}
// ProposalContents doesn't return any content functions for governance proposals.
func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
@ -188,5 +190,7 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
// WeightedOperations returns the all the evm module operations with their respective weights.
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
return nil
return simulation.WeightedOperations(
simState.AppParams, simState.Cdc, am.ak, am.keeper,
)
}

View File

@ -0,0 +1,31 @@
package simulation
import (
"bytes"
"fmt"
"github.com/cosmos/cosmos-sdk/types/kv"
"github.com/ethereum/go-ethereum/common"
"github.com/tharsis/ethermint/x/evm/types"
)
// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
// Value to the corresponding evm type.
func NewDecodeStore() func(kvA, kvB kv.Pair) string {
return func(kvA, kvB kv.Pair) string {
switch {
case bytes.Equal(kvA.Key[:1], types.KeyPrefixStorage):
storageHashA := common.BytesToHash(kvA.Value).Hex()
storageHashB := common.BytesToHash(kvB.Value).Hex()
return fmt.Sprintf("%v\n%v", storageHashA, storageHashB)
case bytes.Equal(kvA.Key[:1], types.KeyPrefixCode):
codeHashA := common.BytesToHash(kvA.Value).Hex()
codeHashB := common.BytesToHash(kvB.Value).Hex()
return fmt.Sprintf("%v\n%v", codeHashA, codeHashB)
default:
panic(fmt.Sprintf("invalid evm key prefix %X", kvA.Key[:1]))
}
}
}

View File

@ -3,12 +3,22 @@ package simulation
import (
"encoding/json"
"fmt"
"math/rand"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/tharsis/ethermint/x/evm/types"
)
// GenExtraEIPs randomly generates specific extra eips or not.
func genExtraEIPs(r *rand.Rand) []int64 {
var extraEIPs []int64
if r.Uint32()%2 == 0 {
extraEIPs = []int64{1344, 1884, 2200, 2929, 3198, 3529}
}
return extraEIPs
}
// RandomizedGenState generates a random GenesisState for nft
func RandomizedGenState(simState *module.SimulationState) {
params := types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig())

View File

@ -0,0 +1,302 @@
package simulation
import (
"encoding/json"
"fmt"
"math/big"
"math/rand"
"time"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
"github.com/cosmos/cosmos-sdk/x/auth/tx"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/tharsis/ethermint/encoding"
"github.com/tharsis/ethermint/server/config"
"github.com/tharsis/ethermint/tests"
"github.com/tharsis/ethermint/x/evm/keeper"
"github.com/tharsis/ethermint/x/evm/types"
)
const (
/* #nosec */
OpWeightMsgEthSimpleTransfer = "op_weight_msg_eth_simple_transfer"
/* #nosec */
OpWeightMsgEthCreateContract = "op_weight_msg_eth_create_contract"
/* #nosec */
OpWeightMsgEthCallContract = "op_weight_msg_eth_call_contract"
)
const (
WeightMsgEthSimpleTransfer = 50
WeightMsgEthCreateContract = 50
)
var ErrNoEnoughBalance = fmt.Errorf("no enough balance")
var maxWaitSeconds = 10
type simulateContext struct {
context sdk.Context
bapp *baseapp.BaseApp
rand *rand.Rand
keeper *keeper.Keeper
}
// WeightedOperations generate Two kinds of operations: SimulateEthSimpleTransfer, SimulateEthCreateContract.
// Contract call operations work as the future operations of SimulateEthCreateContract.
func WeightedOperations(
appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, k *keeper.Keeper,
) simulation.WeightedOperations {
var (
weightMsgEthSimpleTransfer int
weightMsgEthCreateContract int
)
appParams.GetOrGenerate(cdc, OpWeightMsgEthSimpleTransfer, &weightMsgEthSimpleTransfer, nil,
func(_ *rand.Rand) {
weightMsgEthSimpleTransfer = WeightMsgEthSimpleTransfer
},
)
appParams.GetOrGenerate(cdc, OpWeightMsgEthCreateContract, &weightMsgEthCreateContract, nil,
func(_ *rand.Rand) {
weightMsgEthCreateContract = WeightMsgEthCreateContract
},
)
return simulation.WeightedOperations{
simulation.NewWeightedOperation(
weightMsgEthSimpleTransfer,
SimulateEthSimpleTransfer(ak, k),
),
simulation.NewWeightedOperation(
weightMsgEthCreateContract,
SimulateEthCreateContract(ak, k),
),
}
}
// SimulateEthSimpleTransfer simulate simple eth account transferring gas token.
// It randomly choose sender, recipient and transferable amount.
// Other tx details like nonce, gasprice, gaslimit are calculated to get valid value.
func SimulateEthSimpleTransfer(ak types.AccountKeeper, k *keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, bapp *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
simAccount, _ := simtypes.RandomAcc(r, accs)
var recipient simtypes.Account
if r.Intn(2) == 1 {
recipient, _ = simtypes.RandomAcc(r, accs)
} else {
recipient = simtypes.RandomAccounts(r, 1)[0]
}
from := common.BytesToAddress(simAccount.Address)
to := common.BytesToAddress(recipient.Address)
simulateContext := &simulateContext{ctx, bapp, r, k}
return SimulateEthTx(simulateContext, &from, &to, nil, (*hexutil.Bytes)(&[]byte{}), simAccount.PrivKey, nil)
}
}
// SimulateEthCreateContract simulate create an ERC20 contract.
// It makes operationSimulateEthCallContract the future operations of SimulateEthCreateContract to ensure valid contract call.
func SimulateEthCreateContract(ak types.AccountKeeper, k *keeper.Keeper) simtypes.Operation {
return func(
r *rand.Rand, bapp *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
simAccount, _ := simtypes.RandomAcc(r, accs)
from := common.BytesToAddress(simAccount.Address)
nonce := k.GetNonce(ctx, from)
ctorArgs, err := types.ERC20Contract.ABI.Pack("", from, sdk.NewIntWithDecimal(1000, 18).BigInt())
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not pack owner and supply"), nil, err
}
data := types.ERC20Contract.Bin
data = append(data, ctorArgs...)
simulateContext := &simulateContext{ctx, bapp, r, k}
fops := make([]simtypes.FutureOperation, 1)
whenCall := ctx.BlockHeader().Time.Add(time.Duration(r.Intn(maxWaitSeconds)+1) * time.Second)
contractAddr := crypto.CreateAddress(from, nonce)
var tokenReceipient simtypes.Account
if r.Intn(2) == 1 {
tokenReceipient, _ = simtypes.RandomAcc(r, accs)
} else {
tokenReceipient = simtypes.RandomAccounts(r, 1)[0]
}
receipientAddr := common.BytesToAddress(tokenReceipient.Address)
fops[0] = simtypes.FutureOperation{
BlockTime: whenCall,
Op: operationSimulateEthCallContract(k, &contractAddr, &receipientAddr, nil),
}
return SimulateEthTx(simulateContext, &from, nil, nil, (*hexutil.Bytes)(&data), simAccount.PrivKey, fops)
}
}
// operationSimulateEthCallContract simulate calling an contract.
// It is always calling an ERC20 contract.
func operationSimulateEthCallContract(k *keeper.Keeper, contractAddr, to *common.Address, amount *big.Int) simtypes.Operation {
return func(
r *rand.Rand, bapp *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
simAccount, _ := simtypes.RandomAcc(r, accs)
from := common.BytesToAddress(simAccount.Address)
ctorArgs, err := types.ERC20Contract.ABI.Pack("transfer", to, amount)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not pack method and args"), nil, err
}
data := types.ERC20Contract.Bin
data = append(data, ctorArgs...)
simulateContext := &simulateContext{ctx, bapp, r, k}
return SimulateEthTx(simulateContext, &from, contractAddr, nil, (*hexutil.Bytes)(&data), simAccount.PrivKey, nil)
}
}
// SimulateEthTx creates valid ethereum tx and pack it as cosmos tx, and deliver it.
func SimulateEthTx(
ctx *simulateContext, from, to *common.Address, amount *big.Int, data *hexutil.Bytes, prv cryptotypes.PrivKey, fops []simtypes.FutureOperation,
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
ethTx, err := CreateRandomValidEthTx(ctx, from, nil, nil, data)
if err == ErrNoEnoughBalance {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "no enough balance"), nil, nil
}
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not create valid eth tx"), nil, err
}
txConfig := encoding.MakeConfig(module.NewBasicManager()).TxConfig
txBuilder := txConfig.NewTxBuilder()
signedTx, err := GetSignedTx(ctx, txBuilder, ethTx, prv)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not sign ethereum tx"), nil, err
}
_, _, err = ctx.bapp.SimDeliver(txConfig.TxEncoder(), signedTx)
if err != nil {
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "failed to deliver tx"), nil, err
}
return simtypes.OperationMsg{}, fops, nil
}
// CreateRandomValidEthTx create the ethereum tx with valid random values
func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amount *big.Int, data *hexutil.Bytes) (ethTx *types.MsgEthereumTx, err error) {
estimateGas, err := EstimateGas(ctx, from, to, data)
if err != nil {
return nil, err
}
gasLimit := estimateGas + uint64(ctx.rand.Intn(int(sdktx.MaxGasWanted-estimateGas)))
ethChainID := ctx.keeper.ChainID()
chainConfig := ctx.keeper.GetParams(ctx.context).ChainConfig.EthereumConfig(ethChainID)
gasPrice := ctx.keeper.BaseFee(ctx.context, chainConfig)
gasFeeCap := new(big.Int).Add(gasPrice, big.NewInt(int64(ctx.rand.Int())))
gasTipCap := big.NewInt(int64(ctx.rand.Int()))
nonce := ctx.keeper.GetNonce(ctx.context, *from)
if amount == nil {
amount, err = RandomTransferableAmount(ctx, *from, gasLimit, gasFeeCap)
if err != nil {
return nil, err
}
}
ethTx = types.NewTx(ethChainID, nonce, to, amount, gasLimit, gasPrice, gasFeeCap, gasTipCap, *data, nil)
ethTx.From = from.String()
return ethTx, nil
}
// GetSignedTx sign the ethereum tx and packs it as a signing.Tx .
func GetSignedTx(ctx *simulateContext, txBuilder client.TxBuilder, msg *types.MsgEthereumTx, prv cryptotypes.PrivKey) (signedTx signing.Tx, err error) {
builder, ok := txBuilder.(tx.ExtensionOptionsTxBuilder)
if !ok {
return nil, fmt.Errorf("can not initiate ExtensionOptionsTxBuilder")
}
option, err := codectypes.NewAnyWithValue(&types.ExtensionOptionsEthereumTx{})
if err != nil {
return nil, err
}
builder.SetExtensionOptions(option)
if err := msg.Sign(ethtypes.LatestSignerForChainID(ctx.keeper.ChainID()), tests.NewSigner(prv)); err != nil {
return nil, err
}
if err = builder.SetMsgs(msg); err != nil {
return nil, err
}
txData, err := types.UnpackTxData(msg.Data)
if err != nil {
return nil, err
}
fees := sdk.NewCoins(sdk.NewCoin(ctx.keeper.GetParams(ctx.context).EvmDenom, sdk.NewIntFromBigInt(txData.Fee())))
builder.SetFeeAmount(fees)
builder.SetGasLimit(msg.GetGas())
signedTx = builder.GetTx()
return signedTx, nil
}
// RandomTransferableAmount generates a random valid transferable amount.
// Transferable amount is between the range [0, spendable), spendable = balance - gasFeeCap * GasLimit.
func RandomTransferableAmount(ctx *simulateContext, address common.Address, gasLimit uint64, gasFeeCap *big.Int) (amount *big.Int, err error) {
balance := ctx.keeper.GetBalance(ctx.context, address)
feeLimit := new(big.Int).Mul(gasFeeCap, big.NewInt(int64(gasLimit)))
if (feeLimit.Cmp(balance)) > 0 {
return nil, ErrNoEnoughBalance
}
spendable := new(big.Int).Sub(balance, feeLimit)
if spendable.Cmp(big.NewInt(0)) == 0 {
amount = new(big.Int).Set(spendable)
return amount, nil
}
simAmount, err := simtypes.RandPositiveInt(ctx.rand, sdk.NewIntFromBigInt(spendable))
if err != nil {
return nil, err
}
amount = simAmount.BigInt()
return amount, nil
}
// EstimateGas estimates the gas used by quering the keeper.
func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.Bytes) (gas uint64, err error) {
args, err := json.Marshal(&types.TransactionArgs{To: to, From: from, Data: data})
if err != nil {
return 0, err
}
res, err := ctx.keeper.EstimateGas(sdk.WrapSDKContext(ctx.context), &types.EthCallRequest{
Args: args,
GasCap: config.DefaultGasCap,
})
if err != nil {
return 0, err
}
return res.Gas, nil
}

View File

@ -0,0 +1,28 @@
package simulation
// DONTCOVER
import (
"fmt"
"math/rand"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/tharsis/ethermint/x/evm/types"
)
const (
keyExtraEIPs = "ExtraEIPs"
)
// ParamChanges defines the parameters that can be modified by param change proposals
// on the simulation.
func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
return []simtypes.ParamChange{
simulation.NewSimParamChange(types.ModuleName, keyExtraEIPs,
func(r *rand.Rand) string {
return fmt.Sprintf("\"%d\"", genExtraEIPs(r))
},
),
}
}

View File

@ -1,17 +1,16 @@
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/msgservice"
"github.com/cosmos/cosmos-sdk/types/tx"
proto "github.com/gogo/protobuf/proto"
)
var ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
type (
TxResponse interface{}
ExtensionOptionsEthereumTxI interface{}
)
@ -21,9 +20,8 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
(*sdk.Msg)(nil),
&MsgEthereumTx{},
)
registry.RegisterInterface(
"ethermint.evm.v1.ExtensionOptionsEthereumTx",
(*ExtensionOptionsEthereumTxI)(nil),
registry.RegisterImplementations(
(*tx.TxExtensionOptionI)(nil),
&ExtensionOptionsEthereumTx{},
)
registry.RegisterInterface(
@ -33,6 +31,16 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
&AccessListTx{},
&LegacyTx{},
)
registry.RegisterInterface(
"ethermint.evm.v1.MsgEthereumTxResponse",
(*TxResponse)(nil),
&MsgEthereumTxResponse{},
)
registry.RegisterInterface(
"ethermint.evm.v1.ExtensionOptionsEthereumTx",
(*ExtensionOptionsEthereumTxI)(nil),
&ExtensionOptionsEthereumTx{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}

View File

@ -33,6 +33,7 @@ type BankKeeper interface {
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
MintCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
BurnCoins(ctx sdk.Context, moduleName string, amt sdk.Coins) error
SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amount sdk.Coins) error
}
// StakingKeeper returns the historical headers kept in store.

View File

@ -10,7 +10,8 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keyring"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/auth/ante"
authmiddleware "github.com/cosmos/cosmos-sdk/x/auth/middleware"
"github.com/cosmos/cosmos-sdk/x/auth/signing"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
@ -24,7 +25,7 @@ import (
var (
_ sdk.Msg = &MsgEthereumTx{}
_ sdk.Tx = &MsgEthereumTx{}
_ ante.GasTx = &MsgEthereumTx{}
_ authmiddleware.GasTx = &MsgEthereumTx{}
_ codectypes.UnpackInterfacesMessage = MsgEthereumTx{}
)

View File

@ -6,8 +6,8 @@ import (
"github.com/gogo/protobuf/proto"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
@ -18,25 +18,27 @@ const maxBitLen = 256
var EmptyCodeHash = crypto.Keccak256(nil)
// DecodeTxResponse decodes an protobuf-encoded byte slice into TxResponse
func DecodeTxResponse(in []byte) (*MsgEthereumTxResponse, error) {
func DecodeTxResponse(in []byte, cdc codec.Codec) (*MsgEthereumTxResponse, error) {
var txMsgData sdk.TxMsgData
if err := proto.Unmarshal(in, &txMsgData); err != nil {
if err := txMsgData.Unmarshal(in); err != nil {
return nil, err
}
data := txMsgData.GetData()
if len(data) == 0 {
return &MsgEthereumTxResponse{}, nil
responses := txMsgData.GetMsgResponses()
if len(responses) == 0 {
return nil, nil
}
var res MsgEthereumTxResponse
err := proto.Unmarshal(data[0].GetData(), &res)
if err != nil {
return nil, sdkerrors.Wrap(err, "failed to unmarshal tx response message data")
if err := cdc.UnpackAny(responses[0], new(TxResponse)); err != nil {
return nil, fmt.Errorf("failed to unmarshal tx response message: %w", err)
}
return &res, nil
msgval := responses[0].GetCachedValue()
res, ok := msgval.(*MsgEthereumTxResponse)
if !ok {
return nil, fmt.Errorf("tx response message has invalid type: %T", msgval)
}
return res, nil
}
// EncodeTransactionLogs encodes TransactionLogs slice into a protobuf-encoded byte slice.
@ -44,16 +46,6 @@ func EncodeTransactionLogs(res *TransactionLogs) ([]byte, error) {
return proto.Marshal(res)
}
// DecodeTxResponse decodes an protobuf-encoded byte slice into TransactionLogs
func DecodeTransactionLogs(data []byte) (TransactionLogs, error) {
var logs TransactionLogs
err := proto.Unmarshal(data, &logs)
if err != nil {
return TransactionLogs{}, err
}
return logs, nil
}
// UnwrapEthereumMsg extract MsgEthereumTx from wrapping sdk.Tx
func UnwrapEthereumMsg(tx *sdk.Tx, ethHash common.Hash) (*MsgEthereumTx, error) {
if tx == nil {

View File

@ -5,23 +5,33 @@ import (
"math/big"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
proto "github.com/gogo/protobuf/proto"
"github.com/tharsis/ethermint/app"
"github.com/tharsis/ethermint/encoding"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
"github.com/stretchr/testify/require"
"github.com/ethereum/go-ethereum/common"
)
var testCodec codec.Codec
func init() {
registry := codectypes.NewInterfaceRegistry()
evmtypes.RegisterInterfaces(registry)
testCodec = codec.NewProtoCodec(registry)
}
func TestEvmDataEncoding(t *testing.T) {
ret := []byte{0x5, 0x8}
data := &evmtypes.MsgEthereumTxResponse{
resp := &evmtypes.MsgEthereumTxResponse{
Hash: common.BytesToHash([]byte("hash")).String(),
Logs: []*evmtypes.Log{{
Data: []byte{1, 2, 3, 4},
@ -30,21 +40,20 @@ func TestEvmDataEncoding(t *testing.T) {
Ret: ret,
}
enc, err := proto.Marshal(data)
any, err := codectypes.NewAnyWithValue(resp)
require.NoError(t, err)
txData := &sdk.TxMsgData{
Data: []*sdk.MsgData{{MsgType: evmtypes.TypeMsgEthereumTx, Data: enc}},
MsgResponses: []*codectypes.Any{any},
}
txDataBz, err := proto.Marshal(txData)
txDataBz, err := txData.Marshal()
require.NoError(t, err)
res, err := evmtypes.DecodeTxResponse(txDataBz)
decoded, err := evmtypes.DecodeTxResponse(txDataBz, testCodec)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, data.Logs, res.Logs)
require.Equal(t, ret, res.Ret)
require.NotNil(t, decoded)
require.Equal(t, resp.Logs, decoded.Logs)
require.Equal(t, ret, decoded.Ret)
}
func TestUnwrapEthererumMsg(t *testing.T) {

View File

@ -2,8 +2,9 @@ package keeper_test
import (
"fmt"
abci "github.com/tendermint/tendermint/abci/types"
"math/big"
prototypes "github.com/tendermint/tendermint/proto/tendermint/types"
)
func (suite *KeeperTestSuite) TestCalculateBaseFee() {
@ -38,11 +39,11 @@ func (suite *KeeperTestSuite) TestCalculateBaseFee() {
suite.app.FeeMarketKeeper.SetBlockGasUsed(suite.ctx, 100)
// Set target/gasLimit through Consensus Param MaxGas
blockParams := abci.BlockParams{
blockParams := prototypes.BlockParams{
MaxGas: 100,
MaxBytes: 10,
}
consParams := abci.ConsensusParams{Block: &blockParams}
consParams := prototypes.ConsensusParams{Block: &blockParams}
suite.ctx = suite.ctx.WithConsensusParams(&consParams)
// set ElasticityMultiplier
@ -60,11 +61,11 @@ func (suite *KeeperTestSuite) TestCalculateBaseFee() {
suite.app.FeeMarketKeeper.SetBlockGasUsed(suite.ctx, 200)
blockParams := abci.BlockParams{
blockParams := prototypes.BlockParams{
MaxGas: 100,
MaxBytes: 10,
}
consParams := abci.ConsensusParams{Block: &blockParams}
consParams := prototypes.ConsensusParams{Block: &blockParams}
suite.ctx = suite.ctx.WithConsensusParams(&consParams)
params := suite.app.FeeMarketKeeper.GetParams(suite.ctx)
@ -81,11 +82,11 @@ func (suite *KeeperTestSuite) TestCalculateBaseFee() {
suite.app.FeeMarketKeeper.SetBlockGasUsed(suite.ctx, 50)
blockParams := abci.BlockParams{
blockParams := prototypes.BlockParams{
MaxGas: 100,
MaxBytes: 10,
}
consParams := abci.ConsensusParams{Block: &blockParams}
consParams := prototypes.ConsensusParams{Block: &blockParams}
suite.ctx = suite.ctx.WithConsensusParams(&consParams)
params := suite.app.FeeMarketKeeper.GetParams(suite.ctx)

View File

@ -6,6 +6,7 @@ import (
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/tendermint/tendermint/libs/log"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
"github.com/tharsis/ethermint/x/feemarket/types"
)
@ -14,14 +15,14 @@ type Keeper struct {
// Protobuf codec
cdc codec.BinaryCodec
// Store key required for the Fee Market Prefix KVStore.
storeKey sdk.StoreKey
storeKey storetypes.StoreKey
// module specific parameter space that can be configured through governance
paramSpace paramtypes.Subspace
}
// NewKeeper generates new fee market module keeper
func NewKeeper(
cdc codec.BinaryCodec, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace,
cdc codec.BinaryCodec, storeKey storetypes.StoreKey, paramSpace paramtypes.Subspace,
) Keeper {
// set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() {

Some files were not shown because too many files have changed in this diff Show More