forked from cerc-io/laconicd-deprecated
Merge pull request #35 from vulcanize/sai/upgrade_cosmos_v0.46
upgrade: upgrade to vulcanize cosmos v0.46 SMT
This commit is contained in:
commit
007e27dcbc
23
Makefile
23
Makefile
@ -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} .
|
||||
|
103
app/ante/ante.go
103
app/ante/ante.go
@ -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)
|
||||
}
|
@ -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
|
534
app/ante/eth.go
534
app/ante/eth.go
@ -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)
|
||||
}
|
@ -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),
|
||||
)
|
||||
}
|
@ -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)
|
||||
}
|
242
app/app.go
242
app/app.go
@ -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{},
|
||||
@ -173,15 +183,14 @@ var (
|
||||
|
||||
// module account permissions
|
||||
maccPerms = map[string][]string{
|
||||
authtypes.FeeCollectorName: nil,
|
||||
distrtypes.ModuleName: nil,
|
||||
minttypes.ModuleName: {authtypes.Minter},
|
||||
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
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
|
||||
|
||||
authtypes.FeeCollectorName: nil,
|
||||
distrtypes.ModuleName: nil,
|
||||
minttypes.ModuleName: {authtypes.Minter},
|
||||
stakingtypes.BondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
stakingtypes.NotBondedPoolName: {authtypes.Burner, authtypes.Staking},
|
||||
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
|
||||
|
||||
invCheckPeriod uint
|
||||
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{
|
||||
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,
|
||||
MaxTxGasWanted: maxGasWanted,
|
||||
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,
|
||||
FeeMarketKeeper: app.FeeMarketKeeper,
|
||||
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
|
||||
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)
|
||||
|
@ -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)
|
||||
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",
|
||||
)
|
||||
}
|
||||
|
||||
// Initialize the chain
|
||||
app.InitChain(
|
||||
abci.RequestInitChain{
|
||||
ChainId: "ethermint_9000-1",
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
AppStateBytes: stateBytes,
|
||||
},
|
||||
)
|
||||
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")
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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{
|
||||
ak: ak,
|
||||
signModeHandler: signModeHandler,
|
||||
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
757
app/middleware/eth.go
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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 {
|
@ -1,4 +1,4 @@
|
||||
package ante
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"math/big"
|
116
app/middleware/middleware.go
Normal file
116
app/middleware/middleware.go
Normal 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)
|
||||
}
|
@ -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
178
app/middleware/options.go
Normal 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
67
app/middleware/reject.go
Normal 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{}
|
@ -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
|
||||
|
@ -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{
|
||||
AccountKeeper: suite.app.AccountKeeper,
|
||||
BankKeeper: suite.app.BankKeeper,
|
||||
EvmKeeper: suite.app.EvmKeeper,
|
||||
FeegrantKeeper: suite.app.FeeGrantKeeper,
|
||||
IBCKeeper: suite.app.IBCKeeper,
|
||||
FeeMarketKeeper: suite.app.FeeMarketKeeper,
|
||||
SignModeHandler: encodingConfig.TxConfig.SignModeHandler(),
|
||||
SigGasConsumer: ante.DefaultSigVerificationGasConsumer,
|
||||
options := middleware.HandlerOptions{
|
||||
TxDecoder: suite.clientCtx.TxConfig.TxDecoder(),
|
||||
AccountKeeper: suite.app.AccountKeeper,
|
||||
BankKeeper: suite.app.BankKeeper,
|
||||
EvmKeeper: suite.app.EvmKeeper,
|
||||
FeegrantKeeper: suite.app.FeeGrantKeeper,
|
||||
Codec: suite.app.AppCodec(),
|
||||
Debug: suite.app.Trace(),
|
||||
LegacyRouter: suite.app.LegacyRouter,
|
||||
MsgServiceRouter: suite.app.MsgSvcRouter,
|
||||
FeeMarketKeeper: suite.app.FeeMarketKeeper,
|
||||
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,
|
||||
})
|
@ -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(
|
||||
|
@ -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,21 +60,50 @@ 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{})
|
||||
// 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 := ðermint.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 := 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
|
||||
genesisState := NewDefaultGenesisState()
|
||||
if patchGenesis != nil {
|
||||
genesisState = patchGenesis(app, genesisState)
|
||||
}
|
||||
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
stateBytes, err := tmjson.MarshalIndent(genesisState, "", " ")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Initialize the chain
|
||||
app.InitChain(
|
||||
@ -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 := ðermint.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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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])
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -10,4 +10,5 @@ import (
|
||||
// RegisterInterfaces register the Ethermint key concrete types.
|
||||
func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
registry.RegisterImplementations((*cryptotypes.PubKey)(nil), ðsecp256k1.PubKey{})
|
||||
registry.RegisterImplementations((*cryptotypes.PrivKey)(nil), ðsecp256k1.PrivKey{})
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
108
go.mod
@ -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
|
||||
)
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
117
rpc/apis.go
117
rpc/apis.go
@ -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 {
|
||||
nonceLock := new(types.AddrLocker)
|
||||
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
|
||||
// APICreator creates the json-rpc api implementations.
|
||||
type APICreator = func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API
|
||||
|
||||
var apis []rpc.API
|
||||
// remove duplicates
|
||||
selectedAPIs = unique(selectedAPIs)
|
||||
// apiCreators defines the json-rpc api namespaces.
|
||||
var apiCreators map[string]APICreator
|
||||
|
||||
for index := range selectedAPIs {
|
||||
switch selectedAPIs[index] {
|
||||
case EthNamespace:
|
||||
apis = append(apis,
|
||||
rpc.API{
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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"
|
||||
)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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!")
|
||||
|
@ -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()
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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" \
|
||||
--json-rpc.address=$IP_ADDR:$RPC_PORT"$i" \
|
||||
--json-rpc.api="eth,txpool,personal,net,debug,web3" \
|
||||
--keyring-backend test --home "$DATA_DIR$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 --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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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"
|
||||
}
|
||||
|
@ -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 err != nil {
|
||||
logger.Error("failed init node", "error", err.Error())
|
||||
return err
|
||||
}
|
||||
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")
|
||||
|
||||
if err := tmNode.Start(); err != nil {
|
||||
logger.Error("failed start tendermint server", "error", err.Error())
|
||||
return err
|
||||
tmNode, err = node.New(cfg, ctx.Logger, abciclient.NewLocalCreator(app), genDoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tmNode.Start(); err != nil {
|
||||
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) {
|
||||
|
@ -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() {
|
||||
logger.Debug("EVM RPC reconnects to Tendermint WS", "address", tmRPCAddr+tmEndpoint)
|
||||
}),
|
||||
)
|
||||
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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
6
types/address.go
Normal file
@ -0,0 +1,6 @@
|
||||
package types
|
||||
|
||||
const (
|
||||
// Bech32MainPrefix defines the main SDK Bech32 prefix of an account's address
|
||||
Bech32MainPrefix = "ethm"
|
||||
)
|
@ -19,7 +19,7 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
|
||||
&EthAccount{},
|
||||
)
|
||||
registry.RegisterInterface(
|
||||
"ethermint.v1.ExtensionOptionsWeb3Tx",
|
||||
"ethermint.types.v1.ExtensionOptionsWeb3Tx",
|
||||
(*ExtensionOptionsWeb3TxI)(nil),
|
||||
&ExtensionOptionsWeb3Tx{},
|
||||
)
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
)
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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())
|
||||
}
|
||||
|
@ -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{})
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
}))
|
||||
|
@ -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())
|
||||
|
@ -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{})
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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")
|
||||
// }
|
||||
|
@ -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 := ðermint.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 := ðermint.EthAccount{
|
||||
acc = ðermint.EthAccount{
|
||||
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0),
|
||||
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
)
|
||||
}
|
||||
|
31
x/evm/simulation/decoder.go
Normal file
31
x/evm/simulation/decoder.go
Normal 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]))
|
||||
}
|
||||
}
|
||||
}
|
@ -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())
|
||||
|
302
x/evm/simulation/operations.go
Normal file
302
x/evm/simulation/operations.go
Normal 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
|
||||
}
|
28
x/evm/simulation/params.go
Normal file
28
x/evm/simulation/params.go
Normal 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))
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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"
|
||||
|
||||
@ -22,9 +23,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
_ sdk.Msg = &MsgEthereumTx{}
|
||||
_ sdk.Tx = &MsgEthereumTx{}
|
||||
_ ante.GasTx = &MsgEthereumTx{}
|
||||
_ sdk.Msg = &MsgEthereumTx{}
|
||||
_ sdk.Tx = &MsgEthereumTx{}
|
||||
_ authmiddleware.GasTx = &MsgEthereumTx{}
|
||||
|
||||
_ codectypes.UnpackInterfacesMessage = MsgEthereumTx{}
|
||||
)
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user