conflicts

This commit is contained in:
Federico Kunze
2021-04-17 12:00:07 +02:00
parent 20f9a72908
commit 5a3d514ba0
173 changed files with 19392 additions and 13626 deletions
-26
View File
@@ -1,26 +0,0 @@
package evm
import (
"github.com/cosmos/ethermint/x/evm/keeper"
"github.com/cosmos/ethermint/x/evm/types"
)
// nolint
const (
ModuleName = types.ModuleName
StoreKey = types.StoreKey
RouterKey = types.RouterKey
DefaultParamspace = types.DefaultParamspace
)
// nolint
var (
NewKeeper = keeper.NewKeeper
TxDecoder = types.TxDecoder
)
//nolint
type (
Keeper = keeper.Keeper
GenesisState = types.GenesisState
)
+61 -44
View File
@@ -1,88 +1,105 @@
package cli
import (
"fmt"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
rpctypes "github.com/cosmos/ethermint/rpc/types"
"github.com/cosmos/ethermint/x/evm/types"
)
// GetQueryCmd defines evm module queries through the cli
func GetQueryCmd(moduleName string, cdc *codec.Codec) *cobra.Command {
evmQueryCmd := &cobra.Command{
// GetQueryCmd returns the parent command for all x/bank CLi query commands.
func GetQueryCmd() *cobra.Command {
cmd := &cobra.Command{
Use: types.ModuleName,
Short: "Querying commands for the evm module",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
evmQueryCmd.AddCommand(flags.GetCommands(
GetCmdGetStorageAt(moduleName, cdc),
GetCmdGetCode(moduleName, cdc),
)...)
return evmQueryCmd
cmd.AddCommand(
GetStorageCmd(),
GetCodeCmd(),
)
return cmd
}
// GetCmdGetStorageAt queries a key in an accounts storage
func GetCmdGetStorageAt(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "storage [account] [key]",
Short: "Gets storage for an account at a given key",
// GetStorageCmd queries a key in an accounts storage
func GetStorageCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "storage [address] [key]",
Short: "Gets storage for an account with a given key and height",
Long: "Gets storage for an account with a given key and height. If the height is not provided, it will use the latest height from context.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := context.NewCLIContext().WithCodec(cdc)
account, err := accountToHex(args[0])
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return errors.Wrap(err, "could not parse account address")
return err
}
queryClient := types.NewQueryClient(clientCtx)
address, err := accountToHex(args[0])
if err != nil {
return err
}
key := formatKeyToHash(args[1])
res, _, err := clientCtx.Query(
fmt.Sprintf("custom/%s/storage/%s/%s", queryRoute, account, key))
if err != nil {
return fmt.Errorf("could not resolve: %s", err)
req := &types.QueryStorageRequest{
Address: address,
Key: key,
}
var out types.QueryResStorage
cdc.MustUnmarshalJSON(res, &out)
return clientCtx.PrintOutput(out)
res, err := queryClient.Storage(rpctypes.ContextWithHeight(clientCtx.Height), req)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdGetCode queries the code field of a given address
func GetCmdGetCode(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "code [account]",
// GetCodeCmd queries the code field of a given address
func GetCodeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "code [address]",
Short: "Gets code from an account",
Long: "Gets code from an account. If the height is not provided, it will use the latest height from context.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := context.NewCLIContext().WithCodec(cdc)
account, err := accountToHex(args[0])
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return errors.Wrap(err, "could not parse account address")
return err
}
res, _, err := clientCtx.Query(
fmt.Sprintf("custom/%s/code/%s", queryRoute, account))
queryClient := types.NewQueryClient(clientCtx)
address, err := accountToHex(args[0])
if err != nil {
return fmt.Errorf("could not resolve: %s", err)
return err
}
var out types.QueryResCode
cdc.MustUnmarshalJSON(res, &out)
return clientCtx.PrintOutput(out)
req := &types.QueryCodeRequest{
Address: address,
}
res, err := queryClient.Code(rpctypes.ContextWithHeight(clientCtx.Height), req)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
+32 -33
View File
@@ -1,90 +1,89 @@
package rest
import (
"context"
"encoding/hex"
"encoding/json"
"net/http"
"strings"
"github.com/cosmos/cosmos-sdk/client/context"
"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"
"github.com/cosmos/cosmos-sdk/x/auth/client/utils"
rpctypes "github.com/cosmos/ethermint/rpc/types"
"github.com/ethereum/go-ethereum/common"
"github.com/gorilla/mux"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/txs/{hash}", QueryTxRequestHandlerFn(cliCtx)).Methods("GET")
r.HandleFunc("/txs", authrest.QueryTxsRequestHandlerFn(cliCtx)).Methods("GET") // default from auth
r.HandleFunc("/txs", authrest.BroadcastTxRequest(cliCtx)).Methods("POST") // default from auth
r.HandleFunc("/txs/encode", authrest.EncodeTxRequestHandlerFn(cliCtx)).Methods("POST") // default from auth
r.HandleFunc("/txs/decode", authrest.DecodeTxRequestHandlerFn(cliCtx)).Methods("POST") // default from auth
// 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", authrest.BroadcastTxRequest(clientCtx)).Methods("POST")
r.HandleFunc("/txs/encode", authrest.EncodeTxRequestHandlerFn(clientCtx)).Methods("POST")
r.HandleFunc("/txs/decode", authrest.DecodeTxRequestHandlerFn(clientCtx)).Methods("POST")
}
func QueryTxRequestHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
// 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"]
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
clientCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, clientCtx, r)
if !ok {
return
}
ethHashPrefix := "0x"
if strings.HasPrefix(hashHexStr, ethHashPrefix) {
// eth Tx
ethHashPrefixLength := len(ethHashPrefix)
output, err := getEthTransactionByHash(cliCtx, hashHexStr[ethHashPrefixLength:])
if err != nil {
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
rest.PostProcessResponseBare(w, cliCtx, output)
if !strings.HasPrefix(hashHexStr, ethHashPrefix) {
authrest.QueryTxRequestHandlerFn(clientCtx)
return
}
output, err := utils.QueryTx(cliCtx, hashHexStr)
// eth Tx
ethHashPrefixLength := len(ethHashPrefix)
output, err := getEthTransactionByHash(clientCtx, hashHexStr[ethHashPrefixLength:])
if err != nil {
if strings.Contains(err.Error(), hashHexStr) {
rest.WriteErrorResponse(w, http.StatusNotFound, err.Error())
return
}
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
return
}
rest.PostProcessResponseBare(w, cliCtx, output)
}
rest.PostProcessResponseBare(w, clientCtx, output)
}
}
// GetTransactionByHash returns the transaction identified by hash.
func getEthTransactionByHash(cliCtx context.CLIContext, hashHex string) ([]byte, error) {
func getEthTransactionByHash(clientCtx client.Context, hashHex string) ([]byte, error) {
hash, err := hex.DecodeString(hashHex)
if err != nil {
return nil, err
}
node, err := cliCtx.GetNode()
node, err := clientCtx.GetNode()
if err != nil {
return nil, err
}
tx, err := node.Tx(hash, false)
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(&tx.Height)
block, err := node.Block(context.Background(), &tx.Height)
if err != nil {
return nil, err
}
blockHash := common.BytesToHash(block.Block.Hash())
ethTx, err := rpctypes.RawTxToEthTx(cliCtx, tx.Tx)
ethTx, err := rpctypes.RawTxToEthTx(clientCtx, tx.Tx)
if err != nil {
return nil, err
}
+10 -10
View File
@@ -4,7 +4,7 @@ import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
ethcmn "github.com/ethereum/go-ethereum/common"
@@ -20,9 +20,9 @@ func InitGenesis(
ctx sdk.Context,
k keeper.Keeper,
accountKeeper types.AccountKeeper, // nolint: interfacer
data GenesisState,
bankKeeper types.BankKeeper,
data types.GenesisState,
) []abci.ValidatorUpdate {
k.SetParams(ctx, data.Params)
evmDenom := data.Params.EvmDenom
@@ -44,10 +44,9 @@ func InitGenesis(
)
}
evmBalance := acc.GetCoins().AmountOf(evmDenom)
evmBalance := bankKeeper.GetBalance(ctx, accAddress, evmDenom)
k.SetBalance(ctx, address, evmBalance.Amount.BigInt())
k.SetNonce(ctx, address, acc.GetSequence())
k.SetBalance(ctx, address, evmBalance.BigInt())
k.SetCode(ctx, address, ethcmn.Hex2Bytes(account.Code))
for _, storage := range account.Storage {
@@ -57,7 +56,8 @@ func InitGenesis(
var err error
for _, txLog := range data.TxsLogs {
if err = k.SetLogs(ctx, ethcmn.HexToHash(txLog.Hash), txLog.Logs); err != nil {
err = k.SetLogs(ctx, ethcmn.HexToHash(txLog.Hash), txLog.EthLogs())
if err != nil {
panic(err)
}
}
@@ -81,10 +81,10 @@ func InitGenesis(
}
// ExportGenesis exports genesis state of the EVM module
func ExportGenesis(ctx sdk.Context, k keeper.Keeper, ak types.AccountKeeper) GenesisState {
func ExportGenesis(ctx sdk.Context, k keeper.Keeper, ak types.AccountKeeper) *types.GenesisState {
// nolint: prealloc
var ethGenAccounts []types.GenesisAccount
ak.IterateAccounts(ctx, func(account authexported.Account) bool {
ak.IterateAccounts(ctx, func(account authtypes.AccountI) bool {
ethAccount, ok := account.(*ethermint.EthAccount)
if !ok {
// ignore non EthAccounts
@@ -110,7 +110,7 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper, ak types.AccountKeeper) Gen
config, _ := k.GetChainConfig(ctx)
return GenesisState{
return &types.GenesisState{
Accounts: ethGenAccounts,
TxsLogs: k.GetAllTxLogs(ctx),
ChainConfig: config,
+11 -11
View File
@@ -1,7 +1,6 @@
package evm_test
import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
@@ -14,12 +13,12 @@ import (
)
func (suite *EvmTestSuite) TestExportImport() {
var genState types.GenesisState
var genState *types.GenesisState
suite.Require().NotPanics(func() {
genState = evm.ExportGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper)
})
_ = evm.InitGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper, genState)
_ = evm.InitGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper, suite.app.BankKeeper, *genState)
}
func (suite *EvmTestSuite) TestInitGenesis() {
@@ -31,7 +30,7 @@ func (suite *EvmTestSuite) TestInitGenesis() {
testCases := []struct {
name string
malleate func()
genState types.GenesisState
genState *types.GenesisState
expPanic bool
}{
{
@@ -45,11 +44,12 @@ func (suite *EvmTestSuite) TestInitGenesis() {
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
err := acc.SetCoins(sdk.NewCoins(ethermint.NewPhotonCoinInt64(1)))
err := suite.app.BankKeeper.SetBalance(suite.ctx, address.Bytes(), ethermint.NewPhotonCoinInt64(1))
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
},
types.GenesisState{
&types.GenesisState{
Params: types.DefaultParams(),
Accounts: []types.GenesisAccount{
{
@@ -65,7 +65,7 @@ func (suite *EvmTestSuite) TestInitGenesis() {
{
"account not found",
func() {},
types.GenesisState{
&types.GenesisState{
Params: types.DefaultParams(),
Accounts: []types.GenesisAccount{
{
@@ -79,9 +79,9 @@ func (suite *EvmTestSuite) TestInitGenesis() {
"invalid account type",
func() {
acc := authtypes.NewBaseAccountWithAddress(address.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, &acc)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
},
types.GenesisState{
&types.GenesisState{
Params: types.DefaultParams(),
Accounts: []types.GenesisAccount{
{
@@ -102,13 +102,13 @@ func (suite *EvmTestSuite) TestInitGenesis() {
if tc.expPanic {
suite.Require().Panics(
func() {
_ = evm.InitGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper, tc.genState)
_ = evm.InitGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper, suite.app.BankKeeper, *tc.genState)
},
)
} else {
suite.Require().NotPanics(
func() {
_ = evm.InitGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper, tc.genState)
_ = evm.InitGenesis(suite.ctx, *suite.app.EvmKeeper, suite.app.AccountKeeper, suite.app.BankKeeper, *tc.genState)
},
)
}
+43 -114
View File
@@ -1,20 +1,24 @@
package evm
import (
"github.com/ethereum/go-ethereum/common"
"fmt"
"time"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/keeper"
"github.com/cosmos/ethermint/x/evm/types"
ethcmn "github.com/ethereum/go-ethereum/common"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
tmtypes "github.com/tendermint/tendermint/types"
)
// NewHandler returns a handler for Ethermint type messages.
func NewHandler(k *Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (result *sdk.Result, err error) {
func NewHandler(k keeper.Keeper) sdk.Handler {
defer telemetry.MeasureSince(time.Now(), "evm", "state_transition")
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
snapshotStateDB := k.CommitStateDB.Copy()
// The "recover" code here is used to solve the problem of dirty data
@@ -46,116 +50,41 @@ func NewHandler(k *Keeper) sdk.Handler {
}
}()
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
case types.MsgEthereumTx:
result, err = handleMsgEthereumTx(ctx, k, msg)
case types.MsgEthermint:
result, err = handleMsgEthermint(ctx, k, msg)
case *types.MsgEthereumTx:
// execute state transition
res, err := k.EthereumTx(sdk.WrapSDKContext(ctx), msg)
if err != nil {
return nil, err
}
result, err := sdk.WrapServiceResult(ctx, res, err)
if err != nil {
return nil, err
}
// log state transition result
var recipientLog string
if res.ContractAddress != "" {
recipientLog = fmt.Sprintf("contract address %s", res.ContractAddress)
} else {
recipientLog = fmt.Sprintf("recipient address %s", msg.Data.Recipient)
}
sender := ethcmn.BytesToAddress(msg.GetFrom().Bytes())
log := fmt.Sprintf(
"executed EVM state transition; sender address %s; %s", sender, recipientLog,
)
k.Logger(ctx).Info(log)
result.Log = log
return result, nil
default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
}
if err != nil {
types.CopyCommitStateDB(snapshotStateDB, k.CommitStateDB)
}
return result, err
}
}
// handleMsgEthereumTx handles an Ethereum specific tx
func handleMsgEthereumTx(ctx sdk.Context, k *Keeper, msg types.MsgEthereumTx) (*sdk.Result, error) {
// execute state transition
res, err := k.EthereumTx(ctx, msg)
if err != nil {
return nil, err
}
// log state transition result
k.Logger(ctx).Info(res.Log)
return res, nil
}
// handleMsgEthermint handles an sdk.StdTx for an Ethereum state transition
func handleMsgEthermint(ctx sdk.Context, k *Keeper, msg types.MsgEthermint) (*sdk.Result, error) {
// parse the chainID from a string to a base-10 integer
chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID())
if err != nil {
return nil, err
}
txHash := tmtypes.Tx(ctx.TxBytes()).Hash()
ethHash := common.BytesToHash(txHash)
st := types.StateTransition{
AccountNonce: msg.AccountNonce,
Price: msg.Price.BigInt(),
GasLimit: msg.GasLimit,
Amount: msg.Amount.BigInt(),
Payload: msg.Payload,
Csdb: k.CommitStateDB.WithContext(ctx),
ChainID: chainIDEpoch,
TxHash: &ethHash,
Sender: common.BytesToAddress(msg.From.Bytes()),
Simulate: ctx.IsCheckTx(),
}
if msg.Recipient != nil {
to := common.BytesToAddress(msg.Recipient.Bytes())
st.Recipient = &to
}
if !st.Simulate {
// Prepare db for logs
k.CommitStateDB.Prepare(ethHash, k.TxCount)
k.TxCount++
}
config, found := k.GetChainConfig(ctx)
if !found {
return nil, types.ErrChainConfigNotFound
}
executionResult, err := st.TransitionDb(ctx, config)
if err != nil {
return nil, err
}
// update block bloom filter
if !st.Simulate {
k.Bloom.Or(k.Bloom, executionResult.Bloom)
// update transaction logs in KVStore
err = k.SetLogs(ctx, common.BytesToHash(txHash), executionResult.Logs)
if err != nil {
panic(err)
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg)
}
}
// log successful execution
k.Logger(ctx).Info(executionResult.Result.Log)
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeEthermint,
sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Amount.String()),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, msg.From.String()),
),
})
if msg.Recipient != nil {
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeEthermint,
sdk.NewAttribute(types.AttributeKeyRecipient, msg.Recipient.String()),
),
)
}
// set the events to the result
executionResult.Result.Events = ctx.EventManager().Events()
return executionResult.Result, nil
}
+68 -102
View File
@@ -3,7 +3,6 @@ package evm_test
import (
"crypto/ecdsa"
"encoding/json"
"fmt"
"math/big"
"strings"
"testing"
@@ -24,11 +23,9 @@ import (
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm"
"github.com/cosmos/ethermint/x/evm/keeper"
"github.com/cosmos/ethermint/x/evm/types"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/secp256k1"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
type EvmTestSuite struct {
@@ -36,19 +33,32 @@ type EvmTestSuite struct {
ctx sdk.Context
handler sdk.Handler
querier sdk.Querier
app *app.EthermintApp
codec *codec.Codec
codec codec.BinaryMarshaler
privKey *ethsecp256k1.PrivKey
from ethcmn.Address
to sdk.AccAddress
}
func (suite *EvmTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()})
suite.handler = evm.NewHandler(suite.app.EvmKeeper)
suite.querier = keeper.NewQuerier(*suite.app.EvmKeeper)
suite.codec = codec.New()
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()})
suite.handler = evm.NewHandler(*suite.app.EvmKeeper)
suite.codec = suite.app.AppCodec()
privKey, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
suite.to = sdk.AccAddress(privKey.PubKey().Address())
suite.privKey, err = ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
suite.from = ethcmn.BytesToAddress(privKey.PubKey().Address().Bytes())
}
func TestEvmTestSuite(t *testing.T) {
@@ -56,11 +66,8 @@ func TestEvmTestSuite(t *testing.T) {
}
func (suite *EvmTestSuite) TestHandleMsgEthereumTx() {
privkey, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
sender := ethcmn.HexToAddress(privkey.PubKey().Address().String())
var tx types.MsgEthereumTx
var tx *types.MsgEthereumTx
testCases := []struct {
msg string
@@ -70,15 +77,15 @@ func (suite *EvmTestSuite) TestHandleMsgEthereumTx() {
{
"passed",
func() {
suite.app.EvmKeeper.SetBalance(suite.ctx, sender, big.NewInt(100))
tx = types.NewMsgEthereumTx(0, &sender, big.NewInt(100), 0, big.NewInt(10000), nil)
suite.app.EvmKeeper.SetBalance(suite.ctx, suite.from, big.NewInt(100))
tx = types.NewMsgEthereumTx(0, &suite.from, big.NewInt(0), 0, big.NewInt(10000), nil)
// parse context chain ID to big.Int
chainID, err := ethermint.ParseChainID(suite.ctx.ChainID())
suite.Require().NoError(err)
// sign transaction
err = tx.Sign(chainID, privkey.ToECDSA())
err = tx.Sign(chainID, suite.privKey.ToECDSA())
suite.Require().NoError(err)
},
true,
@@ -93,7 +100,7 @@ func (suite *EvmTestSuite) TestHandleMsgEthereumTx() {
suite.Require().NoError(err)
// sign transaction
err = tx.Sign(chainID, privkey.ToECDSA())
err = tx.Sign(chainID, suite.privKey.ToECDSA())
suite.Require().NoError(err)
},
false,
@@ -141,62 +148,6 @@ func (suite *EvmTestSuite) TestHandleMsgEthereumTx() {
}
}
func (suite *EvmTestSuite) TestMsgEthermint() {
var (
tx types.MsgEthermint
from = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
to = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"passed",
func() {
tx = types.NewMsgEthermint(0, &to, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), from)
suite.app.EvmKeeper.SetBalance(suite.ctx, ethcmn.BytesToAddress(from.Bytes()), big.NewInt(100))
},
true,
},
{
"invalid state transition",
func() {
tx = types.NewMsgEthermint(0, &to, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), from)
},
false,
},
{
"invalid chain ID",
func() {
suite.ctx = suite.ctx.WithChainID("chainID")
},
false,
},
}
for _, tc := range testCases {
suite.Run("", func() {
suite.SetupTest() // reset
//nolint
tc.malleate()
res, err := suite.handler(suite.ctx, tx)
//nolint
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
} else {
suite.Require().Error(err)
suite.Require().Nil(res)
}
})
}
}
func (suite *EvmTestSuite) TestHandlerLogs() {
// Test contract:
@@ -231,20 +182,47 @@ func (suite *EvmTestSuite) TestHandlerLogs() {
result, err := suite.handler(suite.ctx, tx)
suite.Require().NoError(err, "failed to handle eth tx msg")
resultData, err := types.DecodeResultData(result.Data)
txResponse, err := types.DecodeTxResponse(result.Data)
suite.Require().NoError(err, "failed to decode result data")
suite.Require().Equal(len(resultData.Logs), 1)
suite.Require().Equal(len(resultData.Logs[0].Topics), 2)
suite.Require().Equal(len(txResponse.TxLogs.Logs), 1)
suite.Require().Equal(len(txResponse.TxLogs.Logs[0].Topics), 2)
hash := []byte{1}
err = suite.app.EvmKeeper.SetLogs(suite.ctx, ethcmn.BytesToHash(hash), resultData.Logs)
err = suite.app.EvmKeeper.SetLogs(suite.ctx, ethcmn.BytesToHash(hash), txResponse.TxLogs.EthLogs())
suite.Require().NoError(err)
logs, err := suite.app.EvmKeeper.GetLogs(suite.ctx, ethcmn.BytesToHash(hash))
suite.Require().NoError(err, "failed to get logs")
suite.Require().Equal(logs, resultData.Logs)
suite.Require().Equal(len(logs), len(txResponse.TxLogs.Logs))
for i, logI := range logs {
for j, logJ := range txResponse.TxLogs.Logs {
if i != j {
continue
}
suite.Require().Equal(uint64(logI.Index), logJ.Index)
suite.Require().Equal(logI.Data, logJ.Data)
suite.Require().Equal(logI.Address.String(), logJ.Address)
suite.Require().Equal(logI.BlockHash.String(), logJ.BlockHash)
suite.Require().Equal(logI.BlockNumber, logJ.BlockNumber)
suite.Require().Equal(logI.Removed, logJ.Removed)
suite.Require().Equal(logI.TxHash.String(), logJ.TxHash)
suite.Require().Equal(uint64(logI.TxIndex), logJ.TxIndex)
suite.Require().Equal(len(logI.Topics), len(logJ.Topics))
for i2, topicI := range logI.Topics {
for j2, topicJ := range logJ.Topics {
if i2 != j2 {
continue
}
suite.Require().Equal(topicI.String(), topicJ)
}
}
}
}
}
func (suite *EvmTestSuite) TestQueryTxLogs() {
@@ -264,31 +242,19 @@ func (suite *EvmTestSuite) TestQueryTxLogs() {
suite.Require().NoError(err)
suite.Require().NotNil(result)
resultData, err := types.DecodeResultData(result.Data)
txResponse, err := types.DecodeTxResponse(result.Data)
suite.Require().NoError(err, "failed to decode result data")
suite.Require().Equal(len(resultData.Logs), 1)
suite.Require().Equal(len(resultData.Logs[0].Topics), 2)
suite.Require().Equal(len(txResponse.TxLogs.Logs), 1)
suite.Require().Equal(len(txResponse.TxLogs.Logs[0].Topics), 2)
// get logs by tx hash
hash := resultData.TxHash.Bytes()
hash := txResponse.TxLogs.Hash
logs, err := suite.app.EvmKeeper.GetLogs(suite.ctx, ethcmn.BytesToHash(hash))
logs, err := suite.app.EvmKeeper.GetLogs(suite.ctx, ethcmn.HexToHash(hash))
suite.Require().NoError(err, "failed to get logs")
suite.Require().Equal(logs, resultData.Logs)
// query tx logs
path := []string{"transactionLogs", fmt.Sprintf("0x%x", hash)}
res, err := suite.querier(suite.ctx, path, abci.RequestQuery{})
suite.Require().NoError(err, "failed to query txLogs")
var txLogs types.QueryETHLogs
suite.codec.MustUnmarshalJSON(res, &txLogs)
// amino decodes an empty byte array as nil, whereas JSON decodes it as []byte{} causing a discrepancy
resultData.Logs[0].Data = []byte{}
suite.Require().Equal(txLogs.Logs[0], resultData.Logs[0])
suite.Require().Equal(logs, txResponse.TxLogs.EthLogs())
}
func (suite *EvmTestSuite) TestDeployAndCallContract() {
@@ -361,13 +327,13 @@ func (suite *EvmTestSuite) TestDeployAndCallContract() {
result, err := suite.handler(suite.ctx, tx)
suite.Require().NoError(err, "failed to handle eth tx msg")
resultData, err := types.DecodeResultData(result.Data)
txResponse, err := types.DecodeTxResponse(result.Data)
suite.Require().NoError(err, "failed to decode result data")
// store - changeOwner
gasLimit = uint64(100000000000)
gasPrice = big.NewInt(100)
receiver := common.HexToAddress(resultData.ContractAddress.String())
receiver := common.HexToAddress(txResponse.ContractAddress)
storeAddr := "0xa6f9dae10000000000000000000000006a82e4a67715c8412a9114fbd2cbaefbc8181424"
bytecode = common.FromHex(storeAddr)
@@ -378,7 +344,7 @@ func (suite *EvmTestSuite) TestDeployAndCallContract() {
result, err = suite.handler(suite.ctx, tx)
suite.Require().NoError(err, "failed to handle eth tx msg")
resultData, err = types.DecodeResultData(result.Data)
txResponse, err = types.DecodeTxResponse(result.Data)
suite.Require().NoError(err, "failed to decode result data")
// query - getOwner
@@ -390,10 +356,10 @@ func (suite *EvmTestSuite) TestDeployAndCallContract() {
result, err = suite.handler(suite.ctx, tx)
suite.Require().NoError(err, "failed to handle eth tx msg")
resultData, err = types.DecodeResultData(result.Data)
txResponse, err = types.DecodeTxResponse(result.Data)
suite.Require().NoError(err, "failed to decode result data")
getAddr := strings.ToLower(hexutils.BytesToHex(resultData.Ret))
getAddr := strings.ToLower(hexutils.BytesToHex(txResponse.Ret))
suite.Require().Equal(true, strings.HasSuffix(storeAddr, getAddr), "Fail to query the address")
}
+2 -4
View File
@@ -11,7 +11,7 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
// BeginBlock sets the block hash -> block height map for the previous block height
// BeginBlock sets the block height -> header hash map for the previous block height
// and resets the Bloom filter and the transaction count to 0.
func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
if req.Header.LastBlockId.GetHash() == nil || req.Header.GetHeight() < 1 {
@@ -25,9 +25,7 @@ func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
currentHash := req.Hash
height := req.Header.GetHeight()
k.SetHeightHash(ctx, uint64(height), common.BytesToHash(currentHash))
k.SetBlockHash(ctx, currentHash, height)
k.CommitStateDB.SetBlockHash(common.BytesToHash(currentHash))
k.SetHeightHash(ctx, uint64(height), common.BytesToHash(hash))
// reset counters that are used on CommitStateDB.Prepare
k.Bloom = big.NewInt(0)
-25
View File
@@ -5,19 +5,6 @@ import (
)
func (suite *KeeperTestSuite) TestBeginBlock() {
req := abci.RequestBeginBlock{
Header: abci.Header{
LastBlockId: abci.BlockID{
Hash: []byte("last hash"),
},
Height: 10,
},
Hash: []byte("hash"),
}
// get the initial consumption
initialConsumed := suite.ctx.GasMeter().GasConsumed()
// update the counters
suite.app.EvmKeeper.Bloom.SetInt64(10)
suite.app.EvmKeeper.TxCount = 10
@@ -25,18 +12,6 @@ func (suite *KeeperTestSuite) TestBeginBlock() {
suite.app.EvmKeeper.BeginBlock(suite.ctx, abci.RequestBeginBlock{})
suite.Require().NotZero(suite.app.EvmKeeper.Bloom.Int64())
suite.Require().NotZero(suite.app.EvmKeeper.TxCount)
suite.Require().Equal(int64(initialConsumed), int64(suite.ctx.GasMeter().GasConsumed()))
suite.app.EvmKeeper.BeginBlock(suite.ctx, req)
suite.Require().Zero(suite.app.EvmKeeper.Bloom.Int64())
suite.Require().Zero(suite.app.EvmKeeper.TxCount)
suite.Require().Equal(int64(initialConsumed), int64(suite.ctx.GasMeter().GasConsumed()))
lastHeight, found := suite.app.EvmKeeper.GetBlockHash(suite.ctx, req.Hash)
suite.Require().True(found)
suite.Require().Equal(int64(10), lastHeight)
}
func (suite *KeeperTestSuite) TestEndBlock() {
+206
View File
@@ -0,0 +1,206 @@
package keeper
import (
"context"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
sdk "github.com/cosmos/cosmos-sdk/types"
ethcmn "github.com/ethereum/go-ethereum/common"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
)
var _ types.QueryServer = Keeper{}
// Account implements the Query/Account gRPC method
func (q Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*types.QueryAccountResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.Address) == 0 {
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
so := q.GetOrNewStateObject(ctx, ethcmn.HexToAddress(req.Address))
balance, err := ethermint.MarshalBigInt(so.Balance())
if err != nil {
return nil, err
}
return &types.QueryAccountResponse{
Balance: balance,
CodeHash: so.CodeHash(),
Nonce: so.Nonce(),
}, nil
}
// Balance implements the Query/Balance gRPC method
func (q Keeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*types.QueryBalanceResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.Address) == 0 {
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
balanceInt := q.GetBalance(ctx, ethcmn.HexToAddress(req.Address))
balance, err := ethermint.MarshalBigInt(balanceInt)
if err != nil {
return nil, status.Error(
codes.Internal,
"failed to marshal big.Int to string",
)
}
return &types.QueryBalanceResponse{
Balance: balance,
}, nil
}
// Storage implements the Query/Storage gRPC method
func (q Keeper) Storage(c context.Context, req *types.QueryStorageRequest) (*types.QueryStorageResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.Address) == 0 {
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
)
}
if len(req.Key) == 0 {
return nil, status.Error(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
address := ethcmn.HexToAddress(req.Address)
key := ethcmn.HexToHash(req.Key)
state := q.GetState(ctx, address, key)
return &types.QueryStorageResponse{
Value: state.String(),
}, nil
}
// Code implements the Query/Code gRPC method
func (q Keeper) Code(c context.Context, req *types.QueryCodeRequest) (*types.QueryCodeResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.Address) == 0 {
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
address := ethcmn.HexToAddress(req.Address)
code := q.GetCode(ctx, address)
return &types.QueryCodeResponse{
Code: code,
}, nil
}
// TxLogs implements the Query/TxLogs gRPC method
func (q Keeper) TxLogs(c context.Context, req *types.QueryTxLogsRequest) (*types.QueryTxLogsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if types.IsEmptyHash(req.Hash) {
return nil, status.Error(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
hash := ethcmn.HexToHash(req.Hash)
logs, err := q.GetLogs(ctx, hash)
if err != nil {
return nil, status.Error(
codes.Internal,
err.Error(),
)
}
return &types.QueryTxLogsResponse{
Logs: types.NewTransactionLogsFromEth(hash, logs).Logs,
}, nil
}
// BlockLogs implements the Query/BlockLogs gRPC method
func (q Keeper) BlockLogs(c context.Context, req *types.QueryBlockLogsRequest) (*types.QueryBlockLogsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if types.IsEmptyHash(req.Hash) {
return nil, status.Error(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
txLogs := q.GetAllTxLogs(ctx)
return &types.QueryBlockLogsResponse{
TxLogs: txLogs,
}, nil
}
// BlockBloom implements the Query/BlockBloom gRPC method
func (q Keeper) BlockBloom(c context.Context, _ *types.QueryBlockBloomRequest) (*types.QueryBlockBloomResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
// use block height provided through the gRPC header
bloom, found := q.GetBlockBloom(ctx, ctx.BlockHeight())
if !found {
return nil, status.Errorf(
codes.NotFound, "%s: height %d", types.ErrBloomNotFound.Error(), ctx.BlockHeight(),
)
}
return &types.QueryBlockBloomResponse{
Bloom: bloom.Bytes(),
}, nil
}
// Params implements the Query/Params gRPC method
func (q Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
ctx := sdk.UnwrapSDKContext(c)
params := q.GetParams(ctx)
return &types.QueryParamsResponse{
Params: params,
}, nil
}
+499
View File
@@ -0,0 +1,499 @@
package keeper_test
import (
"fmt"
"google.golang.org/grpc/metadata"
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
)
func (suite *KeeperTestSuite) TestQueryAccount() {
var (
req *types.QueryAccountRequest
expAccount *types.QueryAccountResponse
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{"zero address",
func() {
suite.app.BankKeeper.SetBalance(suite.ctx, suite.address.Bytes(), ethermint.NewPhotonCoinInt64(0))
expAccount = &types.QueryAccountResponse{
Balance: "0",
CodeHash: ethcrypto.Keccak256(nil),
Nonce: 0,
}
req = &types.QueryAccountRequest{
Address: ethcmn.Address{}.String(),
}
},
true,
},
{
"success",
func() {
suite.app.BankKeeper.SetBalance(suite.ctx, suite.address.Bytes(), ethermint.NewPhotonCoinInt64(100))
expAccount = &types.QueryAccountResponse{
Balance: "100",
CodeHash: ethcrypto.Keccak256(nil),
Nonce: 0,
}
req = &types.QueryAccountRequest{
Address: suite.address.String(),
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)
res, err := suite.queryClient.Account(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(expAccount, res)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryBalance() {
var (
req *types.QueryBalanceRequest
expBalance string
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{"zero address",
func() {
suite.app.BankKeeper.SetBalance(suite.ctx, suite.address.Bytes(), ethermint.NewPhotonCoinInt64(0))
expBalance = "0"
req = &types.QueryBalanceRequest{
Address: ethcmn.Address{}.String(),
}
},
true,
},
{
"success",
func() {
suite.app.BankKeeper.SetBalance(suite.ctx, suite.address.Bytes(), ethermint.NewPhotonCoinInt64(100))
expBalance = "100"
req = &types.QueryBalanceRequest{
Address: suite.address.String(),
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)
res, err := suite.queryClient.Balance(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(expBalance, res.Balance)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryStorage() {
var (
req *types.QueryStorageRequest
expValue string
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{"zero address",
func() {
req = &types.QueryStorageRequest{
Address: ethcmn.Address{}.String(),
}
},
false,
},
{"empty hash",
func() {
req = &types.QueryStorageRequest{
Address: suite.address.String(),
Key: ethcmn.Hash{}.String(),
}
exp := &types.QueryStorageResponse{Value: "0x0000000000000000000000000000000000000000000000000000000000000000"}
expValue = exp.Value
},
true,
},
{
"success",
func() {
key := ethcmn.BytesToHash([]byte("key"))
value := ethcmn.BytesToHash([]byte("value"))
expValue = value.String()
suite.app.EvmKeeper.SetState(suite.ctx, suite.address, key, value)
req = &types.QueryStorageRequest{
Address: suite.address.String(),
Key: key.String(),
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)
res, err := suite.queryClient.Storage(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(expValue, res.Value)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryCode() {
var (
req *types.QueryCodeRequest
expCode []byte
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{"zero address",
func() {
req = &types.QueryCodeRequest{
Address: ethcmn.Address{}.String(),
}
exp := &types.QueryCodeResponse{}
expCode = exp.Code
},
true,
},
{
"success",
func() {
expCode = []byte("code")
suite.app.EvmKeeper.SetCode(suite.ctx, suite.address, expCode)
req = &types.QueryCodeRequest{
Address: suite.address.String(),
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)
res, err := suite.queryClient.Code(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(expCode, res.Code)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryTxLogs() {
var (
req *types.QueryTxLogsRequest
expLogs []*types.Log
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{"empty hash",
func() {
req = &types.QueryTxLogsRequest{
Hash: ethcmn.Hash{}.String(),
}
},
false,
},
{"logs not found",
func() {
hash := ethcmn.BytesToHash([]byte("hash"))
req = &types.QueryTxLogsRequest{
Hash: hash.String(),
}
},
true,
},
{
"success",
func() {
hash := ethcmn.BytesToHash([]byte("tx_hash"))
expLogs = []*types.Log{
{
Address: suite.address.String(),
Topics: []string{ethcmn.BytesToHash([]byte("topic")).String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: hash.String(),
TxIndex: 1,
BlockHash: ethcmn.BytesToHash([]byte("block_hash")).String(),
Index: 0,
Removed: false,
},
}
suite.app.EvmKeeper.SetLogs(suite.ctx, hash, types.LogsToEthereum(expLogs))
req = &types.QueryTxLogsRequest{
Hash: hash.String(),
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)
res, err := suite.queryClient.TxLogs(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(expLogs, res.Logs)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryBlockLogs() {
var (
req *types.QueryBlockLogsRequest
expLogs []types.TransactionLogs
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{"empty hash",
func() {
req = &types.QueryBlockLogsRequest{
Hash: ethcmn.Hash{}.String(),
}
},
false,
},
{"logs not found",
func() {
hash := ethcmn.BytesToHash([]byte("hash"))
req = &types.QueryBlockLogsRequest{
Hash: hash.String(),
}
},
true,
},
{
"success",
func() {
hash := ethcmn.BytesToHash([]byte("block_hash"))
expLogs = []types.TransactionLogs{
{
Hash: ethcmn.BytesToHash([]byte("tx_hash_0")).String(),
Logs: []*types.Log{
{
Address: suite.address.String(),
Topics: []string{ethcmn.BytesToHash([]byte("topic")).String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: ethcmn.BytesToHash([]byte("tx_hash_0")).String(),
TxIndex: 1,
BlockHash: ethcmn.BytesToHash([]byte("block_hash")).String(),
Index: 0,
Removed: false,
},
},
},
{
Hash: ethcmn.BytesToHash([]byte("tx_hash_1")).String(),
Logs: []*types.Log{
{
Address: suite.address.String(),
Topics: []string{ethcmn.BytesToHash([]byte("topic")).String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: ethcmn.BytesToHash([]byte("tx_hash_1")).String(),
TxIndex: 1,
BlockHash: ethcmn.BytesToHash([]byte("block_hash")).String(),
Index: 0,
Removed: false,
},
{
Address: suite.address.String(),
Topics: []string{ethcmn.BytesToHash([]byte("topic_1")).String()},
Data: []byte("data_1"),
BlockNumber: 1,
TxHash: ethcmn.BytesToHash([]byte("tx_hash_1")).String(),
TxIndex: 1,
BlockHash: ethcmn.BytesToHash([]byte("block_hash")).String(),
Index: 0,
Removed: false,
},
},
},
}
suite.app.EvmKeeper.SetLogs(suite.ctx, ethcmn.BytesToHash([]byte("tx_hash_0")), types.LogsToEthereum(expLogs[0].Logs))
suite.app.EvmKeeper.SetLogs(suite.ctx, ethcmn.BytesToHash([]byte("tx_hash_1")), types.LogsToEthereum(expLogs[1].Logs))
req = &types.QueryBlockLogsRequest{
Hash: hash.String(),
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)
res, err := suite.queryClient.BlockLogs(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(expLogs, res.TxLogs)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryBlockBloom() {
var (
req *types.QueryBlockBloomRequest
expBloom []byte
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{"bloom bytes not found for height",
func() {},
false,
},
{
"success",
func() {
req = &types.QueryBlockBloomRequest{}
bloom := ethtypes.BytesToBloom([]byte("bloom"))
expBloom = bloom.Bytes()
suite.ctx = suite.ctx.WithBlockHeight(1)
suite.app.EvmKeeper.SetBlockBloom(suite.ctx, 1, bloom)
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)
ctx = metadata.AppendToOutgoingContext(ctx, grpctypes.GRPCBlockHeightHeader, fmt.Sprintf("%d", suite.ctx.BlockHeight()))
res, err := suite.queryClient.BlockBloom(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(expBloom, res.Bloom)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryParams() {
ctx := sdk.WrapSDKContext(suite.ctx)
expParams := types.DefaultParams()
res, err := suite.queryClient.Params(ctx, &types.QueryParamsRequest{})
suite.Require().NoError(err)
suite.Require().Equal(expParams, res.Params)
}
+6 -5
View File
@@ -4,7 +4,7 @@ import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
@@ -30,7 +30,7 @@ func (k Keeper) BalanceInvariant() sdk.Invariant {
count int
)
k.accountKeeper.IterateAccounts(ctx, func(account authexported.Account) bool {
k.accountKeeper.IterateAccounts(ctx, func(account authtypes.AccountI) bool {
ethAccount, ok := account.(*ethermint.EthAccount)
if !ok {
// ignore non EthAccounts
@@ -38,10 +38,11 @@ func (k Keeper) BalanceInvariant() sdk.Invariant {
}
evmDenom := k.GetParams(ctx).EvmDenom
accountBalance := ethAccount.GetCoins().AmountOf(evmDenom)
accountBalance := k.bankKeeper.GetBalance(ctx, ethAccount.GetAddress(), evmDenom)
evmBalance := k.GetBalance(ctx, ethAccount.EthAddress())
if evmBalance.Cmp(accountBalance.BigInt()) != 0 {
if evmBalance.Cmp(accountBalance.Amount.BigInt()) != 0 {
count++
msg += fmt.Sprintf(
"\tbalance mismatch for address %s: account balance %s, evm balance %s\n",
@@ -70,7 +71,7 @@ func (k Keeper) NonceInvariant() sdk.Invariant {
count int
)
k.accountKeeper.IterateAccounts(ctx, func(account authexported.Account) bool {
k.accountKeeper.IterateAccounts(ctx, func(account authtypes.AccountI) bool {
ethAccount, ok := account.(*ethermint.EthAccount)
if !ok {
// ignore non EthAccounts
+4 -5
View File
@@ -3,7 +3,6 @@ package keeper_test
import (
"math/big"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
@@ -28,7 +27,7 @@ func (suite *KeeperTestSuite) TestBalanceInvariant() {
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
err := acc.SetCoins(sdk.NewCoins(ethermint.NewPhotonCoinInt64(1)))
suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), ethermint.NewPhotonCoinInt64(1))
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
@@ -41,7 +40,7 @@ func (suite *KeeperTestSuite) TestBalanceInvariant() {
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
err := acc.SetCoins(sdk.NewCoins(ethermint.NewPhotonCoinInt64(1)))
suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), ethermint.NewPhotonCoinInt64(1))
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
@@ -53,7 +52,7 @@ func (suite *KeeperTestSuite) TestBalanceInvariant() {
"invalid account type",
func() {
acc := authtypes.NewBaseAccountWithAddress(address.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, &acc)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
},
false,
},
@@ -116,7 +115,7 @@ func (suite *KeeperTestSuite) TestNonceInvariant() {
"invalid account type",
func() {
acc := authtypes.NewBaseAccountWithAddress(address.Bytes())
suite.app.AccountKeeper.SetAccount(suite.ctx, &acc)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
},
false,
},
+12 -38
View File
@@ -1,7 +1,6 @@
package keeper
import (
"encoding/binary"
"fmt"
"math/big"
@@ -10,7 +9,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/cosmos/ethermint/x/evm/types"
@@ -21,8 +20,8 @@ import (
// Keeper wraps the CommitStateDB, allowing us to pass in SDK context while adhering
// to the StateDB interface.
type Keeper struct {
// Amino codec
cdc *codec.Codec
// Protobuf codec
cdc codec.BinaryMarshaler
// Store key required for the EVM Prefix KVStore. It is required by:
// - storing Account's Storage State
// - storing Account's Code
@@ -32,6 +31,7 @@ type Keeper struct {
storeKey sdk.StoreKey
// Account Keeper for fetching accounts
accountKeeper types.AccountKeeper
bankKeeper types.BankKeeper
// Ethermint concrete implementation on the EVM StateDB interface
CommitStateDB *types.CommitStateDB
// Transaction counter in a block. Used on StateSB's Prepare function.
@@ -43,7 +43,8 @@ type Keeper struct {
// NewKeeper generates new evm module keeper
func NewKeeper(
cdc *codec.Codec, storeKey sdk.StoreKey, paramSpace params.Subspace, ak types.AccountKeeper,
cdc codec.BinaryMarshaler, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace,
ak types.AccountKeeper, bankKeeper types.BankKeeper,
) *Keeper {
// set KeyTable if it has not already been set
if !paramSpace.HasKeyTable() {
@@ -53,9 +54,10 @@ func NewKeeper(
// NOTE: we pass in the parameter space to the CommitStateDB in order to use custom denominations for the EVM operations
return &Keeper{
cdc: cdc,
storeKey: storeKey,
accountKeeper: ak,
CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, paramSpace, ak),
bankKeeper: bankKeeper,
storeKey: storeKey,
CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, paramSpace, ak, bankKeeper),
TxCount: 0,
Bloom: big.NewInt(0),
}
@@ -66,31 +68,6 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
}
// ----------------------------------------------------------------------------
// Block hash mapping functions
// Required by Web3 API.
// TODO: remove once tendermint support block queries by hash.
// ----------------------------------------------------------------------------
// GetBlockHash gets block height from block consensus hash
func (k Keeper) GetBlockHash(ctx sdk.Context, hash []byte) (int64, bool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixBlockHash)
bz := store.Get(hash)
if len(bz) == 0 {
return 0, false
}
height := binary.BigEndian.Uint64(bz)
return int64(height), true
}
// SetBlockHash sets the mapping from block consensus hash to block height
func (k Keeper) SetBlockHash(ctx sdk.Context, hash []byte, height int64) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixBlockHash)
bz := sdk.Uint64ToBigEndian(uint64(height))
store.Set(hash, bz)
}
// ----------------------------------------------------------------------------
// Epoch Height -> hash mapping functions
// Required by EVM context's GetHashFunc
@@ -137,12 +114,10 @@ func (k Keeper) GetAllTxLogs(ctx sdk.Context) []types.TransactionLogs {
txsLogs := []types.TransactionLogs{}
for ; iterator.Valid(); iterator.Next() {
hash := common.BytesToHash(iterator.Key())
var logs []*ethtypes.Log
k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &logs)
var txLog types.TransactionLogs
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &txLog)
// add a new entry
txLog := types.NewTransactionLogs(hash, logs)
txsLogs = append(txsLogs, txLog)
}
return txsLogs
@@ -166,7 +141,6 @@ func (k Keeper) GetAccountStorage(ctx sdk.Context, address common.Address) (type
// GetChainConfig gets block height from block consensus hash
func (k Keeper) GetChainConfig(ctx sdk.Context) (types.ChainConfig, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyPrefixChainConfig)
if len(bz) == 0 {
return types.ChainConfig{}, false
@@ -180,6 +154,6 @@ func (k Keeper) GetChainConfig(ctx sdk.Context) (types.ChainConfig, bool) {
// SetChainConfig sets the mapping from block consensus hash to block height
func (k Keeper) SetChainConfig(ctx sdk.Context, config types.ChainConfig) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryBare(config)
bz := k.cdc.MustMarshalBinaryBare(&config)
store.Set(types.KeyPrefixChainConfig, bz)
}
+22 -28
View File
@@ -7,19 +7,19 @@ import (
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/ethermint/app"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/keeper"
"github.com/cosmos/ethermint/x/evm/types"
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
const addrHex = "0x756F45E3FA69347A9A973A725E3C98bC4db0b4c1"
@@ -32,27 +32,31 @@ var (
type KeeperTestSuite struct {
suite.Suite
ctx sdk.Context
querier sdk.Querier
app *app.EthermintApp
address ethcmn.Address
ctx sdk.Context
app *app.EthermintApp
queryClient types.QueryClient
address ethcmn.Address
}
func (suite *KeeperTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()})
suite.querier = keeper.NewQuerier(*suite.app.EvmKeeper)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()})
suite.address = ethcmn.HexToAddress(addrHex)
balance := sdk.NewCoins(ethermint.NewPhotonCoin(sdk.ZeroInt()))
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.app.EvmKeeper)
suite.queryClient = types.NewQueryClient(queryHelper)
balance := ethermint.NewPhotonCoin(sdk.ZeroInt())
acc := &ethermint.EthAccount{
BaseAccount: auth.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), balance, nil, 0, 0),
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0),
CodeHash: ethcrypto.Keccak256(nil),
}
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), balance)
}
func TestKeeperTestSuite(t *testing.T) {
@@ -65,11 +69,13 @@ func (suite *KeeperTestSuite) TestTransactionLogs() {
Address: suite.address,
Data: []byte("log"),
BlockNumber: 10,
Topics: []ethcmn.Hash{},
}
log2 := &ethtypes.Log{
Address: suite.address,
Data: []byte("log2"),
BlockNumber: 11,
Topics: []ethcmn.Hash{},
}
expLogs := []*ethtypes.Log{log}
@@ -84,6 +90,7 @@ func (suite *KeeperTestSuite) TestTransactionLogs() {
// add another log under the zero hash
suite.app.EvmKeeper.AddLog(suite.ctx, log2)
log2.Index = 0
logs = suite.app.EvmKeeper.AllLogs(suite.ctx)
suite.Require().Equal(expLogs, logs)
@@ -92,17 +99,19 @@ func (suite *KeeperTestSuite) TestTransactionLogs() {
Address: suite.address,
Data: []byte("log3"),
BlockNumber: 10,
Topics: []ethcmn.Hash{},
}
suite.app.EvmKeeper.AddLog(suite.ctx, log3)
log3.Index = 0
txLogs := suite.app.EvmKeeper.GetAllTxLogs(suite.ctx)
suite.Require().Equal(2, len(txLogs))
suite.Require().Equal(ethcmn.Hash{}.String(), txLogs[0].Hash)
suite.Require().Equal([]*ethtypes.Log{log2, log3}, txLogs[0].Logs)
suite.Require().Equal([]*ethtypes.Log{log2, log3}, txLogs[0].EthLogs())
suite.Require().Equal(ethHash.String(), txLogs[1].Hash)
suite.Require().Equal([]*ethtypes.Log{log}, txLogs[1].Logs)
suite.Require().Equal([]*ethtypes.Log{log}, txLogs[1].EthLogs())
}
func (suite *KeeperTestSuite) TestDBStorage() {
@@ -113,14 +122,6 @@ func (suite *KeeperTestSuite) TestDBStorage() {
suite.app.EvmKeeper.SetState(suite.ctx, suite.address, ethcmn.HexToHash("0x2"), ethcmn.HexToHash("0x3"))
suite.app.EvmKeeper.SetCode(suite.ctx, suite.address, []byte{0x1})
// Test block hash mapping functionality
suite.app.EvmKeeper.SetBlockHash(suite.ctx, hash, 7)
height, found := suite.app.EvmKeeper.GetBlockHash(suite.ctx, hash)
suite.Require().True(found)
suite.Require().Equal(int64(7), height)
suite.app.EvmKeeper.SetBlockHash(suite.ctx, []byte{0x43, 0x32}, 8)
// Test block height mapping functionality
testBloom := ethtypes.BytesToBloom([]byte{0x1, 0x3})
suite.app.EvmKeeper.SetBlockBloom(suite.ctx, 4, testBloom)
@@ -131,13 +132,6 @@ func (suite *KeeperTestSuite) TestDBStorage() {
suite.Require().Equal(suite.app.EvmKeeper.GetState(suite.ctx, suite.address, ethcmn.HexToHash("0x2")), ethcmn.HexToHash("0x3"))
suite.Require().Equal(suite.app.EvmKeeper.GetCode(suite.ctx, suite.address), []byte{0x1})
height, found = suite.app.EvmKeeper.GetBlockHash(suite.ctx, hash)
suite.Require().True(found)
suite.Require().Equal(height, int64(7))
height, found = suite.app.EvmKeeper.GetBlockHash(suite.ctx, []byte{0x43, 0x32})
suite.Require().True(found)
suite.Require().Equal(height, int64(8))
bloom, found := suite.app.EvmKeeper.GetBlockBloom(suite.ctx, 4)
suite.Require().True(found)
suite.Require().Equal(bloom, testBloom)
+40 -14
View File
@@ -1,17 +1,27 @@
package keeper
import (
"github.com/ethereum/go-ethereum/common"
"context"
"github.com/armon/go-metrics"
tmtypes "github.com/tendermint/tendermint/types"
ethcmn "github.com/ethereum/go-ethereum/common"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
)
var _ types.MsgServer = Keeper{}
// EthereumTx implements the Msg/EthereumTx gRPC method.
func (k Keeper) EthereumTx(ctx sdk.Context, msg types.MsgEthereumTx) (*sdk.Result, error) {
func (k Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// parse the chainID from a string to a base-10 integer
chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID())
if err != nil {
@@ -24,14 +34,18 @@ func (k Keeper) EthereumTx(ctx sdk.Context, msg types.MsgEthereumTx) (*sdk.Resul
return nil, err
}
var recipient *common.Address
if msg.Data.Recipient != nil {
addr := common.HexToAddress(msg.Data.Recipient.Address)
recipient = &addr
}
txHash := tmtypes.Tx(ctx.TxBytes()).Hash()
ethHash := common.BytesToHash(txHash)
ethHash := ethcmn.BytesToHash(txHash)
var recipient *ethcmn.Address
labels := []metrics.Label{telemetry.NewLabel("operation", "create")}
if msg.Data.Recipient != nil {
addr := ethcmn.HexToAddress(msg.Data.Recipient.Address)
recipient = &addr
labels = []metrics.Label{telemetry.NewLabel("operation", "call")}
}
st := types.StateTransition{
AccountNonce: msg.Data.AccountNonce,
@@ -52,7 +66,8 @@ func (k Keeper) EthereumTx(ctx sdk.Context, msg types.MsgEthereumTx) (*sdk.Resul
// other nodes, causing a consensus error
if !st.Simulate {
// Prepare db for logs
k.CommitStateDB.Prepare(ethHash, k.TxCount)
blockHash := types.HashFromContext(ctx)
k.Prepare(ctx, ethHash, blockHash, k.TxCount)
k.TxCount++
}
@@ -71,16 +86,28 @@ func (k Keeper) EthereumTx(ctx sdk.Context, msg types.MsgEthereumTx) (*sdk.Resul
k.Bloom.Or(k.Bloom, executionResult.Bloom)
// update transaction logs in KVStore
err = k.SetLogs(ctx, common.BytesToHash(txHash), executionResult.Logs)
err = k.SetLogs(ctx, ethcmn.BytesToHash(txHash), executionResult.Logs)
if err != nil {
panic(err)
}
}
// add metrics for the transaction
defer func() {
if st.Amount.IsInt64() {
telemetry.SetGaugeWithLabels(
[]string{"tx", "msg", "ethereum"},
float32(st.Amount.Int64()),
labels,
)
}
}()
// emit events
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeEthereumTx,
sdk.NewAttribute(sdk.AttributeKeyAmount, msg.Data.Amount.String()),
sdk.NewAttribute(sdk.AttributeKeyAmount, st.Amount.String()),
),
sdk.NewEvent(
sdk.EventTypeMessage,
@@ -98,6 +125,5 @@ func (k Keeper) EthereumTx(ctx sdk.Context, msg types.MsgEthereumTx) (*sdk.Resul
)
}
executionResult.Result.Events = ctx.EventManager().Events()
return executionResult.Result, nil
return executionResult.Response, nil
}
-222
View File
@@ -1,222 +0,0 @@
package keeper
import (
"fmt"
"strconv"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/ethermint/utils"
"github.com/cosmos/ethermint/x/evm/types"
ethcmn "github.com/ethereum/go-ethereum/common"
abci "github.com/tendermint/tendermint/abci/types"
)
// NewQuerier is the module level router for state queries
func NewQuerier(keeper Keeper) sdk.Querier {
return func(ctx sdk.Context, path []string, _ abci.RequestQuery) ([]byte, error) {
if len(path) < 1 {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"Insufficient parameters, at least 1 parameter is required")
}
switch path[0] {
case types.QueryBalance:
return queryBalance(ctx, path, keeper)
case types.QueryBlockNumber:
return queryBlockNumber(ctx, keeper)
case types.QueryStorage:
return queryStorage(ctx, path, keeper)
case types.QueryCode:
return queryCode(ctx, path, keeper)
case types.QueryHashToHeight:
return queryHashToHeight(ctx, path, keeper)
case types.QueryTransactionLogs:
return queryTransactionLogs(ctx, path, keeper)
case types.QueryBloom:
return queryBlockBloom(ctx, path, keeper)
case types.QueryLogs:
return queryLogs(ctx, keeper)
case types.QueryAccount:
return queryAccount(ctx, path, keeper)
default:
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query endpoint")
}
}
}
func queryBalance(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) {
if len(path) < 2 {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"Insufficient parameters, at least 2 parameters is required")
}
addr := ethcmn.HexToAddress(path[1])
balance := keeper.GetBalance(ctx, addr)
balanceStr, err := utils.MarshalBigInt(balance)
if err != nil {
return nil, err
}
res := types.QueryResBalance{Balance: balanceStr}
bz, err := codec.MarshalJSONIndent(keeper.cdc, res)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryBlockNumber(ctx sdk.Context, keeper Keeper) ([]byte, error) {
num := ctx.BlockHeight()
bnRes := types.QueryResBlockNumber{Number: num}
bz, err := codec.MarshalJSONIndent(keeper.cdc, bnRes)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryStorage(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) {
if len(path) < 3 {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"Insufficient parameters, at least 3 parameters is required")
}
addr := ethcmn.HexToAddress(path[1])
key := ethcmn.HexToHash(path[2])
val := keeper.GetState(ctx, addr, key)
res := types.QueryResStorage{Value: val.Bytes()}
bz, err := codec.MarshalJSONIndent(keeper.cdc, res)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryCode(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) {
if len(path) < 2 {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"Insufficient parameters, at least 2 parameters is required")
}
addr := ethcmn.HexToAddress(path[1])
code := keeper.GetCode(ctx, addr)
res := types.QueryResCode{Code: code}
bz, err := codec.MarshalJSONIndent(keeper.cdc, res)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryHashToHeight(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) {
if len(path) < 2 {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"Insufficient parameters, at least 2 parameters is required")
}
blockHash := ethcmn.FromHex(path[1])
blockNumber, found := keeper.GetBlockHash(ctx, blockHash)
if !found {
return []byte{}, fmt.Errorf("block height not found for hash %s", path[1])
}
res := types.QueryResBlockNumber{Number: blockNumber}
bz, err := codec.MarshalJSONIndent(keeper.cdc, res)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryBlockBloom(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) {
if len(path) < 2 {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"Insufficient parameters, at least 2 parameters is required")
}
num, err := strconv.ParseInt(path[1], 10, 64)
if err != nil {
return nil, fmt.Errorf("could not unmarshal block height: %w", err)
}
bloom, found := keeper.GetBlockBloom(ctx.WithBlockHeight(num), num)
if !found {
return nil, fmt.Errorf("block bloom not found for height %d", num)
}
res := types.QueryBloomFilter{Bloom: bloom}
bz, err := codec.MarshalJSONIndent(keeper.cdc, res)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryTransactionLogs(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) {
if len(path) < 2 {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"Insufficient parameters, at least 2 parameters is required")
}
txHash := ethcmn.HexToHash(path[1])
logs, err := keeper.GetLogs(ctx, txHash)
if err != nil {
return nil, err
}
res := types.QueryETHLogs{Logs: logs}
bz, err := codec.MarshalJSONIndent(keeper.cdc, res)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryLogs(ctx sdk.Context, keeper Keeper) ([]byte, error) {
logs := keeper.AllLogs(ctx)
res := types.QueryETHLogs{Logs: logs}
bz, err := codec.MarshalJSONIndent(keeper.cdc, res)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
func queryAccount(ctx sdk.Context, path []string, keeper Keeper) ([]byte, error) {
if len(path) < 2 {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
"Insufficient parameters, at least 2 parameters is required")
}
addr := ethcmn.HexToAddress(path[1])
so := keeper.GetOrNewStateObject(ctx, addr)
balance, err := utils.MarshalBigInt(so.Balance())
if err != nil {
return nil, err
}
res := types.QueryResAccount{
Balance: balance,
CodeHash: so.CodeHash(),
Nonce: so.Nonce(),
}
bz, err := codec.MarshalJSONIndent(keeper.cdc, res)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return bz, nil
}
-61
View File
@@ -1,61 +0,0 @@
package keeper_test
import (
"math/big"
"github.com/cosmos/ethermint/x/evm/types"
ethtypes "github.com/ethereum/go-ethereum/core/types"
abci "github.com/tendermint/tendermint/abci/types"
)
func (suite *KeeperTestSuite) TestQuerier() {
testCases := []struct {
msg string
path []string
malleate func()
expPass bool
}{
{"balance", []string{types.QueryBalance, addrHex}, func() {
suite.app.EvmKeeper.SetBalance(suite.ctx, suite.address, big.NewInt(5))
}, true},
// {"balance fail", []string{types.QueryBalance, "0x01232"}, func() {}, false},
{"block number", []string{types.QueryBlockNumber, "0x0"}, func() {}, true},
{"storage", []string{types.QueryStorage, "0x0", "0x0"}, func() {}, true},
{"code", []string{types.QueryCode, "0x0"}, func() {}, true},
{"hash to height", []string{types.QueryHashToHeight, hex}, func() {
suite.app.EvmKeeper.SetBlockHash(suite.ctx, hash, 8)
}, true},
{"tx logs", []string{types.QueryTransactionLogs, "0x0"}, func() {}, true},
{"bloom", []string{types.QueryBloom, "4"}, func() {
testBloom := ethtypes.BytesToBloom([]byte{0x1, 0x3})
suite.app.EvmKeeper.SetBlockBloom(suite.ctx, 4, testBloom)
}, true},
{"logs", []string{types.QueryLogs, "0x0"}, func() {}, true},
{"account", []string{types.QueryAccount, "0x0"}, func() {}, true},
{"unknown request", []string{"other"}, func() {}, false},
}
for i, tc := range testCases {
suite.Run("", func() {
//nolint
tc := tc
suite.SetupTest() // reset
//nolint
tc.malleate()
bz, err := suite.querier(suite.ctx, tc.path, abci.RequestQuery{})
//nolint
if tc.expPass {
//nolint
suite.Require().NoError(err, "valid test %d failed: %s", i, tc.msg)
suite.Require().NotZero(len(bz))
} else {
//nolint
suite.Require().Error(err, "invalid test %d passed: %s", i, tc.msg)
}
})
}
}
+8 -7
View File
@@ -20,7 +20,7 @@ func (suite *KeeperTestSuite) TestBloomFilter() {
tHash := ethcmn.BytesToHash([]byte{0x1})
suite.app.EvmKeeper.Prepare(suite.ctx, tHash, 0)
contractAddress := ethcmn.BigToAddress(big.NewInt(1))
log := ethtypes.Log{Address: contractAddress}
log := ethtypes.Log{Address: contractAddress, Topics: []ethcmn.Hash{}}
testCase := []struct {
name string
@@ -196,11 +196,11 @@ func (suite *KeeperTestSuite) TestStateDB_Code() {
func (suite *KeeperTestSuite) TestStateDB_Logs() {
testCase := []struct {
name string
log ethtypes.Log
log *ethtypes.Log
}{
{
"state db log",
ethtypes.Log{
&ethtypes.Log{
Address: suite.address,
Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))},
Data: []byte("data"),
@@ -208,7 +208,7 @@ func (suite *KeeperTestSuite) TestStateDB_Logs() {
TxHash: ethcmn.Hash{},
TxIndex: 1,
BlockHash: ethcmn.Hash{},
Index: 1,
Index: 0,
Removed: false,
},
},
@@ -216,7 +216,7 @@ func (suite *KeeperTestSuite) TestStateDB_Logs() {
for _, tc := range testCase {
hash := ethcmn.BytesToHash([]byte("hash"))
logs := []*ethtypes.Log{&tc.log}
logs := []*ethtypes.Log{tc.log}
err := suite.app.EvmKeeper.SetLogs(suite.ctx, hash, logs)
suite.Require().NoError(err, tc.name)
@@ -229,7 +229,8 @@ func (suite *KeeperTestSuite) TestStateDB_Logs() {
suite.Require().NoError(err, tc.name)
suite.Require().Empty(dbLogs, tc.name)
suite.app.EvmKeeper.AddLog(suite.ctx, &tc.log)
suite.app.EvmKeeper.AddLog(suite.ctx, tc.log)
tc.log.Index = 0 // reset index
suite.Require().Equal(logs, suite.app.EvmKeeper.AllLogs(suite.ctx), tc.name)
//resets state but checking to see if storekey still persists.
@@ -381,7 +382,7 @@ func (suite *KeeperTestSuite) TestSuiteDB_CopyState() {
TxHash: ethcmn.Hash{},
TxIndex: 1,
BlockHash: ethcmn.Hash{},
Index: 1,
Index: 0,
Removed: false,
},
},
+74 -50
View File
@@ -1,15 +1,19 @@
package evm
import (
"context"
"encoding/json"
"fmt"
"github.com/gorilla/mux"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/client/context"
"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"
"github.com/cosmos/cosmos-sdk/types/module"
@@ -18,71 +22,87 @@ import (
"github.com/cosmos/ethermint/x/evm/types"
)
var _ module.AppModuleBasic = AppModuleBasic{}
var _ module.AppModule = AppModule{}
var (
_ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{}
)
// AppModuleBasic struct
// AppModuleBasic defines the basic application module used by the evm module.
type AppModuleBasic struct{}
// Name for app module basic
// Name returns the evm module's name.
func (AppModuleBasic) Name() string {
return types.ModuleName
}
// RegisterCodec registers types for module
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
types.RegisterCodec(cdc)
// RegisterLegacyAminoCodec performs a no-op as the evm module doesn't support amino.
func (AppModuleBasic) RegisterLegacyAminoCodec(_ *codec.LegacyAmino) {
}
// DefaultGenesis is json default structure
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
return types.ModuleCdc.MustMarshalJSON(types.DefaultGenesisState())
// DefaultGenesis returns default genesis state as raw bytes for the evm
// module.
func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage {
return cdc.MustMarshalJSON(types.DefaultGenesisState())
}
// ValidateGenesis is the validation check of the Genesis
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, _ client.TxEncodingConfig, bz json.RawMessage) error {
var genesisState types.GenesisState
err := types.ModuleCdc.UnmarshalJSON(bz, &genesisState)
if err != nil {
return err
if err := cdc.UnmarshalJSON(bz, &genesisState); err != nil {
return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err)
}
return genesisState.Validate()
}
// RegisterRESTRoutes Registers rest routes
func (AppModuleBasic) RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router) {
// RegisterRESTRoutes performs a no-op as the EVM module doesn't expose REST
// endpoints
func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {
}
// GetQueryCmd Gets the root query command of this module
func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
return cli.GetQueryCmd(types.ModuleName, cdc)
// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the evm module.
func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil {
panic(err)
}
}
// GetTxCmd Gets the root tx command of this module
func (AppModuleBasic) GetTxCmd(cdc *codec.Codec) *cobra.Command {
// GetTxCmd returns nil as the evm module doesn't support transactions through the CLI.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return nil
}
//____________________________________________________________________________
// GetQueryCmd returns no root query command for the evm module.
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd()
}
// RegisterInterfaces registers interfaces and implementations of the evm module.
func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) {
types.RegisterInterfaces(registry)
}
// ____________________________________________________________________________
// AppModule implements an application module for the evm module.
type AppModule struct {
AppModuleBasic
keeper *Keeper
keeper *keeper.Keeper
ak types.AccountKeeper
bk types.BankKeeper
}
// NewAppModule creates a new AppModule Object
func NewAppModule(k *Keeper, ak types.AccountKeeper) AppModule {
// NewAppModule creates a new AppModule object
func NewAppModule(k *keeper.Keeper, ak types.AccountKeeper, bk types.BankKeeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
keeper: k,
ak: ak,
bk: bk,
}
}
// Name is module name
// Name returns the evm module's name.
func (AppModule) Name() string {
return types.ModuleName
}
@@ -92,45 +112,49 @@ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
keeper.RegisterInvariants(ir, *am.keeper)
}
// Route specifies path for transactions
func (am AppModule) Route() string {
return types.RouterKey
// RegisterServices registers the evm module Msg and gRPC services.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), am.keeper)
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
}
// NewHandler sets up a new handler for module
func (am AppModule) NewHandler() sdk.Handler {
return NewHandler(am.keeper)
// Route returns the message routing key for the evm module.
func (am AppModule) Route() sdk.Route {
return sdk.NewRoute(types.RouterKey, NewHandler(*am.keeper))
}
// QuerierRoute sets up path for queries
func (am AppModule) QuerierRoute() string {
return types.ModuleName
// QuerierRoute returns the evm module's querier route name.
func (AppModule) QuerierRoute() string { return types.RouterKey }
// LegacyQuerierHandler returns nil as the evm module doesn't expose a legacy
// Querier.
func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
return nil
}
// NewQuerierHandler sets up new querier handler for module
func (am AppModule) NewQuerierHandler() sdk.Querier {
return keeper.NewQuerier(*am.keeper)
}
// BeginBlock function for module at start of each block
// BeginBlock returns the begin block for the evm module.
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
am.keeper.BeginBlock(ctx, req)
}
// EndBlock function for module at end of block
// EndBlock returns the end blocker for the evm module. It returns no validator
// updates.
func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate {
return am.keeper.EndBlock(ctx, req)
}
// InitGenesis instantiates the genesis state
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
// InitGenesis performs genesis initialization for the evm module. It returns
// no validator updates.
func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState types.GenesisState
types.ModuleCdc.MustUnmarshalJSON(data, &genesisState)
return InitGenesis(ctx, *am.keeper, am.ak, genesisState)
cdc.MustUnmarshalJSON(data, &genesisState)
return InitGenesis(ctx, *am.keeper, am.ak, am.bk, genesisState)
}
// ExportGenesis exports the genesis state to be used by daemon
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
// ExportGenesis returns the exported genesis state as raw bytes for the evm
// module.
func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json.RawMessage {
gs := ExportGenesis(ctx, *am.keeper, am.ak)
return types.ModuleCdc.MustMarshalJSON(gs)
return cdc.MustMarshalJSON(gs)
}
+11 -50
View File
@@ -4,8 +4,6 @@ import (
"math/big"
"strings"
"gopkg.in/yaml.v2"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -13,37 +11,6 @@ import (
"github.com/ethereum/go-ethereum/params"
)
// ChainConfig defines the Ethereum ChainConfig parameters using sdk.Int values instead of big.Int.
//
// NOTE 1: Since empty/uninitialized Ints (i.e with a nil big.Int value) are parsed to zero, we need to manually
// specify that negative Int values will be considered as nil. See getBlockValue for reference.
//
// NOTE 2: This type is not a configurable Param since the SDK does not allow for validation against
// a previous stored parameter values or the current block height (retrieved from context). If you
// want to update the config values, use an software upgrade procedure.
type ChainConfig struct {
HomesteadBlock sdk.Int `json:"homestead_block" yaml:"homestead_block"` // Homestead switch block (< 0 no fork, 0 = already homestead)
DAOForkBlock sdk.Int `json:"dao_fork_block" yaml:"dao_fork_block"` // TheDAO hard-fork switch block (< 0 no fork)
DAOForkSupport bool `json:"dao_fork_support" yaml:"dao_fork_support"` // Whether the nodes supports or opposes the DAO hard-fork
// EIP150 implements the Gas price changes (https://github.com/ethereum/EIPs/issues/150)
EIP150Block sdk.Int `json:"eip150_block" yaml:"eip150_block"` // EIP150 HF block (< 0 no fork)
EIP150Hash string `json:"eip150_hash" yaml:"eip150_hash"` // EIP150 HF hash (needed for header only clients as only gas pricing changed)
EIP155Block sdk.Int `json:"eip155_block" yaml:"eip155_block"` // EIP155 HF block
EIP158Block sdk.Int `json:"eip158_block" yaml:"eip158_block"` // EIP158 HF block
ByzantiumBlock sdk.Int `json:"byzantium_block" yaml:"byzantium_block"` // Byzantium switch block (< 0 no fork, 0 = already on byzantium)
ConstantinopleBlock sdk.Int `json:"constantinople_block" yaml:"constantinople_block"` // Constantinople switch block (< 0 no fork, 0 = already activated)
PetersburgBlock sdk.Int `json:"petersburg_block" yaml:"petersburg_block"` // Petersburg switch block (< 0 same as Constantinople)
IstanbulBlock sdk.Int `json:"istanbul_block" yaml:"istanbul_block"` // Istanbul switch block (< 0 no fork, 0 = already on istanbul)
MuirGlacierBlock sdk.Int `json:"muir_glacier_block" yaml:"muir_glacier_block"` // Eip-2384 (bomb delay) switch block (< 0 no fork, 0 = already activated)
YoloV2Block sdk.Int `json:"yoloV2_block" yaml:"yoloV2_block"` // YOLO v1: https://github.com/ethereum/EIPs/pull/2657 (Ephemeral testnet)
EWASMBlock sdk.Int `json:"ewasm_block" yaml:"ewasm_block"` // EWASM switch block (< 0 no fork, 0 = already activated)
}
// EthereumConfig returns an Ethereum ChainConfig for EVM state transitions.
// All the negative or nil values are converted to nil
func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig {
@@ -66,23 +33,7 @@ func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig {
}
}
// IsIstanbul returns whether the Istanbul version is enabled.
func (cc ChainConfig) IsIstanbul() bool {
return getBlockValue(cc.IstanbulBlock) != nil
}
// IsHomestead returns whether the Homestead version is enabled.
func (cc ChainConfig) IsHomestead() bool {
return getBlockValue(cc.HomesteadBlock) != nil
}
// String implements the fmt.Stringer interface
func (cc ChainConfig) String() string {
out, _ := yaml.Marshal(cc)
return string(out)
}
// DefaultChainConfig returns default evm parameters. Th
// DefaultChainConfig returns default evm parameters.
func DefaultChainConfig() ChainConfig {
return ChainConfig{
HomesteadBlock: sdk.ZeroInt(),
@@ -174,3 +125,13 @@ func validateBlock(block sdk.Int) error {
return nil
}
// IsIstanbul returns whether the Istanbul version is enabled.
func (cc ChainConfig) IsIstanbul() bool {
return getBlockValue(cc.IstanbulBlock) != nil
}
// IsHomestead returns whether the Homestead version is enabled.
func (cc ChainConfig) IsHomestead() bool {
return getBlockValue(cc.HomesteadBlock) != nil
}
+3 -16
View File
@@ -226,20 +226,7 @@ func TestChainConfigValidate(t *testing.T) {
}
func TestChainConfig_String(t *testing.T) {
configStr := `homestead_block: "0"
dao_fork_block: "0"
dao_fork_support: true
eip150_block: "0"
eip150_hash: "0x0000000000000000000000000000000000000000000000000000000000000000"
eip155_block: "0"
eip158_block: "0"
byzantium_block: "0"
constantinople_block: "0"
petersburg_block: "0"
istanbul_block: "0"
muir_glacier_block: "0"
yoloV2_block: "-1"
ewasm_block: "-1"
`
require.Equal(t, configStr, DefaultChainConfig().String())
config := DefaultChainConfig()
configStr := `homestead_block:"0" dao_fork_block:"0" dao_fork_support:true eip150_block:"0" eip150_hash:"0x0000000000000000000000000000000000000000000000000000000000000000" eip155_block:"0" eip158_block:"0" byzantium_block:"0" constantinople_block:"0" petersburg_block:"0" istanbul_block:"0" muir_glacier_block:"0" yolo_v2_block:"-1" ewasm_block:"-1" `
require.Equal(t, configStr, config.String())
}
+22 -14
View File
@@ -2,22 +2,30 @@ package types
import (
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/msgservice"
)
// ModuleCdc defines the evm module's codec
var ModuleCdc = codec.New()
// RegisterInterfaces registers the client interfaces to protobuf Any.
func RegisterInterfaces(registry codectypes.InterfaceRegistry) {
registry.RegisterImplementations(
(*sdk.Tx)(nil),
&MsgEthereumTx{},
)
registry.RegisterImplementations(
(*sdk.Msg)(nil),
&MsgEthereumTx{},
)
// RegisterCodec registers all the necessary types and interfaces for the
// evm module
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(MsgEthereumTx{}, "ethermint/MsgEthereumTx", nil)
cdc.RegisterConcrete(MsgEthermint{}, "ethermint/MsgEthermint", nil)
cdc.RegisterConcrete(TxData{}, "ethermint/TxData", nil)
cdc.RegisterConcrete(ChainConfig{}, "ethermint/ChainConfig", nil)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
}
func init() {
RegisterCodec(ModuleCdc)
codec.RegisterCrypto(ModuleCdc)
ModuleCdc.Seal()
}
var (
// ModuleCdc references the global evm module codec. Note, the codec should
// ONLY be used in certain instances of tests and for JSON encoding.
//
// The actual codec used for serialization should be provided to x/evm and
// defined at the application level.
ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry())
)
+11 -2
View File
@@ -16,9 +16,18 @@ var (
// ErrInvalidChainConfig returns an error resulting from an invalid ChainConfig.
ErrInvalidChainConfig = sdkerrors.Register(ModuleName, 4, "invalid chain configuration")
// ErrZeroAddress returns an error resulting from an zero (empty) ethereum Address.
ErrZeroAddress = sdkerrors.Register(ModuleName, 5, "invalid zero address")
// ErrEmptyHash returns an error resulting from an empty ethereum Hash.
ErrEmptyHash = sdkerrors.Register(ModuleName, 6, "empty hash")
// ErrBloomNotFound returns an error if the block bloom cannot be found on the store.
ErrBloomNotFound = sdkerrors.Register(ModuleName, 7, "block bloom not found")
// ErrCreateDisabled returns an error if the EnableCreate parameter is false.
ErrCreateDisabled = sdkerrors.Register(ModuleName, 5, "EVM Create operation is disabled")
ErrCreateDisabled = sdkerrors.Register(ModuleName, 8, "EVM Create operation is disabled")
// ErrCallDisabled returns an error if the EnableCall parameter is false.
ErrCallDisabled = sdkerrors.Register(ModuleName, 6, "EVM Call operation is disabled")
ErrCallDisabled = sdkerrors.Register(ModuleName, 9, "EVM Call operation is disabled")
)
-1
View File
@@ -2,7 +2,6 @@ package types
// Evm module events
const (
EventTypeEthermint = TypeMsgEthermint
EventTypeEthereumTx = TypeMsgEthereumTx
AttributeKeyContractAddress = "contract"
File diff suppressed because it is too large Load Diff
+13 -7
View File
@@ -2,15 +2,21 @@ package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
)
// AccountKeeper defines the expected account keeper interface
type AccountKeeper interface {
NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authexported.Account
GetAllAccounts(ctx sdk.Context) (accounts []authexported.Account)
IterateAccounts(ctx sdk.Context, cb func(account authexported.Account) bool)
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authexported.Account
SetAccount(ctx sdk.Context, account authexported.Account)
RemoveAccount(ctx sdk.Context, account authexported.Account)
NewAccountWithAddress(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
GetAllAccounts(ctx sdk.Context) (accounts []authtypes.AccountI)
IterateAccounts(ctx sdk.Context, cb func(account authtypes.AccountI) bool)
GetAccount(ctx sdk.Context, addr sdk.AccAddress) authtypes.AccountI
SetAccount(ctx sdk.Context, account authtypes.AccountI)
RemoveAccount(ctx sdk.Context, account authtypes.AccountI)
}
// BankKeeper defines the expected interface needed to retrieve account balances.
type BankKeeper interface {
GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
SetBalance(ctx sdk.Context, addr sdk.AccAddress, balance sdk.Coin) error
}
+2 -23
View File
@@ -5,30 +5,9 @@ import (
"fmt"
ethermint "github.com/cosmos/ethermint/types"
ethcmn "github.com/ethereum/go-ethereum/common"
)
type (
// GenesisState defines the evm module genesis state
GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
TxsLogs []TransactionLogs `json:"txs_logs"`
ChainConfig ChainConfig `json:"chain_config"`
Params Params `json:"params"`
}
// GenesisAccount defines an account to be initialized in the genesis state.
// Its main difference between with Geth's GenesisAccount is that it uses a custom
// storage type and that it doesn't contain the private key field.
// NOTE: balance is omitted as it is imported from the auth account balance.
GenesisAccount struct {
Address string `json:"address"`
Code string `json:"code,omitempty"`
Storage Storage `json:"storage,omitempty"`
}
)
// Validate performs a basic validation of a GenesisAccount fields.
func (ga GenesisAccount) Validate() error {
if ethermint.IsZeroAddress(ga.Address) {
@@ -43,8 +22,8 @@ func (ga GenesisAccount) Validate() error {
// DefaultGenesisState sets default evm genesis state with empty accounts and default params and
// chain config values.
func DefaultGenesisState() GenesisState {
return GenesisState{
func DefaultGenesisState() *GenesisState {
return &GenesisState{
Accounts: []GenesisAccount{},
TxsLogs: []TransactionLogs{},
ChainConfig: DefaultChainConfig(),
+811
View File
@@ -0,0 +1,811 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: ethermint/evm/v1alpha1/genesis.proto
package types
import (
fmt "fmt"
_ "github.com/gogo/protobuf/gogoproto"
proto "github.com/gogo/protobuf/proto"
io "io"
math "math"
math_bits "math/bits"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
// GenesisState defines the evm module's genesis state.
type GenesisState struct {
// accounts is an array containing the ethereum genesis accounts.
Accounts []GenesisAccount `protobuf:"bytes,1,rep,name=accounts,proto3" json:"accounts"`
// chain_config defines the Ethereum chain configuration.
ChainConfig ChainConfig `protobuf:"bytes,2,opt,name=chain_config,json=chainConfig,proto3" json:"chain_config" yaml:"chain_config"`
// params defines all the paramaters of the module.
Params Params `protobuf:"bytes,3,opt,name=params,proto3" json:"params"`
TxsLogs []TransactionLogs `protobuf:"bytes,4,rep,name=txs_logs,json=txsLogs,proto3" json:"txs_logs" yaml:"txs_logs"`
}
func (m *GenesisState) Reset() { *m = GenesisState{} }
func (m *GenesisState) String() string { return proto.CompactTextString(m) }
func (*GenesisState) ProtoMessage() {}
func (*GenesisState) Descriptor() ([]byte, []int) {
return fileDescriptor_8205a12b97b89a87, []int{0}
}
func (m *GenesisState) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GenesisState) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GenesisState.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *GenesisState) XXX_Merge(src proto.Message) {
xxx_messageInfo_GenesisState.Merge(m, src)
}
func (m *GenesisState) XXX_Size() int {
return m.Size()
}
func (m *GenesisState) XXX_DiscardUnknown() {
xxx_messageInfo_GenesisState.DiscardUnknown(m)
}
var xxx_messageInfo_GenesisState proto.InternalMessageInfo
func (m *GenesisState) GetAccounts() []GenesisAccount {
if m != nil {
return m.Accounts
}
return nil
}
func (m *GenesisState) GetChainConfig() ChainConfig {
if m != nil {
return m.ChainConfig
}
return ChainConfig{}
}
func (m *GenesisState) GetParams() Params {
if m != nil {
return m.Params
}
return Params{}
}
func (m *GenesisState) GetTxsLogs() []TransactionLogs {
if m != nil {
return m.TxsLogs
}
return nil
}
// GenesisAccount defines an account to be initialized in the genesis state.
// Its main difference between with Geth's GenesisAccount is that it uses a
// custom storage type and that it doesn't contain the private key field.
type GenesisAccount struct {
// address defines an ethereum hex formated address of an account
Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"`
// code defines the hex bytes of the account code.
Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"`
// storage defines the set of state key values for the account.
Storage Storage `protobuf:"bytes,3,rep,name=storage,proto3,castrepeated=Storage" json:"storage"`
}
func (m *GenesisAccount) Reset() { *m = GenesisAccount{} }
func (m *GenesisAccount) String() string { return proto.CompactTextString(m) }
func (*GenesisAccount) ProtoMessage() {}
func (*GenesisAccount) Descriptor() ([]byte, []int) {
return fileDescriptor_8205a12b97b89a87, []int{1}
}
func (m *GenesisAccount) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
}
func (m *GenesisAccount) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
if deterministic {
return xxx_messageInfo_GenesisAccount.Marshal(b, m, deterministic)
} else {
b = b[:cap(b)]
n, err := m.MarshalToSizedBuffer(b)
if err != nil {
return nil, err
}
return b[:n], nil
}
}
func (m *GenesisAccount) XXX_Merge(src proto.Message) {
xxx_messageInfo_GenesisAccount.Merge(m, src)
}
func (m *GenesisAccount) XXX_Size() int {
return m.Size()
}
func (m *GenesisAccount) XXX_DiscardUnknown() {
xxx_messageInfo_GenesisAccount.DiscardUnknown(m)
}
var xxx_messageInfo_GenesisAccount proto.InternalMessageInfo
func (m *GenesisAccount) GetAddress() string {
if m != nil {
return m.Address
}
return ""
}
func (m *GenesisAccount) GetCode() string {
if m != nil {
return m.Code
}
return ""
}
func (m *GenesisAccount) GetStorage() Storage {
if m != nil {
return m.Storage
}
return nil
}
func init() {
proto.RegisterType((*GenesisState)(nil), "ethermint.evm.v1alpha1.GenesisState")
proto.RegisterType((*GenesisAccount)(nil), "ethermint.evm.v1alpha1.GenesisAccount")
}
func init() {
proto.RegisterFile("ethermint/evm/v1alpha1/genesis.proto", fileDescriptor_8205a12b97b89a87)
}
var fileDescriptor_8205a12b97b89a87 = []byte{
// 405 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xb1, 0x8e, 0xda, 0x30,
0x18, 0xc7, 0x13, 0x40, 0x04, 0x0c, 0x2a, 0x92, 0x5b, 0xb5, 0x11, 0x55, 0x03, 0x4a, 0xab, 0xc2,
0x94, 0x08, 0xba, 0x55, 0x5d, 0x08, 0x43, 0x19, 0x3a, 0x54, 0xa1, 0x53, 0x3b, 0x20, 0x63, 0x5c,
0x27, 0x12, 0x89, 0xa3, 0xd8, 0x20, 0x78, 0x83, 0x1b, 0xef, 0x39, 0xee, 0x49, 0x18, 0x19, 0x99,
0xb8, 0x13, 0xbc, 0xc1, 0x3d, 0xc1, 0x29, 0x4e, 0x02, 0x77, 0xd2, 0x65, 0x73, 0xa4, 0xdf, 0xff,
0xe7, 0x7f, 0x3e, 0x7f, 0xe0, 0x0b, 0x11, 0x1e, 0x89, 0x03, 0x3f, 0x14, 0x36, 0x59, 0x07, 0xf6,
0x7a, 0x80, 0x96, 0x91, 0x87, 0x06, 0x36, 0x25, 0x21, 0xe1, 0x3e, 0xb7, 0xa2, 0x98, 0x09, 0x06,
0xdf, 0x5f, 0x28, 0x8b, 0xac, 0x03, 0x2b, 0xa7, 0xda, 0xef, 0x28, 0xa3, 0x4c, 0x22, 0x76, 0x72,
0x4a, 0xe9, 0x76, 0xb7, 0xc0, 0x99, 0x44, 0x25, 0x61, 0x1e, 0x4a, 0xa0, 0xf9, 0x33, 0xbd, 0x61,
0x2a, 0x90, 0x20, 0x70, 0x02, 0x6a, 0x08, 0x63, 0xb6, 0x0a, 0x05, 0xd7, 0xd5, 0x6e, 0xb9, 0xdf,
0x18, 0x7e, 0xb5, 0x5e, 0xbf, 0xd3, 0xca, 0x72, 0xa3, 0x14, 0x77, 0x2a, 0xbb, 0x63, 0x47, 0x71,
0x2f, 0x69, 0x88, 0x41, 0x13, 0x7b, 0xc8, 0x0f, 0x67, 0x98, 0x85, 0xff, 0x7d, 0xaa, 0x97, 0xba,
0x6a, 0xbf, 0x31, 0xfc, 0x5c, 0x64, 0x1b, 0x27, 0xec, 0x58, 0xa2, 0xce, 0xc7, 0x44, 0xf5, 0x78,
0xec, 0xbc, 0xdd, 0xa2, 0x60, 0xf9, 0xdd, 0x7c, 0xae, 0x31, 0xdd, 0x06, 0xbe, 0x92, 0xf0, 0x07,
0xa8, 0x46, 0x28, 0x46, 0x01, 0xd7, 0xcb, 0x52, 0x6f, 0x14, 0xe9, 0x7f, 0x4b, 0x2a, 0x2b, 0x99,
0x65, 0xe0, 0x3f, 0x50, 0x13, 0x1b, 0x3e, 0x5b, 0x32, 0xca, 0xf5, 0x8a, 0xfc, 0xd9, 0x5e, 0x51,
0xfe, 0x4f, 0x8c, 0x42, 0x8e, 0xb0, 0xf0, 0x59, 0xf8, 0x8b, 0x51, 0xee, 0x7c, 0xc8, 0x2a, 0xb6,
0xd2, 0x8a, 0xb9, 0xc6, 0x74, 0x35, 0xb1, 0xe1, 0x09, 0x61, 0xde, 0xa8, 0xe0, 0xcd, 0xcb, 0x11,
0x41, 0x1d, 0x68, 0x68, 0xb1, 0x88, 0x09, 0x4f, 0x66, 0xab, 0xf6, 0xeb, 0x6e, 0xfe, 0x09, 0x21,
0xa8, 0x60, 0xb6, 0x20, 0x72, 0x48, 0x75, 0x57, 0x9e, 0xe1, 0x04, 0x68, 0x5c, 0xb0, 0x18, 0x51,
0xa2, 0x97, 0x65, 0xb9, 0x4f, 0x45, 0xe5, 0xe4, 0xd3, 0x39, 0xad, 0xa4, 0xd2, 0xdd, 0x7d, 0x47,
0x9b, 0xa6, 0x29, 0x37, 0x8f, 0x3b, 0xa3, 0xdd, 0xc9, 0x50, 0xf7, 0x27, 0x43, 0x7d, 0x38, 0x19,
0xea, 0xed, 0xd9, 0x50, 0xf6, 0x67, 0x43, 0x39, 0x9c, 0x0d, 0xe5, 0x6f, 0x8f, 0xfa, 0xc2, 0x5b,
0xcd, 0x2d, 0xcc, 0x02, 0x1b, 0x33, 0x1e, 0x30, 0x6e, 0x5f, 0x77, 0x66, 0x23, 0xb7, 0x46, 0x6c,
0x23, 0xc2, 0xe7, 0x55, 0xb9, 0x2f, 0xdf, 0x9e, 0x02, 0x00, 0x00, 0xff, 0xff, 0xf3, 0x74, 0xbc,
0x46, 0xa7, 0x02, 0x00, 0x00,
}
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GenesisState) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.TxsLogs) > 0 {
for iNdEx := len(m.TxsLogs) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.TxsLogs[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x22
}
}
{
size, err := m.Params.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x1a
{
size, err := m.ChainConfig.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x12
if len(m.Accounts) > 0 {
for iNdEx := len(m.Accounts) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Accounts[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0xa
}
}
return len(dAtA) - i, nil
}
func (m *GenesisAccount) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalToSizedBuffer(dAtA[:size])
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GenesisAccount) MarshalTo(dAtA []byte) (int, error) {
size := m.Size()
return m.MarshalToSizedBuffer(dAtA[:size])
}
func (m *GenesisAccount) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i := len(dAtA)
_ = i
var l int
_ = l
if len(m.Storage) > 0 {
for iNdEx := len(m.Storage) - 1; iNdEx >= 0; iNdEx-- {
{
size, err := m.Storage[iNdEx].MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintGenesis(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x1a
}
}
if len(m.Code) > 0 {
i -= len(m.Code)
copy(dAtA[i:], m.Code)
i = encodeVarintGenesis(dAtA, i, uint64(len(m.Code)))
i--
dAtA[i] = 0x12
}
if len(m.Address) > 0 {
i -= len(m.Address)
copy(dAtA[i:], m.Address)
i = encodeVarintGenesis(dAtA, i, uint64(len(m.Address)))
i--
dAtA[i] = 0xa
}
return len(dAtA) - i, nil
}
func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int {
offset -= sovGenesis(v)
base := offset
for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7
offset++
}
dAtA[offset] = uint8(v)
return base
}
func (m *GenesisState) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
if len(m.Accounts) > 0 {
for _, e := range m.Accounts {
l = e.Size()
n += 1 + l + sovGenesis(uint64(l))
}
}
l = m.ChainConfig.Size()
n += 1 + l + sovGenesis(uint64(l))
l = m.Params.Size()
n += 1 + l + sovGenesis(uint64(l))
if len(m.TxsLogs) > 0 {
for _, e := range m.TxsLogs {
l = e.Size()
n += 1 + l + sovGenesis(uint64(l))
}
}
return n
}
func (m *GenesisAccount) Size() (n int) {
if m == nil {
return 0
}
var l int
_ = l
l = len(m.Address)
if l > 0 {
n += 1 + l + sovGenesis(uint64(l))
}
l = len(m.Code)
if l > 0 {
n += 1 + l + sovGenesis(uint64(l))
}
if len(m.Storage) > 0 {
for _, e := range m.Storage {
l = e.Size()
n += 1 + l + sovGenesis(uint64(l))
}
}
return n
}
func sovGenesis(x uint64) (n int) {
return (math_bits.Len64(x|1) + 6) / 7
}
func sozGenesis(x uint64) (n int) {
return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63))))
}
func (m *GenesisState) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GenesisState: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Accounts", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Accounts = append(m.Accounts, GenesisAccount{})
if err := m.Accounts[len(m.Accounts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field ChainConfig", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.ChainConfig.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Params", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if err := m.Params.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 4:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field TxsLogs", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.TxsLogs = append(m.TxsLogs, TransactionLogs{})
if err := m.TxsLogs[len(m.TxsLogs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GenesisAccount) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GenesisAccount: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GenesisAccount: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Address = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= uint64(b&0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + intStringLen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Code = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
case 3:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Storage", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowGenesis
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthGenesis
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthGenesis
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Storage = append(m.Storage, State{})
if err := m.Storage[len(m.Storage)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipGenesis(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func skipGenesis(dAtA []byte) (n int, err error) {
l := len(dAtA)
iNdEx := 0
depth := 0
for iNdEx < l {
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
wireType := int(wire & 0x7)
switch wireType {
case 0:
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
iNdEx++
if dAtA[iNdEx-1] < 0x80 {
break
}
}
case 1:
iNdEx += 8
case 2:
var length int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return 0, ErrIntOverflowGenesis
}
if iNdEx >= l {
return 0, io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
length |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if length < 0 {
return 0, ErrInvalidLengthGenesis
}
iNdEx += length
case 3:
depth++
case 4:
if depth == 0 {
return 0, ErrUnexpectedEndOfGroupGenesis
}
depth--
case 5:
iNdEx += 4
default:
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
}
if iNdEx < 0 {
return 0, ErrInvalidLengthGenesis
}
if depth == 0 {
return iNdEx, nil
}
}
return 0, io.ErrUnexpectedEOF
}
var (
ErrInvalidLengthGenesis = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowGenesis = fmt.Errorf("proto: integer overflow")
ErrUnexpectedEndOfGroupGenesis = fmt.Errorf("proto: unexpected end of group")
)
+31 -31
View File
@@ -6,7 +6,6 @@ import (
"github.com/stretchr/testify/suite"
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
)
@@ -14,7 +13,7 @@ import (
type GenesisTestSuite struct {
suite.Suite
address ethcmn.Address
address string
hash ethcmn.Hash
code string
}
@@ -23,7 +22,7 @@ func (suite *GenesisTestSuite) SetupTest() {
priv, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
suite.address = ethcmn.BytesToAddress(priv.PubKey().Address().Bytes())
suite.address = ethcmn.BytesToAddress(priv.PubKey().Address().Bytes()).String()
suite.hash = ethcmn.BytesToHash([]byte("hash"))
suite.code = ethcmn.Bytes2Hex([]byte{1, 2, 3})
}
@@ -33,6 +32,7 @@ func TestGenesisTestSuite(t *testing.T) {
}
func (suite *GenesisTestSuite) TestValidateGenesisAccount() {
testCases := []struct {
name string
genesisAccount GenesisAccount
@@ -41,7 +41,7 @@ func (suite *GenesisTestSuite) TestValidateGenesisAccount() {
{
"valid genesis account",
GenesisAccount{
Address: suite.address.String(),
Address: suite.address,
Code: suite.code,
Storage: Storage{
NewState(suite.hash, suite.hash),
@@ -59,7 +59,7 @@ func (suite *GenesisTestSuite) TestValidateGenesisAccount() {
{
"empty code bytes",
GenesisAccount{
Address: suite.address.String(),
Address: suite.address,
Code: "",
},
false,
@@ -80,7 +80,7 @@ func (suite *GenesisTestSuite) TestValidateGenesisAccount() {
func (suite *GenesisTestSuite) TestValidateGenesis() {
testCases := []struct {
name string
genState GenesisState
genState *GenesisState
expPass bool
}{
{
@@ -90,10 +90,10 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
},
{
name: "valid genesis",
genState: GenesisState{
genState: &GenesisState{
Accounts: []GenesisAccount{
{
Address: suite.address.String(),
Address: suite.address,
Code: suite.code,
Storage: Storage{
{Key: suite.hash.String()},
@@ -103,15 +103,15 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
TxsLogs: []TransactionLogs{
{
Hash: suite.hash.String(),
Logs: []*ethtypes.Log{
Logs: []*Log{
{
Address: suite.address,
Topics: []ethcmn.Hash{suite.hash},
Topics: []string{suite.hash.String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: suite.hash,
TxHash: suite.hash.String(),
TxIndex: 1,
BlockHash: suite.hash,
BlockHash: suite.hash.String(),
Index: 1,
Removed: false,
},
@@ -125,12 +125,12 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
},
{
name: "empty genesis",
genState: GenesisState{},
genState: &GenesisState{},
expPass: false,
},
{
name: "invalid genesis",
genState: GenesisState{
genState: &GenesisState{
Accounts: []GenesisAccount{
{
Address: ethcmn.Address{}.String(),
@@ -141,17 +141,17 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
},
{
name: "duplicated genesis account",
genState: GenesisState{
genState: &GenesisState{
Accounts: []GenesisAccount{
{
Address: suite.address.String(),
Address: suite.address,
Code: suite.code,
Storage: Storage{
NewState(suite.hash, suite.hash),
},
},
{
Address: suite.address.String(),
Address: suite.address,
Code: suite.code,
Storage: Storage{
NewState(suite.hash, suite.hash),
@@ -163,10 +163,10 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
},
{
name: "duplicated tx log",
genState: GenesisState{
genState: &GenesisState{
Accounts: []GenesisAccount{
{
Address: suite.address.String(),
Address: suite.address,
Code: suite.code,
Storage: Storage{
{Key: suite.hash.String()},
@@ -176,15 +176,15 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
TxsLogs: []TransactionLogs{
{
Hash: suite.hash.String(),
Logs: []*ethtypes.Log{
Logs: []*Log{
{
Address: suite.address,
Topics: []ethcmn.Hash{suite.hash},
Topics: []string{suite.hash.String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: suite.hash,
TxHash: suite.hash.String(),
TxIndex: 1,
BlockHash: suite.hash,
BlockHash: suite.hash.String(),
Index: 1,
Removed: false,
},
@@ -192,15 +192,15 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
},
{
Hash: suite.hash.String(),
Logs: []*ethtypes.Log{
Logs: []*Log{
{
Address: suite.address,
Topics: []ethcmn.Hash{suite.hash},
Topics: []string{suite.hash.String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: suite.hash,
TxHash: suite.hash.String(),
TxIndex: 1,
BlockHash: suite.hash,
BlockHash: suite.hash.String(),
Index: 1,
Removed: false,
},
@@ -212,10 +212,10 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
},
{
name: "invalid tx log",
genState: GenesisState{
genState: &GenesisState{
Accounts: []GenesisAccount{
{
Address: suite.address.String(),
Address: suite.address,
Code: suite.code,
Storage: Storage{
{Key: suite.hash.String()},
@@ -228,7 +228,7 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
},
{
name: "invalid params",
genState: GenesisState{
genState: &GenesisState{
ChainConfig: DefaultChainConfig(),
Params: Params{},
},
@@ -236,7 +236,7 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
},
{
name: "invalid chain config",
genState: GenesisState{
genState: &GenesisState{
ChainConfig: ChainConfig{},
Params: DefaultParams(),
},
+2 -4
View File
@@ -240,8 +240,7 @@ func (ch suicideChange) revert(s *CommitStateDB) {
so := s.getStateObject(*ch.account)
if so != nil {
so.suicided = ch.prev
evmDenom := s.GetParams().EvmDenom
so.setBalance(evmDenom, ch.prevBalance)
so.setBalance(ch.prevBalance)
}
}
@@ -257,8 +256,7 @@ func (ch touchChange) dirtied() *ethcmn.Address {
}
func (ch balanceChange) revert(s *CommitStateDB) {
evmDenom := s.GetParams().EvmDenom
s.getStateObject(*ch.account).setBalance(evmDenom, ch.prev)
s.getStateObject(*ch.account).setBalance(ch.prev)
}
func (ch balanceChange) dirtied() *ethcmn.Address {
+44 -34
View File
@@ -7,25 +7,42 @@ import (
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
tmlog "github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmdb "github.com/tendermint/tm-db"
sdkcodec "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/params"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
paramkeeper "github.com/cosmos/cosmos-sdk/x/params/keeper"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
ethermintcodec "github.com/cosmos/ethermint/codec"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
ethermint "github.com/cosmos/ethermint/types"
)
func newTestCodec() (codec.BinaryMarshaler, *codec.LegacyAmino) {
interfaceRegistry := codectypes.NewInterfaceRegistry()
cdc := codec.NewProtoCodec(interfaceRegistry)
amino := codec.NewLegacyAmino()
sdk.RegisterLegacyAminoCodec(amino)
ethermintcodec.RegisterInterfaces(interfaceRegistry)
return cdc, amino
}
type JournalTestSuite struct {
suite.Suite
@@ -35,19 +52,6 @@ type JournalTestSuite struct {
stateDB *CommitStateDB
}
func newTestCodec() *sdkcodec.Codec {
cdc := sdkcodec.New()
RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
ethsecp256k1.RegisterCodec(cdc)
sdkcodec.RegisterCrypto(cdc)
auth.RegisterCodec(cdc)
ethermint.RegisterCodec(cdc)
return cdc
}
func (suite *JournalTestSuite) SetupTest() {
suite.setup()
@@ -57,14 +61,14 @@ func (suite *JournalTestSuite) SetupTest() {
suite.address = ethcmn.BytesToAddress(privkey.PubKey().Address().Bytes())
suite.journal = newJournal()
balance := sdk.NewCoins(ethermint.NewPhotonCoin(sdk.NewInt(100)))
balance := ethermint.NewPhotonCoin(sdk.NewInt(100))
acc := &ethermint.EthAccount{
BaseAccount: auth.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), balance, nil, 0, 0),
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0),
CodeHash: ethcrypto.Keccak256(nil),
}
suite.stateDB.accountKeeper.SetAccount(suite.ctx, acc)
// suite.stateDB.bankKeeper.SetBalance(suite.ctx, sdk.AccAddress(suite.address.Bytes()), balance)
suite.stateDB.bankKeeper.SetBalance(suite.ctx, sdk.AccAddress(suite.address.Bytes()), balance)
suite.stateDB.SetLogs(ethcmn.BytesToHash([]byte("txhash")), []*ethtypes.Log{
{
Address: suite.address,
@@ -96,36 +100,41 @@ func (suite *JournalTestSuite) SetupTest() {
// the latter would result in a cycle dependency. We also want to avoid declaring the journal methods public
// to maintain consistency with the Geth implementation.
func (suite *JournalTestSuite) setup() {
authKey := sdk.NewKVStoreKey(auth.StoreKey)
paramsKey := sdk.NewKVStoreKey(params.StoreKey)
paramsTKey := sdk.NewTransientStoreKey(params.TStoreKey)
// bankKey := sdk.NewKVStoreKey(bank.StoreKey)
authKey := sdk.NewKVStoreKey(authtypes.StoreKey)
paramsKey := sdk.NewKVStoreKey(paramtypes.StoreKey)
paramsTKey := sdk.NewTransientStoreKey(paramtypes.TStoreKey)
bankKey := sdk.NewKVStoreKey(banktypes.StoreKey)
storeKey := sdk.NewKVStoreKey(StoreKey)
db := tmdb.NewDB("state", tmdb.GoLevelDBBackend, "temp")
db, err := tmdb.NewDB("state", tmdb.GoLevelDBBackend, "temp")
suite.Require().NoError(err)
defer func() {
os.RemoveAll("temp")
}()
cms := store.NewCommitMultiStore(db)
cms.MountStoreWithDB(authKey, sdk.StoreTypeIAVL, db)
cms.MountStoreWithDB(bankKey, sdk.StoreTypeIAVL, db)
cms.MountStoreWithDB(paramsKey, sdk.StoreTypeIAVL, db)
cms.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db)
cms.MountStoreWithDB(paramsTKey, sdk.StoreTypeTransient, db)
err := cms.LoadLatestVersion()
err = cms.LoadLatestVersion()
suite.Require().NoError(err)
cdc := newTestCodec()
cdc, amino := newTestCodec()
paramsKeeper := params.NewKeeper(cdc, paramsKey, paramsTKey)
paramsKeeper := paramkeeper.NewKeeper(cdc, amino, paramsKey, paramsTKey)
authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace)
evmSubspace := paramsKeeper.Subspace(types.DefaultParamspace).WithKeyTable(ParamKeyTable())
authSubspace := paramsKeeper.Subspace(authtypes.ModuleName)
bankSubspace := paramsKeeper.Subspace(banktypes.ModuleName)
evmSubspace := paramsKeeper.Subspace(ModuleName).WithKeyTable(ParamKeyTable())
ak := auth.NewAccountKeeper(cdc, authKey, authSubspace, ethermint.ProtoAccount)
suite.ctx = sdk.NewContext(cms, abci.Header{ChainID: "ethermint-8"}, false, tmlog.NewNopLogger())
suite.stateDB = NewCommitStateDB(suite.ctx, storeKey, evmSubspace, ak).WithContext(suite.ctx)
ak := authkeeper.NewAccountKeeper(cdc, authKey, authSubspace, ethermint.ProtoAccount, nil)
bk := bankkeeper.NewBaseKeeper(cdc, bankKey, ak, bankSubspace, nil)
suite.ctx = sdk.NewContext(cms, tmproto.Header{ChainID: "ethermint-8"}, false, tmlog.NewNopLogger())
suite.stateDB = NewCommitStateDB(suite.ctx, storeKey, evmSubspace, ak, bk).WithContext(suite.ctx)
suite.stateDB.SetParams(DefaultParams())
}
@@ -149,6 +158,7 @@ func (suite *JournalTestSuite) TestJournal_append_revert() {
resetObjectChange{
prev: &stateObject{
address: suite.address,
balance: sdk.OneInt(),
},
},
},
+13 -7
View File
@@ -21,13 +21,12 @@ const (
// KVStore key prefixes
var (
KeyPrefixBlockHash = []byte{0x01}
KeyPrefixBloom = []byte{0x02}
KeyPrefixLogs = []byte{0x03}
KeyPrefixCode = []byte{0x04}
KeyPrefixStorage = []byte{0x05}
KeyPrefixChainConfig = []byte{0x06}
KeyPrefixHeightHash = []byte{0x07}
KeyPrefixBloom = []byte{0x01}
KeyPrefixLogs = []byte{0x02}
KeyPrefixCode = []byte{0x03}
KeyPrefixStorage = []byte{0x04}
KeyPrefixChainConfig = []byte{0x05}
KeyPrefixHeightHash = []byte{0x06}
)
// HeightHashKey returns the key for the given chain epoch and height.
@@ -48,3 +47,10 @@ func BloomKey(height int64) []byte {
func AddressStoragePrefix(address ethcmn.Address) []byte {
return append(KeyPrefixStorage, address.Bytes()...)
}
// StateKey defines the full key under which an account state is stored.
func StateKey(address ethcmn.Address, key []byte) []byte {
return append(AddressStoragePrefix(address), key...)
}
// TODO: fix Logs key and append block hash
+77 -32
View File
@@ -9,32 +9,25 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
// TransactionLogs define the logs generated from a transaction execution
// with a given hash. It it used for import/export data as transactions are not persisted
// on blockchain state after an upgrade.
type TransactionLogs struct {
Hash string `json:"hash"`
Logs []*ethtypes.Log `json:"logs"`
}
// NewTransactionLogs creates a new NewTransactionLogs instance.
func NewTransactionLogs(hash ethcmn.Hash, logs []*ethtypes.Log) TransactionLogs { // nolint: interfacer
func NewTransactionLogs(hash ethcmn.Hash, logs []*Log) TransactionLogs { // nolint: interfacer
return TransactionLogs{
Hash: hash.String(),
Logs: logs,
}
}
// MarshalLogs encodes an array of logs using amino
func MarshalLogs(logs []*ethtypes.Log) ([]byte, error) {
return ModuleCdc.MarshalBinaryLengthPrefixed(logs)
}
// NewTransactionLogsFromEth creates a new NewTransactionLogs instance using []*ethtypes.Log.
func NewTransactionLogsFromEth(hash ethcmn.Hash, ethlogs []*ethtypes.Log) TransactionLogs { // nolint: interfacer
logs := make([]*Log, len(ethlogs))
for i := range ethlogs {
logs[i] = NewLogFromEth(ethlogs[i])
}
// UnmarshalLogs decodes an amino-encoded byte array into an array of logs
func UnmarshalLogs(in []byte) ([]*ethtypes.Log, error) {
logs := []*ethtypes.Log{}
err := ModuleCdc.UnmarshalBinaryLengthPrefixed(in, &logs)
return logs, err
return TransactionLogs{
Hash: hash.String(),
Logs: logs,
}
}
// Validate performs a basic validation of a GenesisAccount fields.
@@ -44,32 +37,84 @@ func (tx TransactionLogs) Validate() error {
}
for i, log := range tx.Logs {
if err := ValidateLog(log); err != nil {
if log == nil {
return fmt.Errorf("log %d cannot be nil", i)
}
if err := log.Validate(); err != nil {
return fmt.Errorf("invalid log %d: %w", i, err)
}
if log.TxHash.String() != tx.Hash {
return fmt.Errorf("log tx hash mismatch (%s ≠ %s)", log.TxHash.String(), tx.Hash)
if log.TxHash != tx.Hash {
return fmt.Errorf("log tx hash mismatch (%s ≠ %s)", log.TxHash, tx.Hash)
}
}
return nil
}
// ValidateLog performs a basic validation of an ethereum Log fields.
func ValidateLog(log *ethtypes.Log) error {
if log == nil {
return errors.New("log cannot be nil")
// EthLogs returns the Ethereum type Logs from the Transaction Logs.
func (tx TransactionLogs) EthLogs() []*ethtypes.Log {
return LogsToEthereum(tx.Logs)
}
// Validate performs a basic validation of an ethereum Log fields.
func (log *Log) Validate() error {
if ethermint.IsZeroAddress(log.Address) {
return fmt.Errorf("log address cannot be empty %s", log.Address)
}
if ethermint.IsZeroAddress(log.Address.String()) {
return fmt.Errorf("log address cannot be empty %s", log.Address.String())
}
if ethermint.IsEmptyHash(log.BlockHash.String()) {
return fmt.Errorf("block hash cannot be the empty %s", log.BlockHash.String())
if IsEmptyHash(log.BlockHash) {
return fmt.Errorf("block hash cannot be the empty %s", log.BlockHash)
}
if log.BlockNumber == 0 {
return errors.New("block number cannot be zero")
}
if ethermint.IsEmptyHash(log.TxHash.String()) {
return fmt.Errorf("tx hash cannot be the empty %s", log.TxHash.String())
if ethermint.IsEmptyHash(log.TxHash) {
return fmt.Errorf("tx hash cannot be the empty %s", log.TxHash)
}
return nil
}
// ToEthereum returns the Ethereum type Log from a Ethermint-proto compatible Log.
func (log *Log) ToEthereum() *ethtypes.Log {
topics := make([]ethcmn.Hash, len(log.Topics))
for i := range log.Topics {
topics[i] = ethcmn.HexToHash(log.Topics[i])
}
return &ethtypes.Log{
Address: ethcmn.HexToAddress(log.Address),
Topics: topics,
Data: log.Data,
BlockNumber: log.BlockNumber,
TxHash: ethcmn.HexToHash(log.TxHash),
TxIndex: uint(log.TxIndex),
BlockHash: ethcmn.HexToHash(log.BlockHash),
Removed: log.Removed,
}
}
// LogsToEthereum casts the Ethermint Logs to a slice of Ethereum Logs.
func LogsToEthereum(logs []*Log) []*ethtypes.Log {
ethLogs := make([]*ethtypes.Log, len(logs))
for i := range logs {
ethLogs[i] = logs[i].ToEthereum()
}
return ethLogs
}
// NewLogFromEth creates a new Log instance from a Ethereum type Log.
func NewLogFromEth(log *ethtypes.Log) *Log {
topics := make([]string, len(log.Topics))
for i := range log.Topics {
topics[i] = log.Topics[i].String()
}
return &Log{
Address: log.Address.String(),
Topics: topics,
Data: log.Data,
BlockNumber: log.BlockNumber,
TxHash: log.TxHash.String(),
TxIndex: uint64(log.TxIndex),
BlockHash: log.BlockHash.String(),
Removed: log.Removed,
}
}
+25 -26
View File
@@ -2,7 +2,6 @@ package types
import (
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
func (suite *GenesisTestSuite) TestTransactionLogsValidate() {
@@ -15,15 +14,15 @@ func (suite *GenesisTestSuite) TestTransactionLogsValidate() {
"valid log",
TransactionLogs{
Hash: suite.hash.String(),
Logs: []*ethtypes.Log{
Logs: []*Log{
{
Address: suite.address,
Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))},
Topics: []string{suite.hash.String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: suite.hash,
TxHash: suite.hash.String(),
TxIndex: 1,
BlockHash: suite.hash,
BlockHash: suite.hash.String(),
Index: 1,
Removed: false,
},
@@ -42,7 +41,7 @@ func (suite *GenesisTestSuite) TestTransactionLogsValidate() {
"invalid log",
TransactionLogs{
Hash: suite.hash.String(),
Logs: []*ethtypes.Log{nil},
Logs: []*Log{nil},
},
false,
},
@@ -50,15 +49,15 @@ func (suite *GenesisTestSuite) TestTransactionLogsValidate() {
"hash mismatch log",
TransactionLogs{
Hash: suite.hash.String(),
Logs: []*ethtypes.Log{
Logs: []*Log{
{
Address: suite.address,
Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))},
Topics: []string{suite.hash.String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: ethcmn.BytesToHash([]byte("other_hash")),
TxHash: ethcmn.BytesToHash([]byte("other_hash")).String(),
TxIndex: 1,
BlockHash: suite.hash,
BlockHash: suite.hash.String(),
Index: 1,
Removed: false,
},
@@ -82,58 +81,58 @@ func (suite *GenesisTestSuite) TestTransactionLogsValidate() {
func (suite *GenesisTestSuite) TestValidateLog() {
testCases := []struct {
name string
log *ethtypes.Log
log *Log
expPass bool
}{
{
"valid log",
&ethtypes.Log{
&Log{
Address: suite.address,
Topics: []ethcmn.Hash{ethcmn.BytesToHash([]byte("topic"))},
Topics: []string{suite.hash.String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: suite.hash,
TxHash: suite.hash.String(),
TxIndex: 1,
BlockHash: suite.hash,
BlockHash: suite.hash.String(),
Index: 1,
Removed: false,
},
true,
},
{
"nil log", nil, false,
"empty log", &Log{}, false,
},
{
"zero address",
&ethtypes.Log{
Address: ethcmn.Address{},
&Log{
Address: ethcmn.Address{}.String(),
},
false,
},
{
"empty block hash",
&ethtypes.Log{
&Log{
Address: suite.address,
BlockHash: ethcmn.Hash{},
BlockHash: ethcmn.Hash{}.String(),
},
false,
},
{
"zero block number",
&ethtypes.Log{
&Log{
Address: suite.address,
BlockHash: suite.hash,
BlockHash: suite.hash.String(),
BlockNumber: 0,
},
false,
},
{
"empty tx hash",
&ethtypes.Log{
&Log{
Address: suite.address,
BlockHash: suite.hash,
BlockHash: suite.hash.String(),
BlockNumber: 1,
TxHash: ethcmn.Hash{},
TxHash: ethcmn.Hash{}.String(),
},
false,
},
@@ -141,7 +140,7 @@ func (suite *GenesisTestSuite) TestValidateLog() {
for _, tc := range testCases {
tc := tc
err := ValidateLog(tc.log)
err := tc.log.Validate()
if tc.expPass {
suite.Require().NoError(err, tc.name)
} else {
+34 -138
View File
@@ -6,10 +6,8 @@ import (
"fmt"
"io"
"math/big"
"sync/atomic"
"github.com/cosmos/ethermint/types"
"gopkg.in/yaml.v2"
ethermint "github.com/cosmos/ethermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -21,121 +19,23 @@ import (
)
var (
_ sdk.Msg = MsgEthermint{}
_ sdk.Msg = MsgEthereumTx{}
_ sdk.Tx = MsgEthereumTx{}
_ sdk.Msg = &MsgEthereumTx{}
_ sdk.Tx = &MsgEthereumTx{}
)
var big8 = big.NewInt(8)
// message type and route constants
const (
// TypeMsgEthereumTx defines the type string of an Ethereum tranasction
// TypeMsgEthereumTx defines the type string of an Ethereum transaction
TypeMsgEthereumTx = "ethereum"
// TypeMsgEthermint defines the type string of Ethermint message
TypeMsgEthermint = "ethermint"
)
// MsgEthermint implements a cosmos equivalent structure for Ethereum transactions
type MsgEthermint struct {
AccountNonce uint64 `json:"nonce"`
Price sdk.Int `json:"gasPrice"`
GasLimit uint64 `json:"gas"`
Recipient *sdk.AccAddress `json:"to" rlp:"nil"` // nil means contract creation
Amount sdk.Int `json:"value"`
Payload []byte `json:"input"`
// From address (formerly derived from signature)
From sdk.AccAddress `json:"from"`
}
// NewMsgEthermint returns a reference to a new Ethermint transaction
func NewMsgEthermint(
nonce uint64, to *sdk.AccAddress, amount sdk.Int,
gasLimit uint64, gasPrice sdk.Int, payload []byte, from sdk.AccAddress,
) MsgEthermint {
return MsgEthermint{
AccountNonce: nonce,
Price: gasPrice,
GasLimit: gasLimit,
Recipient: to,
Amount: amount,
Payload: payload,
From: from,
}
}
func (msg MsgEthermint) String() string {
return fmt.Sprintf("nonce=%d gasPrice=%d gasLimit=%d recipient=%s amount=%d data=0x%x from=%s",
msg.AccountNonce, msg.Price, msg.GasLimit, msg.Recipient, msg.Amount, msg.Payload, msg.From)
}
// Route should return the name of the module
func (msg MsgEthermint) Route() string { return RouterKey }
// Type returns the action of the message
func (msg MsgEthermint) Type() string { return TypeMsgEthermint }
// GetSignBytes encodes the message for signing
func (msg MsgEthermint) GetSignBytes() []byte {
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg))
}
// ValidateBasic runs stateless checks on the message
func (msg MsgEthermint) ValidateBasic() error {
if msg.Price.IsZero() {
return sdkerrors.Wrapf(types.ErrInvalidValue, "gas price cannot be 0")
}
if msg.Price.Sign() == -1 {
return sdkerrors.Wrapf(types.ErrInvalidValue, "gas price cannot be negative %s", msg.Price)
}
// Amount can be 0
if msg.Amount.Sign() == -1 {
return sdkerrors.Wrapf(types.ErrInvalidValue, "amount cannot be negative %s", msg.Amount)
}
return nil
}
// GetSigners defines whose signature is required
func (msg MsgEthermint) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{msg.From}
}
// To returns the recipient address of the transaction. It returns nil if the
// transaction is a contract creation.
func (msg MsgEthermint) To() *ethcmn.Address {
if msg.Recipient == nil {
return nil
}
addr := ethcmn.BytesToAddress(msg.Recipient.Bytes())
return &addr
}
// MsgEthereumTx encapsulates an Ethereum transaction as an SDK message.
type MsgEthereumTx struct {
Data TxData
// caches
size atomic.Value
from atomic.Value
}
// sigCache is used to cache the derived sender and contains the signer used
// to derive it.
type sigCache struct {
signer ethtypes.Signer
from ethcmn.Address
}
// NewMsgEthereumTx returns a reference to a new Ethereum transaction message.
func NewMsgEthereumTx(
nonce uint64, to *ethcmn.Address, amount *big.Int,
gasLimit uint64, gasPrice *big.Int, payload []byte,
) MsgEthereumTx {
) *MsgEthereumTx {
return newMsgEthereumTx(nonce, to, amount, gasLimit, gasPrice, payload)
}
@@ -143,14 +43,14 @@ func NewMsgEthereumTx(
// message designated for contract creation.
func NewMsgEthereumTxContract(
nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, payload []byte,
) MsgEthereumTx {
) *MsgEthereumTx {
return newMsgEthereumTx(nonce, nil, amount, gasLimit, gasPrice, payload)
}
func newMsgEthereumTx(
nonce uint64, to *ethcmn.Address, amount *big.Int, // nolint: interfacer
gasLimit uint64, gasPrice *big.Int, payload []byte,
) MsgEthereumTx {
) *MsgEthereumTx {
if len(payload) > 0 {
payload = ethcmn.CopyBytes(payload)
}
@@ -160,7 +60,7 @@ func newMsgEthereumTx(
recipient = &Recipient{Address: to.String()}
}
txData := TxData{
txData := &TxData{
AccountNonce: nonce,
Recipient: recipient,
Payload: payload,
@@ -179,12 +79,7 @@ func newMsgEthereumTx(
txData.Price = sdk.NewIntFromBigInt(gasPrice)
}
return MsgEthereumTx{Data: txData}
}
func (msg MsgEthereumTx) String() string {
out, _ := yaml.Marshal(msg.Data)
return string(out)
return &MsgEthereumTx{Data: txData}
}
// Route returns the route value of an MsgEthereumTx.
@@ -197,16 +92,16 @@ func (msg MsgEthereumTx) Type() string { return TypeMsgEthereumTx }
// checks of a Transaction. If returns an error if validation fails.
func (msg MsgEthereumTx) ValidateBasic() error {
if msg.Data.Price.IsZero() {
return sdkerrors.Wrapf(types.ErrInvalidValue, "gas price cannot be 0")
return sdkerrors.Wrapf(ethermint.ErrInvalidValue, "gas price cannot be 0")
}
if msg.Data.Price.IsNegative() {
return sdkerrors.Wrapf(types.ErrInvalidValue, "gas price cannot be negative %s", msg.Data.Price)
return sdkerrors.Wrapf(ethermint.ErrInvalidValue, "gas price cannot be negative %s", msg.Data.Price)
}
// Amount can be 0
if msg.Data.Amount.IsNegative() {
return sdkerrors.Wrapf(types.ErrInvalidValue, "amount cannot be negative %s", msg.Data.Amount)
return sdkerrors.Wrapf(ethermint.ErrInvalidValue, "amount cannot be negative %s", msg.Data.Amount)
}
return nil
@@ -224,7 +119,7 @@ func (msg MsgEthereumTx) To() *ethcmn.Address {
}
// GetMsgs returns a single MsgEthereumTx as an sdk.Msg.
func (msg MsgEthereumTx) GetMsgs() []sdk.Msg {
func (msg *MsgEthereumTx) GetMsgs() []sdk.Msg {
return []sdk.Msg{msg}
}
@@ -233,7 +128,7 @@ func (msg MsgEthereumTx) GetMsgs() []sdk.Msg {
//
// NOTE: This method panics if 'VerifySig' hasn't been called first.
func (msg MsgEthereumTx) GetSigners() []sdk.AccAddress {
sender := msg.From()
sender := msg.GetFrom()
if sender.Empty() {
panic("must use 'VerifySig' with a chain ID to get the signer")
}
@@ -259,7 +154,9 @@ func (msg MsgEthereumTx) RLPSignBytes(chainID *big.Int) ethcmn.Hash {
msg.To(),
msg.Data.Amount.BigInt(),
msg.Data.Payload,
chainID, uint(0), uint(0),
chainID,
uint(0),
uint(0),
})
}
@@ -339,7 +236,7 @@ func (msg *MsgEthereumTx) DecodeRLP(s *rlp.Stream) error {
recipient = &Recipient{Address: data.Recipient.String()}
}
msg.Data = TxData{
msg.Data = &TxData{
AccountNonce: data.AccountNonce,
Price: sdk.NewIntFromBigInt(data.Price),
GasLimit: data.GasLimit,
@@ -352,7 +249,7 @@ func (msg *MsgEthereumTx) DecodeRLP(s *rlp.Stream) error {
Hash: hash,
}
msg.size.Store(ethcmn.StorageSize(rlp.ListSize(size)))
msg.Size_ = float64(ethcmn.StorageSize(rlp.ListSize(size)))
return nil
}
@@ -398,12 +295,12 @@ func (msg *MsgEthereumTx) VerifySig(chainID *big.Int) (ethcmn.Address, error) {
v, r, s := msg.RawSignatureValues()
signer := ethtypes.NewEIP155Signer(chainID)
if sc := msg.from.Load(); sc != nil {
sigCache := sc.(sigCache)
if msg.From != nil {
// If the signer used to derive from in a previous call is not the same as
// used current, invalidate the cache.
if sigCache.signer.Equal(signer) {
return sigCache.from, nil
fromSigner := ethtypes.NewEIP155Signer(new(big.Int).SetBytes(msg.From.Signer.chainId))
if signer.Equal(fromSigner) {
return ethcmn.HexToAddress(msg.From.Address), nil
}
}
@@ -422,7 +319,13 @@ func (msg *MsgEthereumTx) VerifySig(chainID *big.Int) (ethcmn.Address, error) {
return ethcmn.Address{}, err
}
msg.from.Store(sigCache{signer: signer, from: sender})
msg.From = &SigCache{
Signer: &EIP155Signer{
chainId: chainID.Bytes(),
chainIdMul: new(big.Int).Mul(chainID, big.NewInt(2)).Bytes(),
},
Address: sender.String(),
}
return sender, nil
}
@@ -459,21 +362,14 @@ func (msg MsgEthereumTx) RawSignatureValues() (v, r, s *big.Int) {
new(big.Int).SetBytes(msg.Data.S)
}
// From loads the ethereum sender address from the sigcache and returns an
// GetFrom loads the ethereum sender address from the sigcache and returns an
// sdk.AccAddress from its bytes
func (msg *MsgEthereumTx) From() sdk.AccAddress {
sc := msg.from.Load()
if sc == nil {
func (msg *MsgEthereumTx) GetFrom() sdk.AccAddress {
if msg.From == nil {
return nil
}
sigCache := sc.(sigCache)
if len(sigCache.from.Bytes()) == 0 {
return nil
}
return sdk.AccAddress(sigCache.from.Bytes())
return sdk.AccAddress(ethcmn.HexToAddress(msg.From.Address).Bytes())
}
// deriveChainID derives the chain id from the given v parameter
+10 -105
View File
@@ -8,83 +8,22 @@ import (
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/tendermint/tendermint/crypto/secp256k1"
)
func TestMsgEthermint(t *testing.T) {
addr := newSdkAddress()
fromAddr := newSdkAddress()
msg := NewMsgEthermint(0, &addr, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), fromAddr)
require.NotNil(t, msg)
require.Equal(t, msg.Recipient, &addr)
require.Equal(t, msg.Route(), RouterKey)
require.Equal(t, msg.Type(), TypeMsgEthermint)
}
func TestMsgEthermintValidation(t *testing.T) {
testCases := []struct {
nonce uint64
to *sdk.AccAddress
amount sdk.Int
gasLimit uint64
gasPrice sdk.Int
payload []byte
expectPass bool
from sdk.AccAddress
}{
{amount: sdk.NewInt(100), gasPrice: sdk.NewInt(100000), expectPass: true},
{amount: sdk.NewInt(0), gasPrice: sdk.NewInt(100000), expectPass: true},
{amount: sdk.NewInt(-1), gasPrice: sdk.NewInt(100000), expectPass: false},
{amount: sdk.NewInt(100), gasPrice: sdk.NewInt(-1), expectPass: false},
{amount: sdk.NewInt(100), gasPrice: sdk.NewInt(0), expectPass: false},
// GenerateEthAddress generates an Ethereum address.
func GenerateEthAddress() ethcmn.Address {
priv, err := ethsecp256k1.GenerateKey()
if err != nil {
panic(err)
}
for i, tc := range testCases {
msg := NewMsgEthermint(tc.nonce, tc.to, tc.amount, tc.gasLimit, tc.gasPrice, tc.payload, tc.from)
if tc.expectPass {
require.Nil(t, msg.ValidateBasic(), "test: %v", i)
} else {
require.NotNil(t, msg.ValidateBasic(), "test: %v", i)
}
}
}
func TestMsgEthermintEncodingAndDecoding(t *testing.T) {
addr := newSdkAddress()
fromAddr := newSdkAddress()
msg := NewMsgEthermint(0, &addr, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), fromAddr)
raw, err := ModuleCdc.MarshalBinaryBare(msg)
require.NoError(t, err)
var msg2 MsgEthermint
err = ModuleCdc.UnmarshalBinaryBare(raw, &msg2)
require.NoError(t, err)
require.Equal(t, msg.AccountNonce, msg2.AccountNonce)
require.Equal(t, msg.Recipient, msg2.Recipient)
require.Equal(t, msg.Amount, msg2.Amount)
require.Equal(t, msg.GasLimit, msg2.GasLimit)
require.Equal(t, msg.Price, msg2.Price)
require.Equal(t, msg.Payload, msg2.Payload)
require.Equal(t, msg.From, msg2.From)
}
func newSdkAddress() sdk.AccAddress {
tmpKey := secp256k1.GenPrivKey().PubKey()
return sdk.AccAddress(tmpKey.Address().Bytes())
return ethcmn.BytesToAddress(priv.PubKey().Address().Bytes())
}
func TestMsgEthereumTx(t *testing.T) {
@@ -123,10 +62,11 @@ func TestMsgEthereumTxValidation(t *testing.T) {
for i, tc := range testCases {
msg := NewMsgEthereumTx(0, nil, tc.amount, 0, tc.gasPrice, nil)
err := msg.ValidateBasic()
if tc.expectPass {
require.Nil(t, msg.ValidateBasic(), "valid test %d failed: %s", i, tc.msg)
require.NoError(t, err, "valid test %d failed: %s", i, tc.msg)
} else {
require.NotNil(t, msg.ValidateBasic(), "invalid test %d passed: %s", i, tc.msg)
require.Error(t, err, "invalid test %d passed: %s", i, tc.msg)
}
}
}
@@ -188,38 +128,3 @@ func TestMsgEthereumTxSig(t *testing.T) {
require.Error(t, err)
require.Equal(t, ethcmn.Address{}, signer)
}
func TestMarshalAndUnmarshalLogs(t *testing.T) {
var cdc = codec.New()
logs := []*ethtypes.Log{
{
Address: ethcmn.BytesToAddress([]byte{0x11}),
TxHash: ethcmn.HexToHash("0x01"),
// May need to find workaround since Topics is required to unmarshal from JSON
Topics: []ethcmn.Hash{},
Removed: true,
},
{Address: ethcmn.BytesToAddress([]byte{0x01, 0x11}), Topics: []ethcmn.Hash{}},
}
raw, err := codec.MarshalJSONIndent(cdc, logs)
require.NoError(t, err)
var logs2 []*ethtypes.Log
err = cdc.UnmarshalJSON(raw, &logs2)
require.NoError(t, err)
require.Len(t, logs2, 2)
require.Equal(t, logs[0].Address, logs2[0].Address)
require.Equal(t, logs[0].TxHash, logs2[0].TxHash)
require.True(t, logs[0].Removed)
emptyLogs := []*ethtypes.Log{}
raw, err = codec.MarshalJSONIndent(cdc, emptyLogs)
require.NoError(t, err)
err = cdc.UnmarshalJSON(raw, &logs2)
require.NoError(t, err)
}
+11 -27
View File
@@ -3,20 +3,17 @@ package types
import (
"fmt"
"gopkg.in/yaml.v2"
yaml "gopkg.in/yaml.v2"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/ethereum/go-ethereum/core/vm"
ethermint "github.com/cosmos/ethermint/types"
)
const (
// DefaultParamspace for params keeper
DefaultParamspace = ModuleName
)
var _ paramtypes.ParamSet = &Params{}
// Parameter keys
var (
@@ -27,21 +24,8 @@ var (
)
// ParamKeyTable returns the parameter key table.
func ParamKeyTable() params.KeyTable {
return params.NewKeyTable().RegisterParamSet(&Params{})
}
// Params defines the EVM module parameters
type Params struct {
// EVMDenom defines the token denomination used for state transitions on the
// EVM module.
EvmDenom string `json:"evm_denom" yaml:"evm_denom"`
// EnableCreate toggles state transitions that use the vm.Create function
EnableCreate bool `json:"enable_create" yaml:"enable_create"`
// EnableCall toggles state transitions that use the vm.Call function
EnableCall bool `json:"enable_call" yaml:"enable_call"`
// ExtraEIPs defines the additional EIPs for the vm.Config
ExtraEIPs []int64 `json:"extra_eips" yaml:"extra_eips"`
func ParamKeyTable() paramtypes.KeyTable {
return paramtypes.NewKeyTable().RegisterParamSet(&Params{})
}
// NewParams creates a new Params instance
@@ -71,12 +55,12 @@ func (p Params) String() string {
}
// ParamSetPairs returns the parameter set pairs.
func (p *Params) ParamSetPairs() params.ParamSetPairs {
return params.ParamSetPairs{
params.NewParamSetPair(ParamStoreKeyEVMDenom, &p.EvmDenom, validateEVMDenom),
params.NewParamSetPair(ParamStoreKeyEnableCreate, &p.EnableCreate, validateBool),
params.NewParamSetPair(ParamStoreKeyEnableCall, &p.EnableCall, validateBool),
params.NewParamSetPair(ParamStoreKeyExtraEIPs, &p.ExtraEIPs, validateEIPs),
func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs {
return paramtypes.ParamSetPairs{
paramtypes.NewParamSetPair(ParamStoreKeyEVMDenom, &p.EvmDenom, validateEVMDenom),
paramtypes.NewParamSetPair(ParamStoreKeyEnableCreate, &p.EnableCreate, validateBool),
paramtypes.NewParamSetPair(ParamStoreKeyEnableCall, &p.EnableCall, validateBool),
paramtypes.NewParamSetPair(ParamStoreKeyExtraEIPs, &p.ExtraEIPs, validateEIPs),
}
}
-99
View File
@@ -1,99 +0,0 @@
package types
import (
"fmt"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
// Supported endpoints
const (
QueryBalance = "balance"
QueryBlockNumber = "blockNumber"
QueryStorage = "storage"
QueryCode = "code"
QueryNonce = "nonce"
QueryHashToHeight = "hashToHeight"
QueryTransactionLogs = "transactionLogs"
QueryBloom = "bloom"
QueryLogs = "logs"
QueryAccount = "account"
)
// QueryResBalance is response type for balance query
type QueryResBalance struct {
Balance string `json:"balance"`
}
func (q QueryResBalance) String() string {
return q.Balance
}
// QueryResBlockNumber is response type for block number query
type QueryResBlockNumber struct {
Number int64 `json:"blockNumber"`
}
func (q QueryResBlockNumber) String() string {
return fmt.Sprint(q.Number)
}
// QueryResStorage is response type for storage query
type QueryResStorage struct {
Value []byte `json:"value"`
}
func (q QueryResStorage) String() string {
return string(q.Value)
}
// QueryResCode is response type for code query
type QueryResCode struct {
Code []byte
}
func (q QueryResCode) String() string {
return string(q.Code)
}
// QueryResNonce is response type for Nonce query
type QueryResNonce struct {
Nonce uint64 `json:"nonce"`
}
func (q QueryResNonce) String() string {
return fmt.Sprint(q.Nonce)
}
// QueryETHLogs is response type for tx logs query
type QueryETHLogs struct {
Logs []*ethtypes.Log `json:"logs"`
}
func (q QueryETHLogs) String() string {
var logsStr string
logsLen := len(q.Logs)
for i := 0; i < logsLen; i++ {
logsStr = fmt.Sprintf("%s%v\n", logsStr, *q.Logs[i])
}
return logsStr
}
// QueryBloomFilter is response type for tx logs query
type QueryBloomFilter struct {
Bloom ethtypes.Bloom `json:"bloom"`
}
func (q QueryBloomFilter) String() string {
return string(q.Bloom.Bytes())
}
// QueryAccount is response type for querying Ethereum state objects
type QueryResAccount struct {
Balance string `json:"balance"`
CodeHash []byte `json:"codeHash"`
Nonce uint64 `json:"nonce"`
}
type QueryResExportAccount = GenesisAccount
File diff suppressed because it is too large Load Diff
+820
View File
@@ -0,0 +1,820 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: ethermint/evm/v1alpha1/query.proto
/*
Package types is a reverse proxy.
It translates gRPC into RESTful JSON APIs.
*/
package types
import (
"context"
"io"
"net/http"
"github.com/golang/protobuf/descriptor"
"github.com/golang/protobuf/proto"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"github.com/grpc-ecosystem/grpc-gateway/utilities"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog"
"google.golang.org/grpc/status"
)
// Suppress "imported and not used" errors
var _ codes.Code
var _ io.Reader
var _ status.Status
var _ = runtime.String
var _ = utilities.NewDoubleArray
var _ = descriptor.ForMessage
func request_Query_Account_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryAccountRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address")
}
protoReq.Address, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err)
}
msg, err := client.Account(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Account_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryAccountRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address")
}
protoReq.Address, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err)
}
msg, err := server.Account(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_Balance_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryBalanceRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address")
}
protoReq.Address, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err)
}
msg, err := client.Balance(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Balance_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryBalanceRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address")
}
protoReq.Address, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err)
}
msg, err := server.Balance(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_Storage_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryStorageRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address")
}
protoReq.Address, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err)
}
val, ok = pathParams["key"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "key")
}
protoReq.Key, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "key", err)
}
msg, err := client.Storage(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Storage_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryStorageRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address")
}
protoReq.Address, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err)
}
val, ok = pathParams["key"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "key")
}
protoReq.Key, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "key", err)
}
msg, err := server.Storage(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_Code_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryCodeRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address")
}
protoReq.Address, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err)
}
msg, err := client.Code(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Code_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryCodeRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["address"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address")
}
protoReq.Address, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err)
}
msg, err := server.Code(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_TxLogs_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryTxLogsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["hash"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "hash")
}
protoReq.Hash, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "hash", err)
}
msg, err := client.TxLogs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_TxLogs_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryTxLogsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["hash"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "hash")
}
protoReq.Hash, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "hash", err)
}
msg, err := server.TxLogs(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_BlockLogs_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryBlockLogsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["hash"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "hash")
}
protoReq.Hash, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "hash", err)
}
msg, err := client.BlockLogs(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_BlockLogs_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryBlockLogsRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["hash"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "hash")
}
protoReq.Hash, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "hash", err)
}
msg, err := server.BlockLogs(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_BlockBloom_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryBlockBloomRequest
var metadata runtime.ServerMetadata
msg, err := client.BlockBloom(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_BlockBloom_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryBlockBloomRequest
var metadata runtime.ServerMetadata
msg, err := server.BlockBloom(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryParamsRequest
var metadata runtime.ServerMetadata
msg, err := client.Params(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryParamsRequest
var metadata runtime.ServerMetadata
msg, err := server.Params(ctx, &protoReq)
return msg, metadata, err
}
// RegisterQueryHandlerServer registers the http handlers for service Query to "mux".
// UnaryRPC :call QueryServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
// Note that using this registration option will cause many gRPC library features (such as grpc.SendHeader, etc) to stop working. Consider using RegisterQueryHandlerFromEndpoint instead.
func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error {
mux.Handle("GET", pattern_Query_Account_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Account_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Account_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Balance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Balance_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Balance_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Storage_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Storage_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Storage_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Code_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Code_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Code_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_TxLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_TxLogs_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_TxLogs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_BlockLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_BlockLogs_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_BlockLogs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_BlockBloom_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_BlockBloom_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_BlockBloom_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Query_Params_0(rctx, inboundMarshaler, server, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
conn, err := grpc.Dial(endpoint, opts...)
if err != nil {
return err
}
defer func() {
if err != nil {
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
return
}
go func() {
<-ctx.Done()
if cerr := conn.Close(); cerr != nil {
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
}
}()
}()
return RegisterQueryHandler(ctx, mux, conn)
}
// RegisterQueryHandler registers the http handlers for service Query to "mux".
// The handlers forward requests to the grpc endpoint over "conn".
func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn))
}
// RegisterQueryHandlerClient registers the http handlers for service Query
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient".
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient"
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
// "QueryClient" to call the correct interceptors.
func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error {
mux.Handle("GET", pattern_Query_Account_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Account_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Account_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Balance_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Balance_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Balance_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Storage_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Storage_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Storage_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Code_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Code_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Code_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_TxLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_TxLogs_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_TxLogs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_BlockLogs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_BlockLogs_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_BlockLogs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_BlockBloom_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_BlockBloom_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_BlockBloom_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_Params_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Query_Params_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Query_Params_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
var (
pattern_Query_Account_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"ethermint", "evm", "v1alpha1", "account", "address"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_Balance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"ethermint", "evm", "v1alpha1", "balances", "address"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_Storage_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"ethermint", "evm", "v1alpha1", "storage", "address", "key"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_Code_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"ethermint", "evm", "v1alpha1", "codes", "address"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_TxLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"ethermint", "evm", "v1alpha1", "tx_logs", "hash"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_BlockLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"ethermint", "evm", "v1alpha1", "block_logs", "hash"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_BlockBloom_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1alpha1", "block_bloom"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"ethermint", "evm", "v1alpha1", "params"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_Query_Account_0 = runtime.ForwardResponseMessage
forward_Query_Balance_0 = runtime.ForwardResponseMessage
forward_Query_Storage_0 = runtime.ForwardResponseMessage
forward_Query_Code_0 = runtime.ForwardResponseMessage
forward_Query_TxLogs_0 = runtime.ForwardResponseMessage
forward_Query_BlockLogs_0 = runtime.ForwardResponseMessage
forward_Query_BlockBloom_0 = runtime.ForwardResponseMessage
forward_Query_Params_0 = runtime.ForwardResponseMessage
)
+16 -19
View File
@@ -8,7 +8,7 @@ import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
ethermint "github.com/cosmos/ethermint/types"
@@ -65,6 +65,8 @@ type stateObject struct {
dbErr error
stateDB *CommitStateDB
account *ethermint.EthAccount
// balance represents the amount of the EVM denom token that an account holds
balance sdk.Int
keyToOriginStorageIndex map[ethcmn.Hash]int
keyToDirtyStorageIndex map[ethcmn.Hash]int
@@ -80,8 +82,7 @@ type stateObject struct {
deleted bool
}
func newStateObject(db *CommitStateDB, accProto authexported.Account) *stateObject {
// func newStateObject(db *CommitStateDB, accProto authexported.Account, balance sdk.Int) *stateObject {
func newStateObject(db *CommitStateDB, accProto authtypes.AccountI, balance sdk.Int) *stateObject {
ethermintAccount, ok := accProto.(*ethermint.EthAccount)
if !ok {
panic(fmt.Sprintf("invalid account type for state object: %T", accProto))
@@ -95,6 +96,7 @@ func newStateObject(db *CommitStateDB, accProto authexported.Account) *stateObje
return &stateObject{
stateDB: db,
account: ethermintAccount,
balance: balance,
address: ethermintAccount.EthAddress(),
originStorage: Storage{},
dirtyStorage: Storage{},
@@ -176,8 +178,7 @@ func (so *stateObject) AddBalance(amount *big.Int) {
return
}
evmDenom := so.stateDB.GetParams().EvmDenom
newBalance := so.account.GetCoins().AmountOf(evmDenom).Add(amt)
newBalance := so.balance.Add(amt)
so.SetBalance(newBalance.BigInt())
}
@@ -189,26 +190,25 @@ func (so *stateObject) SubBalance(amount *big.Int) {
return
}
evmDenom := so.stateDB.GetParams().EvmDenom
newBalance := so.account.GetCoins().AmountOf(evmDenom).Sub(amt)
newBalance := so.balance.Sub(amt)
so.SetBalance(newBalance.BigInt())
}
// SetBalance sets the state object's balance.
// SetBalance sets the state object's balance. It doesn't perform any validation
// on the amount value.
func (so *stateObject) SetBalance(amount *big.Int) {
amt := sdk.NewIntFromBigInt(amount)
evmDenom := so.stateDB.GetParams().EvmDenom
so.stateDB.journal.append(balanceChange{
account: &so.address,
prev: so.account.GetCoins().AmountOf(evmDenom),
prev: so.balance,
})
so.setBalance(evmDenom, amt)
so.setBalance(amt)
}
func (so *stateObject) setBalance(denom string, amount sdk.Int) {
so.account.SetBalance(denom, amount)
func (so *stateObject) setBalance(amount sdk.Int) {
so.balance = amount
}
// SetNonce sets the state object's nonce (i.e sequence number of the account).
@@ -298,8 +298,7 @@ func (so stateObject) Address() ethcmn.Address {
// Balance returns the state object's current balance.
func (so *stateObject) Balance() *big.Int {
evmDenom := so.stateDB.GetParams().EvmDenom
balance := so.account.Balance(evmDenom).BigInt()
balance := so.balance.BigInt()
if balance == nil {
return zeroBalance
}
@@ -400,7 +399,7 @@ func (so *stateObject) GetCommittedState(_ ethstate.Database, key ethcmn.Hash) e
func (so *stateObject) ReturnGas(gas *big.Int) {}
func (so *stateObject) deepCopy(db *CommitStateDB) *stateObject {
newStateObj := newStateObject(db, so.account)
newStateObj := newStateObject(db, so.account, so.balance)
newStateObj.code = so.code
newStateObj.dirtyStorage = so.dirtyStorage.Copy()
@@ -414,12 +413,10 @@ func (so *stateObject) deepCopy(db *CommitStateDB) *stateObject {
// empty returns whether the account is considered empty.
func (so *stateObject) empty() bool {
evmDenom := so.stateDB.GetParams().EvmDenom
balace := so.account.Balance(evmDenom)
return so.account == nil ||
(so.account != nil &&
so.account.Sequence == 0 &&
(balace.BigInt() == nil || balace.IsZero()) &&
(so.balance.BigInt() == nil || so.balance.IsZero()) &&
bytes.Equal(so.account.CodeHash, emptyCodeHash))
}
+38 -32
View File
@@ -2,9 +2,10 @@ package types
import (
"errors"
"fmt"
"math/big"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
@@ -41,10 +42,10 @@ type GasInfo struct {
// ExecutionResult represents what's returned from a transition
type ExecutionResult struct {
Logs []*ethtypes.Log
Bloom *big.Int
Result *sdk.Result
GasInfo GasInfo
Logs []*ethtypes.Log
Bloom *big.Int
Response *MsgEthereumTxResponse
GasInfo GasInfo
}
// GetHashFn implements vm.GetHashFunc for Ethermint. It handles 3 cases:
@@ -79,7 +80,7 @@ func (st StateTransition) newEVM(
config ChainConfig,
extraEIPs []int64,
) *vm.EVM {
// Create contexts for evm
// Create context for evm
blockCtx := vm.BlockContext{
CanTransfer: core.CanTransfer,
@@ -105,7 +106,6 @@ func (st StateTransition) newEVM(
vmConfig := vm.Config{
ExtraEips: eips,
}
return vm.NewEVM(blockCtx, txCtx, csdb, config.EthereumConfig(st.ChainID), vmConfig)
}
@@ -153,13 +153,12 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
return nil, errors.New("gas price cannot be nil")
}
evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.Int, config, params.ExtraEIPs)
evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.BigInt(), config, params.ExtraEIPs)
var (
ret []byte
leftOverGas uint64
contractAddress common.Address
recipientLog string
senderRef = vm.AccountRef(st.Sender)
)
@@ -176,7 +175,7 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
}
ret, contractAddress, leftOverGas, err = evm.Create(senderRef, st.Payload, gasLimit, st.Amount)
recipientLog = fmt.Sprintf("contract address %s", contractAddress.String())
default:
if !params.EnableCall {
return nil, ErrCallDisabled
@@ -185,7 +184,6 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
// Increment the nonce for the next transaction (just for evm state transition)
csdb.SetNonce(st.Sender, csdb.GetNonce(st.Sender)+1)
ret, leftOverGas, err = evm.Call(senderRef, *st.Recipient, st.Payload, gasLimit, st.Amount)
recipientLog = fmt.Sprintf("recipient address %s", st.Recipient.String())
}
gasConsumed := gasLimit - leftOverGas
@@ -225,34 +223,20 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
}
}
// Encode all necessary data into slice of bytes to return in sdk result
resultData := ResultData{
Bloom: bloomFilter,
Logs: logs,
res := &MsgEthereumTxResponse{
Bloom: bloomFilter.Bytes(),
TxLogs: NewTransactionLogsFromEth(*st.TxHash, logs),
Ret: ret,
TxHash: *st.TxHash,
}
if contractCreation {
resultData.ContractAddress = contractAddress
res.ContractAddress = contractAddress.String()
}
resBz, err := EncodeResultData(resultData)
if err != nil {
return nil, err
}
resultLog := fmt.Sprintf(
"executed EVM state transition; sender address %s; %s", st.Sender.String(), recipientLog,
)
executionResult := &ExecutionResult{
Logs: logs,
Bloom: bloomInt,
Result: &sdk.Result{
Data: resBz,
Log: resultLog,
},
Logs: logs,
Bloom: bloomInt,
Response: res,
GasInfo: GasInfo{
GasConsumed: gasConsumed,
GasLimit: gasLimit,
@@ -268,3 +252,25 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
return executionResult, nil
}
// HashFromContext returns the Ethereum Header hash from the context's Tendermint
// block header.
func HashFromContext(ctx sdk.Context) common.Hash {
// cast the ABCI header to tendermint Header type
protoHeader := ctx.BlockHeader()
tmHeader, err := tmtypes.HeaderFromProto(&protoHeader)
if err != nil {
return common.Hash{}
}
// get the Tendermint block hash from the current header
tmBlockHash := tmHeader.Hash()
// NOTE: if the validator set hash is missing the hash will be returned as nil,
// so we need to check for this case to prevent a panic when calling Bytes()
if tmBlockHash == nil {
return common.Hash{}
}
return common.BytesToHash(tmBlockHash.Bytes())
}
+66 -36
View File
@@ -3,7 +3,9 @@ package types_test
import (
"math/big"
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tendermint/tendermint/proto/tendermint/version"
tmversion "github.com/tendermint/tendermint/version"
sdk "github.com/cosmos/cosmos-sdk/types"
@@ -23,53 +25,60 @@ func (suite *StateDBTestSuite) TestGetHashFn() {
malleate func()
expEmptyHash bool
}{
{
"valid hash, case 1",
1,
func() {
suite.ctx = suite.ctx.WithBlockHeader(
abci.Header{
ChainID: "ethermint-1",
Height: 1,
ValidatorsHash: []byte("val_hash"),
},
)
hash := ethcmn.BytesToHash([]byte("test hash"))
suite.stateDB.SetBlockHash(hash)
},
false,
},
// {
// "valid hash, case 1",
// 1,
// func() {
// suite.ctx = suite.ctx.WithBlockHeader(
// tmproto.Header{
// ChainID: "ethermint-1",
// Height: 1,
// ValidatorsHash: []byte("val_hash"),
// Version: version.Consensus{
// Block: tmversion.BlockProtocol,
// },
// },
// )
// },
// false,
// },
{
"case 1, nil tendermint hash",
1,
func() {},
true,
},
{
"valid hash, case 2",
1,
func() {
suite.ctx = suite.ctx.WithBlockHeader(
abci.Header{
ChainID: "ethermint-1",
Height: 100,
ValidatorsHash: []byte("val_hash"),
},
)
hash := ethcmn.BytesToHash([]byte("test hash"))
suite.stateDB.WithContext(suite.ctx).SetHeightHash(1, hash)
},
false,
},
// {
// "valid hash, case 2",
// 1,
// func() {
// suite.ctx = suite.ctx.WithBlockHeader(
// tmproto.Header{
// ChainID: "ethermint-1",
// Height: 100,
// ValidatorsHash: []byte("val_hash"),
// Version: version.Consensus{
// Block: tmversion.BlockProtocol,
// },
// },
// )
// hash := types.HashFromContext(suite.ctx)
// suite.stateDB.WithContext(suite.ctx).SetHeightHash(1, hash)
// },
// false,
// },
{
"height not found, case 2",
1,
func() {
suite.ctx = suite.ctx.WithBlockHeader(
abci.Header{
tmproto.Header{
ChainID: "ethermint-1",
Height: 100,
ValidatorsHash: []byte("val_hash"),
Version: version.Consensus{
Block: tmversion.BlockProtocol,
},
},
)
},
@@ -80,10 +89,13 @@ func (suite *StateDBTestSuite) TestGetHashFn() {
1000,
func() {
suite.ctx = suite.ctx.WithBlockHeader(
abci.Header{
tmproto.Header{
ChainID: "ethermint-1",
Height: 100,
ValidatorsHash: []byte("val_hash"),
Version: version.Consensus{
Block: tmversion.BlockProtocol,
},
},
)
},
@@ -113,8 +125,8 @@ func (suite *StateDBTestSuite) TestTransitionDb() {
addr := sdk.AccAddress(suite.address.Bytes())
balance := ethermint.NewPhotonCoin(sdk.NewInt(5000))
acc := suite.app.AccountKeeper.GetAccount(suite.ctx, addr)
_ = acc.SetCoins(sdk.NewCoins(balance))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
suite.app.BankKeeper.SetBalance(suite.ctx, addr, balance)
priv, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
@@ -198,6 +210,24 @@ func (suite *StateDBTestSuite) TestTransitionDb() {
},
false,
},
{
"failed to Finalize",
func() {},
types.StateTransition{
AccountNonce: 123,
Price: big.NewInt(10),
GasLimit: 11,
Recipient: &recipient,
Amount: big.NewInt(-5000),
Payload: []byte("data"),
ChainID: big.NewInt(1),
Csdb: suite.stateDB,
TxHash: &ethcmn.Hash{},
Sender: suite.address,
Simulate: false,
},
false,
},
{
"call disabled",
func() {
+52 -49
View File
@@ -8,7 +8,7 @@ import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
ethermint "github.com/cosmos/ethermint/types"
@@ -43,8 +43,9 @@ type CommitStateDB struct {
ctx sdk.Context
storeKey sdk.StoreKey
paramSpace params.Subspace
paramSpace paramtypes.Subspace
accountKeeper AccountKeeper
bankKeeper BankKeeper
// array that hold 'live' objects, which will get modified while processing a
// state transition
@@ -90,13 +91,15 @@ type CommitStateDB struct {
// CONTRACT: Stores used for state must be cache-wrapped as the ordering of the
// key/value space matters in determining the merkle root.
func NewCommitStateDB(
ctx sdk.Context, storeKey sdk.StoreKey, paramSpace params.Subspace, ak AccountKeeper,
ctx sdk.Context, storeKey sdk.StoreKey, paramSpace paramtypes.Subspace,
ak AccountKeeper, bankKeeper BankKeeper,
) *CommitStateDB {
return &CommitStateDB{
ctx: ctx,
storeKey: storeKey,
paramSpace: paramSpace,
accountKeeper: ak,
bankKeeper: bankKeeper,
stateObjects: []stateEntry{},
addressToObjectIndex: make(map[ethcmn.Address]int),
stateObjectsDirty: make(map[ethcmn.Address]struct{}),
@@ -132,49 +135,38 @@ func (csdb *CommitStateDB) SetParams(params Params) {
// SetBalance sets the balance of an account.
func (csdb *CommitStateDB) SetBalance(addr ethcmn.Address, amount *big.Int) {
so := csdb.GetOrNewStateObject(addr)
if so != nil {
so.SetBalance(amount)
}
so.SetBalance(amount)
}
// AddBalance adds amount to the account associated with addr.
func (csdb *CommitStateDB) AddBalance(addr ethcmn.Address, amount *big.Int) {
so := csdb.GetOrNewStateObject(addr)
if so != nil {
so.AddBalance(amount)
}
so.AddBalance(amount)
}
// SubBalance subtracts amount from the account associated with addr.
func (csdb *CommitStateDB) SubBalance(addr ethcmn.Address, amount *big.Int) {
so := csdb.GetOrNewStateObject(addr)
if so != nil {
so.SubBalance(amount)
}
so.SubBalance(amount)
}
// SetNonce sets the nonce (sequence number) of an account.
func (csdb *CommitStateDB) SetNonce(addr ethcmn.Address, nonce uint64) {
so := csdb.GetOrNewStateObject(addr)
if so != nil {
so.SetNonce(nonce)
}
so.SetNonce(nonce)
}
// SetState sets the storage state with a key, value pair for an account.
func (csdb *CommitStateDB) SetState(addr ethcmn.Address, key, value ethcmn.Hash) {
so := csdb.GetOrNewStateObject(addr)
if so != nil {
so.SetState(nil, key, value)
}
so.SetState(nil, key, value)
}
// SetCode sets the code for a given account.
func (csdb *CommitStateDB) SetCode(addr ethcmn.Address, code []byte) {
so := csdb.GetOrNewStateObject(addr)
if so != nil {
so.SetCode(ethcrypto.Keccak256Hash(code), code)
}
so.SetCode(ethcrypto.Keccak256Hash(code), code)
}
// ----------------------------------------------------------------------------
@@ -187,7 +179,9 @@ func (csdb *CommitStateDB) SetCode(addr ethcmn.Address, code []byte) {
// SetLogs sets the logs for a transaction in the KVStore.
func (csdb *CommitStateDB) SetLogs(hash ethcmn.Hash, logs []*ethtypes.Log) error {
store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixLogs)
bz, err := MarshalLogs(logs)
txLogs := NewTransactionLogsFromEth(hash, logs)
bz, err := ModuleCdc.MarshalBinaryBare(&txLogs)
if err != nil {
return err
}
@@ -306,8 +300,16 @@ func (csdb *CommitStateDB) GetHeightHash(height uint64) ethcmn.Hash {
}
// GetParams returns the total set of evm parameters.
// It will check if every param exists in the Subspace's KVStore before querying by the key,
// the default value of that param will be returned if not exist.
func (csdb *CommitStateDB) GetParams() (params Params) {
csdb.paramSpace.GetParamSet(csdb.ctx, &params)
ps := &params
for _, pair := range ps.ParamSetPairs() {
if csdb.paramSpace.Has(csdb.ctx, pair.Key) {
csdb.paramSpace.Get(csdb.ctx, pair.Key, pair.Value)
}
}
return params
}
@@ -410,7 +412,12 @@ func (csdb *CommitStateDB) GetLogs(hash ethcmn.Hash) ([]*ethtypes.Log, error) {
return []*ethtypes.Log{}, nil
}
return UnmarshalLogs(bz)
var txLogs TransactionLogs
if err := ModuleCdc.UnmarshalBinaryBare(bz, &txLogs); err != nil {
return []*ethtypes.Log{}, err
}
return txLogs.EthLogs(), nil
}
// AllLogs returns all the current logs in the state.
@@ -421,9 +428,9 @@ func (csdb *CommitStateDB) AllLogs() []*ethtypes.Log {
allLogs := []*ethtypes.Log{}
for ; iterator.Valid(); iterator.Next() {
var logs []*ethtypes.Log
ModuleCdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &logs)
allLogs = append(allLogs, logs...)
var txLogs TransactionLogs
ModuleCdc.MustUnmarshalBinaryBare(iterator.Value(), &txLogs)
allLogs = append(allLogs, txLogs.EthLogs()...)
}
return allLogs
@@ -572,18 +579,11 @@ func (csdb *CommitStateDB) updateStateObject(so *stateObject) error {
return fmt.Errorf("invalid balance %s", newBalance)
}
coins := so.account.GetCoins()
balance := coins.AmountOf(newBalance.Denom)
if balance.IsZero() || !balance.Equal(newBalance.Amount) {
coins = coins.Add(newBalance)
}
if err := so.account.SetCoins(coins); err != nil {
err := csdb.bankKeeper.SetBalance(csdb.ctx, so.account.GetAddress(), newBalance)
if err != nil {
return err
}
csdb.accountKeeper.SetAccount(csdb.ctx, so.account)
// return csdb.bankKeeper.SetBalance(csdb.ctx, so.account.Address, newBalance)
return nil
}
@@ -703,20 +703,21 @@ func (csdb *CommitStateDB) Reset(_ ethcmn.Hash) error {
// UpdateAccounts updates the nonce and coin balances of accounts
func (csdb *CommitStateDB) UpdateAccounts() {
for _, stateEntry := range csdb.stateObjects {
currAcc := csdb.accountKeeper.GetAccount(csdb.ctx, sdk.AccAddress(stateEntry.address.Bytes()))
ethermintAcc, ok := currAcc.(*ethermint.EthAccount)
address := sdk.AccAddress(stateEntry.address.Bytes())
currAccount := csdb.accountKeeper.GetAccount(csdb.ctx, address)
ethermintAcc, ok := currAccount.(*ethermint.EthAccount)
if !ok {
continue
}
evmDenom := csdb.GetParams().EvmDenom
balance := sdk.Coin{
Denom: evmDenom,
Amount: ethermintAcc.GetCoins().AmountOf(evmDenom),
balance := csdb.bankKeeper.GetBalance(csdb.ctx, address, evmDenom)
if stateEntry.stateObject.Balance() != balance.Amount.BigInt() && balance.IsValid() {
stateEntry.stateObject.balance = balance.Amount
}
if stateEntry.stateObject.Balance() != balance.Amount.BigInt() && balance.IsValid() ||
stateEntry.stateObject.Nonce() != ethermintAcc.GetSequence() {
if stateEntry.stateObject.Nonce() != ethermintAcc.GetSequence() {
stateEntry.stateObject.account = ethermintAcc
}
}
@@ -755,8 +756,7 @@ func (csdb *CommitStateDB) Prepare(thash ethcmn.Hash, txi int) {
func (csdb *CommitStateDB) CreateAccount(addr ethcmn.Address) {
newobj, prevobj := csdb.createObject(addr)
if prevobj != nil {
evmDenom := csdb.GetParams().EvmDenom
newobj.setBalance(evmDenom, sdk.NewIntFromBigInt(prevobj.Balance()))
newobj.setBalance(sdk.NewIntFromBigInt(prevobj.Balance()))
}
}
@@ -780,6 +780,7 @@ func CopyCommitStateDB(from, to *CommitStateDB) {
to.storeKey = from.storeKey
to.paramSpace = from.paramSpace
to.accountKeeper = from.accountKeeper
to.bankKeeper = from.bankKeeper
to.stateObjects = []stateEntry{}
to.addressToObjectIndex = make(map[ethcmn.Address]int)
to.stateObjectsDirty = make(map[ethcmn.Address]struct{})
@@ -866,8 +867,7 @@ func (csdb *CommitStateDB) ForEachStorage(addr ethcmn.Address, cb func(key, valu
return nil
}
// GetOrNewStateObject retrieves a state object or create a new state object if
// nil.
// GetOrNewStateObject retrieves a state object or create a new state object if nil.
func (csdb *CommitStateDB) GetOrNewStateObject(addr ethcmn.Address) StateObject {
so := csdb.getStateObject(addr)
if so == nil || so.deleted {
@@ -884,7 +884,7 @@ func (csdb *CommitStateDB) createObject(addr ethcmn.Address) (newObj, prevObj *s
acc := csdb.accountKeeper.NewAccountWithAddress(csdb.ctx, sdk.AccAddress(addr.Bytes()))
newObj = newStateObject(csdb, acc)
newObj = newStateObject(csdb, acc, sdk.ZeroInt())
newObj.setNonce(0) // sets the object to dirty
if prevObj == nil {
@@ -925,8 +925,11 @@ func (csdb *CommitStateDB) getStateObject(addr ethcmn.Address) (stateObject *sta
return nil
}
evmDenom := csdb.GetParams().EvmDenom
balance := csdb.bankKeeper.GetBalance(csdb.ctx, acc.GetAddress(), evmDenom)
// insert the state object into the live set
so := newStateObject(csdb, acc)
so := newStateObject(csdb, acc, balance.Amount)
csdb.setStateObject(so)
return so
+36 -8
View File
@@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/suite"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
@@ -19,7 +19,7 @@ import (
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
)
type StateDBTestSuite struct {
@@ -40,7 +40,7 @@ func (suite *StateDBTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "ethermint-1"})
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: "ethermint-1"})
suite.stateDB = suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx)
privkey, err := ethsecp256k1.GenerateKey()
@@ -48,13 +48,16 @@ func (suite *StateDBTestSuite) SetupTest() {
suite.address = ethcmn.BytesToAddress(privkey.PubKey().Address().Bytes())
balance := sdk.NewCoins(ethermint.NewPhotonCoin(sdk.ZeroInt()))
balance := ethermint.NewPhotonCoin(sdk.ZeroInt())
acc := &ethermint.EthAccount{
BaseAccount: auth.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), balance, nil, 0, 0),
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0),
CodeHash: ethcrypto.Keccak256(nil),
}
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
err = suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), balance)
suite.Require().NoError(err)
suite.stateObject = suite.stateDB.GetOrNewStateObject(suite.address)
}
@@ -83,7 +86,10 @@ func (suite *StateDBTestSuite) TestBloomFilter() {
tHash := ethcmn.BytesToHash([]byte{0x1})
suite.stateDB.Prepare(tHash, 0)
contractAddress := ethcmn.BigToAddress(big.NewInt(1))
log := ethtypes.Log{Address: contractAddress}
log := ethtypes.Log{
Address: contractAddress,
Topics: []ethcmn.Hash{},
}
testCase := []struct {
name string
@@ -159,6 +165,13 @@ func (suite *StateDBTestSuite) TestStateDB_Balance() {
},
big.NewInt(200),
},
{
"sub more than balance",
func() {
suite.stateDB.SubBalance(suite.address, big.NewInt(300))
},
big.NewInt(-100),
},
}
for _, tc := range testCase {
@@ -271,7 +284,7 @@ func (suite *StateDBTestSuite) TestStateDB_Logs() {
TxHash: ethcmn.Hash{},
TxIndex: 1,
BlockHash: ethcmn.Hash{},
Index: 1,
Index: 0,
Removed: false,
},
},
@@ -293,6 +306,7 @@ func (suite *StateDBTestSuite) TestStateDB_Logs() {
suite.Require().Empty(dbLogs, tc.name)
suite.stateDB.AddLog(&tc.log)
tc.log.Index = 0 // reset index
suite.Require().Equal(logs, suite.stateDB.AllLogs(), tc.name)
//resets state but checking to see if storekey still persists.
@@ -441,7 +455,7 @@ func (suite *StateDBTestSuite) TestSuiteDB_CopyState() {
TxHash: ethcmn.Hash{},
TxIndex: 1,
BlockHash: ethcmn.Hash{},
Index: 1,
Index: 0,
Removed: false,
},
},
@@ -542,6 +556,13 @@ func (suite *StateDBTestSuite) TestCommitStateDB_Commit() {
},
false, true,
},
{
"faled to update state object",
func() {
suite.stateDB.SubBalance(suite.address, big.NewInt(10))
},
false, false,
},
}
for _, tc := range testCase {
@@ -599,6 +620,13 @@ func (suite *StateDBTestSuite) TestCommitStateDB_Finalize() {
},
false, true,
},
{
"faled to update state object",
func() {
suite.stateDB.SubBalance(suite.address, big.NewInt(10))
},
false, false,
},
}
for _, tc := range testCase {
+1 -7
View File
@@ -35,7 +35,7 @@ func (s Storage) Validate() error {
func (s Storage) String() string {
var str string
for _, state := range s {
str += fmt.Sprintf("%s: %s\n", state.Key, state.Value)
str += fmt.Sprintf("%s\n", state.String())
}
return str
@@ -49,12 +49,6 @@ func (s Storage) Copy() Storage {
return cpy
}
// State represents a single Storage key value pair item.
type State struct {
Key string `json:"key"`
Value string `json:"value"`
}
// Validate performs a basic validation of the State fields.
func (s State) Validate() error {
if ethermint.IsEmptyHash(s.Key) {
+2 -1
View File
@@ -80,6 +80,7 @@ func TestStorageCopy(t *testing.T) {
func TestStorageString(t *testing.T) {
storage := Storage{NewState(ethcmn.BytesToHash([]byte("key")), ethcmn.BytesToHash([]byte("value")))}
str := "0x00000000000000000000000000000000000000000000000000000000006b6579: 0x00000000000000000000000000000000000000000000000000000076616c7565\n"
str := `key:"0x00000000000000000000000000000000000000000000000000000000006b6579" value:"0x00000000000000000000000000000000000000000000000000000076616c7565"
`
require.Equal(t, str, storage.String())
}
+2003
View File
File diff suppressed because it is too large Load Diff
-29
View File
@@ -1,29 +0,0 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Recipient is a wrapper of the
type Recipient struct {
Address string
}
// TxData implements the Ethereum transaction data structure. It is used
// solely as intended in Ethereum abiding by the protocol.
type TxData struct {
AccountNonce uint64 `json:"nonce"`
Price sdk.Int `json:"gasPrice"`
GasLimit uint64 `json:"gas"`
Recipient *Recipient `json:"to" rlp:"nil"` // nil means contract creation
Amount sdk.Int `json:"value"`
Payload []byte `json:"input"`
// signature values
V []byte `json:"v"`
R []byte `json:"r"`
S []byte `json:"s"`
// hash is only used when marshaling to JSON
Hash string `json:"hash" rlp:"-"`
}
+22 -76
View File
@@ -1,35 +1,19 @@
package types
import (
"bytes"
"fmt"
"math/big"
"strings"
"github.com/gogo/protobuf/proto"
"github.com/pkg/errors"
"golang.org/x/crypto/sha3"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
)
// GenerateEthAddress generates an Ethereum address.
func GenerateEthAddress() ethcmn.Address {
priv, err := ethsecp256k1.GenerateKey()
if err != nil {
panic(err)
}
return ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
}
// ValidateSigner attempts to validate a signer for a given slice of bytes over
// which a signature and signer is given. An error is returned if address
// derived from the signature and bytes signed does not match the given signer.
@@ -53,73 +37,25 @@ func rlpHash(x interface{}) (hash ethcmn.Hash) {
return hash
}
// ResultData represents the data returned in an sdk.Result
type ResultData struct {
ContractAddress ethcmn.Address `json:"contract_address"`
Bloom ethtypes.Bloom `json:"bloom"`
Logs []*ethtypes.Log `json:"logs"`
Ret []byte `json:"ret"`
TxHash ethcmn.Hash `json:"tx_hash"`
// EncodeTxResponse takes all of the necessary data from the EVM execution
// and returns the data as a byte slice encoded with protobuf.
func EncodeTxResponse(res *MsgEthereumTxResponse) ([]byte, error) {
return proto.Marshal(res)
}
// String implements fmt.Stringer interface.
func (rd ResultData) String() string {
var logsStr string
logsLen := len(rd.Logs)
for i := 0; i < logsLen; i++ {
logsStr = fmt.Sprintf("%s\t\t%v\n ", logsStr, *rd.Logs[i])
}
return strings.TrimSpace(fmt.Sprintf(`ResultData:
ContractAddress: %s
Bloom: %s
Ret: %v
TxHash: %s
Logs:
%s`, rd.ContractAddress.String(), rd.Bloom.Big().String(), rd.Ret, rd.TxHash.String(), logsStr))
}
// EncodeResultData takes all of the necessary data from the EVM execution
// and returns the data as a byte slice encoded with amino
func EncodeResultData(data ResultData) ([]byte, error) {
return ModuleCdc.MarshalBinaryLengthPrefixed(data)
}
// DecodeResultData decodes an amino-encoded byte slice into ResultData
func DecodeResultData(in []byte) (ResultData, error) {
var data ResultData
err := ModuleCdc.UnmarshalBinaryLengthPrefixed(in, &data)
// DecodeTxResponse decodes an protobuf-encoded byte slice into TxResponse
func DecodeTxResponse(data []byte) (MsgEthereumTxResponse, error) {
var txResponse MsgEthereumTxResponse
err := proto.Unmarshal(data, &txResponse)
if err != nil {
return ResultData{}, err
return MsgEthereumTxResponse{}, err
}
return data, nil
return txResponse, nil
}
// ----------------------------------------------------------------------------
// Auxiliary
// TxDecoder returns an sdk.TxDecoder that can decode both auth.StdTx and
// MsgEthereumTx transactions.
func TxDecoder(cdc *codec.Codec) sdk.TxDecoder {
return func(txBytes []byte) (sdk.Tx, error) {
var tx sdk.Tx
if len(txBytes) == 0 {
return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty")
}
// sdk.Tx is an interface. The concrete message types
// are registered by MakeTxCodec
// TODO: switch to UnmarshalBinaryBare on SDK v0.40.0
err := cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error())
}
return tx, nil
}
}
// recoverEthSig recovers a signature according to the Ethereum specification and
// returns the sender or an error.
//
@@ -158,3 +94,13 @@ func recoverEthSig(R, S, Vb *big.Int, sigHash ethcmn.Hash) (ethcmn.Address, erro
return addr, nil
}
// IsEmptyHash returns true if the hash corresponds to an empty ethereum hex hash.
func IsEmptyHash(hash string) bool {
return bytes.Equal(ethcmn.HexToHash(hash).Bytes(), ethcmn.Hash{}.Bytes())
}
// IsZeroAddress returns true if the address corresponds to an empty ethereum hex address.
func IsZeroAddress(address string) bool {
return bytes.Equal(ethcmn.HexToAddress(address).Bytes(), ethcmn.Address{}.Bytes())
}
+15 -11
View File
@@ -11,28 +11,32 @@ import (
)
func TestEvmDataEncoding(t *testing.T) {
addr := ethcmn.HexToAddress("0x5dE8a020088a2D6d0a23c204FFbeD02790466B49")
addr := "0x5dE8a020088a2D6d0a23c204FFbeD02790466B49"
bloom := ethtypes.BytesToBloom([]byte{0x1, 0x3})
ret := []byte{0x5, 0x8}
data := ResultData{
data := &MsgEthereumTxResponse{
ContractAddress: addr,
Bloom: bloom,
Logs: []*ethtypes.Log{{
Data: []byte{1, 2, 3, 4},
BlockNumber: 17,
}},
Bloom: bloom.Bytes(),
TxLogs: TransactionLogs{
Hash: ethcmn.BytesToHash([]byte{1, 2, 3, 4}).String(),
Logs: []*Log{{
Data: []byte{1, 2, 3, 4},
BlockNumber: 17,
}},
},
Ret: ret,
}
enc, err := EncodeResultData(data)
enc, err := EncodeTxResponse(data)
require.NoError(t, err)
res, err := DecodeResultData(enc)
res, err := DecodeTxResponse(enc)
require.NoError(t, err)
require.NotNil(t, res)
require.Equal(t, addr, res.ContractAddress)
require.Equal(t, bloom, res.Bloom)
require.Equal(t, data.Logs, res.Logs)
require.Equal(t, bloom.Bytes(), res.Bloom)
require.Equal(t, data.TxLogs, res.TxLogs)
require.Equal(t, ret, res.Ret)
}