additions

This commit is contained in:
Federico Kunze
2021-04-18 17:54:18 +02:00
parent 5a3d514ba0
commit 614e62fb7e
138 changed files with 11348 additions and 2906 deletions
+95 -1
View File
@@ -1,12 +1,19 @@
package cli
import (
"math/big"
"strings"
rpctypes "github.com/cosmos/ethermint/ethereum/rpc/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
rpctypes "github.com/cosmos/ethermint/rpc/types"
"github.com/InjectiveLabs/sdk-go/ethereum/rpc"
"github.com/InjectiveLabs/sdk-go/wrappers"
"github.com/cosmos/ethermint/x/evm/types"
)
@@ -23,6 +30,8 @@ func GetQueryCmd() *cobra.Command {
cmd.AddCommand(
GetStorageCmd(),
GetCodeCmd(),
GetErc20Balance(),
GetAccount(),
)
return cmd
}
@@ -103,3 +112,88 @@ func GetCodeCmd() *cobra.Command {
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetErc20Balance queries the erc20 balance of an address
func GetErc20Balance() *cobra.Command {
cmd := &cobra.Command{
Use: "erc20balance [contract] [address]",
Short: "Gets erc20 balance of an account",
Long: "Gets erc20 balance of an account.",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
contract := args[0]
address := args[1]
erc20ABI, err := abi.JSON(strings.NewReader(wrappers.ERC20ABI))
if err != nil {
return err
}
input, err := erc20ABI.Pack("balanceOf", common.HexToAddress(address))
if err != nil {
return err
}
req := &types.QueryStaticCallRequest{
Address: contract,
Input: input,
}
res, err := queryClient.StaticCall(rpc.ContextWithHeight(clientCtx.Height), req)
if err != nil {
return err
}
ret := big.NewInt(0)
err = erc20ABI.UnpackIntoInterface(&ret, "balanceOf", res.Data)
if err != nil {
return err
}
return clientCtx.PrintString(ret.String())
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetAccount queries the account by address
func GetAccount() *cobra.Command {
cmd := &cobra.Command{
Use: "account [address]",
Short: "Get an account by address",
Long: "Get an account by address",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
address := args[0]
req := &types.QueryAccountRequest{
Address: address,
}
res, err := queryClient.Account(rpc.ContextWithHeight(clientCtx.Height), req)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
+16
View File
@@ -45,3 +45,19 @@ func formatKeyToHash(key string) string {
return ethkey.Hex()
}
func cosmosAddressFromArg(addr string) (sdk.AccAddress, error) {
if strings.HasPrefix(addr, sdk.GetConfig().GetBech32AccountAddrPrefix()) {
// Check to see if address is Cosmos bech32 formatted
toAddr, err := sdk.AccAddressFromBech32(addr)
if err != nil {
return nil, errors.Wrap(err, "invalid bech32 formatted address")
}
return toAddr, nil
}
// Strip 0x prefix if exists
addr = strings.TrimPrefix(addr, "0x")
return sdk.AccAddressFromHex(addr)
}
+21
View File
@@ -61,3 +61,24 @@ func TestCosmosToEthereumTypes(t *testing.T) {
require.NoError(t, err)
require.Equal(t, hexString, ethDecoded)
}
func TestAddressToCosmosAddress(t *testing.T) {
baseAddr, err := sdk.AccAddressFromHex("6A98D72760f7bbA69d62Ed6F48278451251948E7")
require.NoError(t, err)
// Test cosmos string back to address
cosmosFormatted, err := cosmosAddressFromArg(baseAddr.String())
require.NoError(t, err)
require.Equal(t, baseAddr, cosmosFormatted)
// Test account address from Ethereum address
ethAddr := common.BytesToAddress(baseAddr.Bytes())
ethFormatted, err := cosmosAddressFromArg(ethAddr.Hex())
require.NoError(t, err)
require.Equal(t, baseAddr, ethFormatted)
// Test encoding without the 0x prefix
ethFormatted, err = cosmosAddressFromArg(ethAddr.Hex()[2:])
require.NoError(t, err)
require.Equal(t, baseAddr, ethFormatted)
}
+2 -2
View File
@@ -14,7 +14,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/rest"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
rpctypes "github.com/cosmos/ethermint/rpc/types"
rpctypes "github.com/cosmos/ethermint/ethereum/rpc/types"
"github.com/ethereum/go-ethereum/common"
)
@@ -81,7 +81,7 @@ func getEthTransactionByHash(clientCtx client.Context, hashHex string) ([]byte,
return nil, err
}
blockHash := common.BytesToHash(block.Block.Hash())
blockHash := common.BytesToHash(block.Block.Header.Hash())
ethTx, err := rpctypes.RawTxToEthTx(clientCtx, tx.Tx)
if err != nil {
+1 -3
View File
@@ -5,14 +5,12 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
ethcmn "github.com/ethereum/go-ethereum/common"
abci "github.com/tendermint/tendermint/abci/types"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/keeper"
"github.com/cosmos/ethermint/x/evm/types"
abci "github.com/tendermint/tendermint/abci/types"
)
// InitGenesis initializes genesis state based on exported genesis
+54 -6
View File
File diff suppressed because one or more lines are too long
+46 -53
View File
@@ -2,53 +2,23 @@ package evm
import (
"fmt"
"time"
"runtime/debug"
log "github.com/xlab/suplog"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ethcmn "github.com/ethereum/go-ethereum/common"
"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"
)
// NewHandler returns a handler for Ethermint type messages.
func NewHandler(k keeper.Keeper) sdk.Handler {
defer telemetry.MeasureSince(time.Now(), "evm", "state_transition")
func NewHandler(k *keeper.Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (result *sdk.Result, err error) {
defer Recover(&err)
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
// in CommitStateDB due to insufficient gas.
// The following is a detailed description:
// If the gas is insufficient during the execution of the "handler",
// panic will be thrown from the function "ConsumeGas" and finally
// caught by the function "runTx" from Cosmos. The function "runTx"
// will think that the execution of Msg has failed and the modified
// data in the Store will not take effect.
// StacktracerunTx->runMsgs->handler->...->gaskv.Store.Set->ConsumeGas
// The problem is that when the modified data in the Store does not take
// effect, the data in the modified CommitStateDB is not rolled back,
// they take effect, and dirty data is generated.
// Therefore, the code here specifically deals with this situation.
// See https://github.com/cosmos/ethermint/issues/668 for more information.
defer func() {
if r := recover(); r != nil {
// We first used "k.CommitStateDB = snapshotStateDB" to roll back
// CommitStateDB, but this can only change the CommitStateDB in the
// current Keeper object, but the Keeper object will be destroyed
// soon, it is not a global variable, so the content pointed to by
// the CommitStateDB pointer can be modified to take effect.
types.CopyCommitStateDB(snapshotStateDB, k.CommitStateDB)
panic(r)
}
}()
ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) {
@@ -56,11 +26,8 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
// 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 sdk.WrapServiceResult(ctx, res, err)
} else if result, err = sdk.WrapServiceResult(ctx, res, nil); err != nil {
return nil, err
}
@@ -69,22 +36,48 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
if res.ContractAddress != "" {
recipientLog = fmt.Sprintf("contract address %s", res.ContractAddress)
} else {
recipientLog = fmt.Sprintf("recipient address %s", msg.Data.Recipient)
var recipient string
if to := msg.To(); to != nil {
recipient = to.Hex()
}
recipientLog = fmt.Sprintf("recipient address %s", 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
if res.Reverted {
result.Log = "transaction reverted"
log := fmt.Sprintf(
"reverted EVM state transition; sender address %s; %s", sender.Hex(), recipientLog,
)
k.Logger(ctx).Info(log)
} else {
log := fmt.Sprintf(
"executed EVM state transition; sender address %s; %s", sender.Hex(), recipientLog,
)
result.Log = log
k.Logger(ctx).Info(log)
}
return result, nil
default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg)
err := sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg)
return nil, err
}
}
}
func Recover(err *error) {
if r := recover(); r != nil {
*err = sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r)
if e, ok := r.(error); ok {
log.WithError(e).Errorln("evm msg handler panicked with an error")
log.Debugln(string(debug.Stack()))
} else {
log.Errorln(r)
}
}
}
+13 -40
View File
@@ -33,7 +33,7 @@ type EvmTestSuite struct {
ctx sdk.Context
handler sdk.Handler
app *app.EthermintApp
app *app.InjectiveApp
codec codec.BinaryMarshaler
privKey *ethsecp256k1.PrivKey
@@ -45,8 +45,8 @@ func (suite *EvmTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx)
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.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: "888", Time: time.Now().UTC()})
suite.handler = evm.NewHandler(suite.app.EvmKeeper)
suite.codec = suite.app.AppCodec()
privKey, err := ethsecp256k1.GenerateKey()
@@ -78,7 +78,7 @@ func (suite *EvmTestSuite) TestHandleMsgEthereumTx() {
"passed",
func() {
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)
tx = types.NewMsgEthereumTx(0, &suite.from, big.NewInt(100), 0, big.NewInt(10000), nil)
// parse context chain ID to big.Int
chainID, err := ethermint.ParseChainID(suite.ctx.ChainID())
@@ -176,7 +176,7 @@ func (suite *EvmTestSuite) TestHandlerLogs() {
bytecode := common.FromHex("0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029")
tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode)
err = tx.Sign(big.NewInt(3), priv.ToECDSA())
err = tx.Sign(big.NewInt(888), priv.ToECDSA())
suite.Require().NoError(err)
result, err := suite.handler(suite.ctx, tx)
@@ -195,34 +195,7 @@ func (suite *EvmTestSuite) TestHandlerLogs() {
logs, err := suite.app.EvmKeeper.GetLogs(suite.ctx, ethcmn.BytesToHash(hash))
suite.Require().NoError(err, "failed to get 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)
}
}
}
}
suite.Require().Equal(logs, txResponse.TxLogs.Logs)
}
func (suite *EvmTestSuite) TestQueryTxLogs() {
@@ -235,7 +208,7 @@ func (suite *EvmTestSuite) TestQueryTxLogs() {
// send contract deployment transaction with an event in the constructor
bytecode := common.FromHex("0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029")
tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode)
err = tx.Sign(big.NewInt(3), priv.ToECDSA())
err = tx.Sign(big.NewInt(888), priv.ToECDSA())
suite.Require().NoError(err)
result, err := suite.handler(suite.ctx, tx)
@@ -321,7 +294,7 @@ func (suite *EvmTestSuite) TestDeployAndCallContract() {
bytecode := common.FromHex("0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a36102c4806100dc6000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c010000000000000000000000000000000000000000000000000000000090048063893d20e814610058578063a6f9dae1146100a2575b600080fd5b6100606100e6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100e4600480360360208110156100b857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061010f565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146101d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f43616c6c6572206973206e6f74206f776e65720000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72315820f397f2733a89198bc7fed0764083694c5b828791f39ebcbc9e414bccef14b48064736f6c63430005100032")
tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode)
tx.Sign(big.NewInt(3), priv.ToECDSA())
tx.Sign(big.NewInt(888), priv.ToECDSA())
suite.Require().NoError(err)
result, err := suite.handler(suite.ctx, tx)
@@ -338,7 +311,7 @@ func (suite *EvmTestSuite) TestDeployAndCallContract() {
storeAddr := "0xa6f9dae10000000000000000000000006a82e4a67715c8412a9114fbd2cbaefbc8181424"
bytecode = common.FromHex(storeAddr)
tx = types.NewMsgEthereumTx(2, &receiver, big.NewInt(0), gasLimit, gasPrice, bytecode)
tx.Sign(big.NewInt(3), priv.ToECDSA())
tx.Sign(big.NewInt(888), priv.ToECDSA())
suite.Require().NoError(err)
result, err = suite.handler(suite.ctx, tx)
@@ -350,7 +323,7 @@ func (suite *EvmTestSuite) TestDeployAndCallContract() {
// query - getOwner
bytecode = common.FromHex("0x893d20e8")
tx = types.NewMsgEthereumTx(2, &receiver, big.NewInt(0), gasLimit, gasPrice, bytecode)
tx.Sign(big.NewInt(3), priv.ToECDSA())
tx.Sign(big.NewInt(888), priv.ToECDSA())
suite.Require().NoError(err)
result, err = suite.handler(suite.ctx, tx)
@@ -375,7 +348,7 @@ func (suite *EvmTestSuite) TestSendTransaction() {
// send simple value transfer with gasLimit=21000
tx := types.NewMsgEthereumTx(1, &ethcmn.Address{0x1}, big.NewInt(1), gasLimit, gasPrice, nil)
err = tx.Sign(big.NewInt(3), priv.ToECDSA())
err = tx.Sign(big.NewInt(888), priv.ToECDSA())
suite.Require().NoError(err)
result, err := suite.handler(suite.ctx, tx)
@@ -448,7 +421,7 @@ func (suite *EvmTestSuite) TestOutOfGasWhenDeployContract() {
bytecode := common.FromHex("0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a36102c4806100dc6000396000f3fe608060405234801561001057600080fd5b5060043610610053576000357c010000000000000000000000000000000000000000000000000000000090048063893d20e814610058578063a6f9dae1146100a2575b600080fd5b6100606100e6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100e4600480360360208110156100b857600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061010f565b005b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146101d1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260138152602001807f43616c6c6572206973206e6f74206f776e65720000000000000000000000000081525060200191505060405180910390fd5b8073ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167f342827c97908e5e2f71151c08502a66d44b6f758e3ac2f1de95f02eb95f0a73560405160405180910390a3806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505056fea265627a7a72315820f397f2733a89198bc7fed0764083694c5b828791f39ebcbc9e414bccef14b48064736f6c63430005100032")
tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode)
tx.Sign(big.NewInt(3), priv.ToECDSA())
tx.Sign(big.NewInt(888), priv.ToECDSA())
suite.Require().NoError(err)
snapshotCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB)
@@ -478,7 +451,7 @@ func (suite *EvmTestSuite) TestErrorWhenDeployContract() {
bytecode := common.FromHex("0xa6f9dae10000000000000000000000006a82e4a67715c8412a9114fbd2cbaefbc8181424")
tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode)
tx.Sign(big.NewInt(3), priv.ToECDSA())
tx.Sign(big.NewInt(888), priv.ToECDSA())
suite.Require().NoError(err)
snapshotCommitStateDBJson, err := json.Marshal(suite.app.EvmKeeper.CommitStateDB)
+12 -8
View File
@@ -3,29 +3,29 @@ package keeper
import (
"math/big"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/ethermint/metrics"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
abci "github.com/tendermint/tendermint/abci/types"
)
// BeginBlock sets the block height -> header hash map for the previous block height
// BeginBlock sets the block hash -> block height 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 {
if req.Header.Height < 1 {
return
}
// Gas costs are handled within msg handler so costs should be ignored
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
// Set the hash -> height and height -> hash mapping.
currentHash := req.Hash
height := req.Header.GetHeight()
k.SetBlockHash(ctx, req.Hash, req.Header.Height)
k.SetBlockHeightToHash(ctx, req.Hash, req.Header.Height)
k.SetHeightHash(ctx, uint64(height), common.BytesToHash(hash))
// special setter for csdb
k.SetHeightHash(ctx, uint64(req.Header.Height), common.BytesToHash(req.Hash))
// reset counters that are used on CommitStateDB.Prepare
k.Bloom = big.NewInt(0)
@@ -37,6 +37,10 @@ func (k *Keeper) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
// the store. The EVM end block logic doesn't update the validator set, thus it returns
// an empty slice.
func (k Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
// Gas costs are handled within msg handler so costs should be ignored
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
-32
View File
@@ -1,32 +0,0 @@
package keeper_test
import (
abci "github.com/tendermint/tendermint/abci/types"
)
func (suite *KeeperTestSuite) TestBeginBlock() {
// update the counters
suite.app.EvmKeeper.Bloom.SetInt64(10)
suite.app.EvmKeeper.TxCount = 10
suite.app.EvmKeeper.BeginBlock(suite.ctx, abci.RequestBeginBlock{})
suite.Require().NotZero(suite.app.EvmKeeper.Bloom.Int64())
suite.Require().NotZero(suite.app.EvmKeeper.TxCount)
}
func (suite *KeeperTestSuite) TestEndBlock() {
// update the counters
suite.app.EvmKeeper.Bloom.SetInt64(10)
// set gas limit to 1 to ensure no gas is consumed during the operation
initialConsumed := suite.ctx.GasMeter().GasConsumed()
_ = suite.app.EvmKeeper.EndBlock(suite.ctx, abci.RequestEndBlock{Height: 100})
suite.Require().Equal(int64(initialConsumed), int64(suite.ctx.GasMeter().GasConsumed()))
bloom, found := suite.app.EvmKeeper.GetBlockBloom(suite.ctx, 100)
suite.Require().True(found)
suite.Require().Equal(int64(10), bloom.Big().Int64())
}
+263 -32
View File
@@ -2,14 +2,17 @@ package keeper
import (
"context"
"math/big"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
sdk "github.com/cosmos/cosmos-sdk/types"
tmtypes "github.com/tendermint/tendermint/types"
ethcmn "github.com/ethereum/go-ethereum/common"
"github.com/cosmos/ethermint/metrics"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
)
@@ -17,12 +20,18 @@ import (
var _ types.QueryServer = Keeper{}
// Account implements the Query/Account gRPC method
func (q Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*types.QueryAccountResponse, error) {
func (k Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*types.QueryAccountResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.Address) == 0 {
if types.IsZeroAddress(req.Address) {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
@@ -30,9 +39,10 @@ func (q Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*typ
}
ctx := sdk.UnwrapSDKContext(c)
so := q.GetOrNewStateObject(ctx, ethcmn.HexToAddress(req.Address))
so := k.GetOrNewStateObject(ctx, ethcmn.HexToAddress(req.Address))
balance, err := ethermint.MarshalBigInt(so.Balance())
if err != nil {
metrics.ReportFuncError(k.svcTags)
return nil, err
}
@@ -43,13 +53,18 @@ func (q Keeper) Account(c context.Context, req *types.QueryAccountRequest) (*typ
}, nil
}
// Balance implements the Query/Balance gRPC method
func (q Keeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*types.QueryBalanceResponse, error) {
func (k Keeper) CosmosAccount(c context.Context, req *types.QueryCosmosAccountRequest) (*types.QueryCosmosAccountResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.Address) == 0 {
if types.IsZeroAddress(req.Address) {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
@@ -58,9 +73,48 @@ func (q Keeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*typ
ctx := sdk.UnwrapSDKContext(c)
balanceInt := q.GetBalance(ctx, ethcmn.HexToAddress(req.Address))
ethStr := req.Address
ethAddr := ethcmn.FromHex(ethStr)
ethToCosmosAddr := sdk.AccAddress(ethAddr[:]).String()
cosmosToEthAddr, _ := sdk.AccAddressFromBech32(ethToCosmosAddr)
acc := k.accountKeeper.GetAccount(ctx, cosmosToEthAddr)
res := types.QueryCosmosAccountResponse{
CosmosAddress: cosmosToEthAddr.String(),
}
if acc != nil {
res.Sequence = acc.GetSequence()
res.AccountNumber = acc.GetAccountNumber()
}
return &res, nil
}
// Balance implements the Query/Balance gRPC method
func (k Keeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*types.QueryBalanceResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if types.IsZeroAddress(req.Address) {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
balanceInt := k.GetBalance(ctx, ethcmn.HexToAddress(req.Address))
balance, err := ethermint.MarshalBigInt(balanceInt)
if err != nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.Internal,
"failed to marshal big.Int to string",
@@ -73,31 +127,30 @@ func (q Keeper) Balance(c context.Context, req *types.QueryBalanceRequest) (*typ
}
// Storage implements the Query/Storage gRPC method
func (q Keeper) Storage(c context.Context, req *types.QueryStorageRequest) (*types.QueryStorageResponse, error) {
func (k Keeper) Storage(c context.Context, req *types.QueryStorageRequest) (*types.QueryStorageResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.Address) == 0 {
if types.IsZeroAddress(req.Address) {
metrics.ReportFuncError(k.svcTags)
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)
state := k.GetState(ctx, address, key)
return &types.QueryStorageResponse{
Value: state.String(),
@@ -105,12 +158,18 @@ func (q Keeper) Storage(c context.Context, req *types.QueryStorageRequest) (*typ
}
// Code implements the Query/Code gRPC method
func (q Keeper) Code(c context.Context, req *types.QueryCodeRequest) (*types.QueryCodeResponse, error) {
func (k Keeper) Code(c context.Context, req *types.QueryCodeRequest) (*types.QueryCodeResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.Address) == 0 {
if types.IsZeroAddress(req.Address) {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.InvalidArgument,
types.ErrZeroAddress.Error(),
@@ -120,7 +179,7 @@ func (q Keeper) Code(c context.Context, req *types.QueryCodeRequest) (*types.Que
ctx := sdk.UnwrapSDKContext(c)
address := ethcmn.HexToAddress(req.Address)
code := q.GetCode(ctx, address)
code := k.GetCode(ctx, address)
return &types.QueryCodeResponse{
Code: code,
@@ -128,12 +187,18 @@ func (q Keeper) Code(c context.Context, req *types.QueryCodeRequest) (*types.Que
}
// TxLogs implements the Query/TxLogs gRPC method
func (q Keeper) TxLogs(c context.Context, req *types.QueryTxLogsRequest) (*types.QueryTxLogsResponse, error) {
func (k Keeper) TxLogs(c context.Context, req *types.QueryTxLogsRequest) (*types.QueryTxLogsResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if types.IsEmptyHash(req.Hash) {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
@@ -143,8 +208,9 @@ func (q Keeper) TxLogs(c context.Context, req *types.QueryTxLogsRequest) (*types
ctx := sdk.UnwrapSDKContext(c)
hash := ethcmn.HexToHash(req.Hash)
logs, err := q.GetLogs(ctx, hash)
logs, err := k.GetLogs(ctx, hash)
if err != nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.Internal,
err.Error(),
@@ -156,13 +222,19 @@ func (q Keeper) TxLogs(c context.Context, req *types.QueryTxLogsRequest) (*types
}, nil
}
// BlockLogs implements the Query/BlockLogs gRPC method
func (q Keeper) BlockLogs(c context.Context, req *types.QueryBlockLogsRequest) (*types.QueryBlockLogsResponse, error) {
// TxReceipt implements the Query/TxReceipt gRPC method
func (k Keeper) TxReceipt(c context.Context, req *types.QueryTxReceiptRequest) (*types.QueryTxReceiptResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if types.IsEmptyHash(req.Hash) {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
@@ -171,7 +243,90 @@ func (q Keeper) BlockLogs(c context.Context, req *types.QueryBlockLogsRequest) (
ctx := sdk.UnwrapSDKContext(c)
txLogs := q.GetAllTxLogs(ctx)
hash := ethcmn.HexToHash(req.Hash)
receipt, found := k.GetTxReceiptFromHash(ctx, hash)
if !found {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.NotFound, types.ErrTxReceiptNotFound.Error(),
)
}
return &types.QueryTxReceiptResponse{
Receipt: receipt,
}, nil
}
// TxReceiptsByBlockHeight implements the Query/TxReceiptsByBlockHeight gRPC method
func (k Keeper) TxReceiptsByBlockHeight(c context.Context, req *types.QueryTxReceiptsByBlockHeightRequest) (*types.QueryTxReceiptsByBlockHeightResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(c)
receipts := k.GetTxReceiptsByBlockHeight(ctx, req.Height)
return &types.QueryTxReceiptsByBlockHeightResponse{
Receipts: receipts,
}, nil
}
// TxReceiptsByBlockHash implements the Query/TxReceiptsByBlockHash gRPC method
func (k Keeper) TxReceiptsByBlockHash(c context.Context, req *types.QueryTxReceiptsByBlockHashRequest) (*types.QueryTxReceiptsByBlockHashResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if types.IsEmptyHash(req.Hash) {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
hash := ethcmn.HexToHash(req.Hash)
receipts := k.GetTxReceiptsByBlockHash(ctx, hash)
return &types.QueryTxReceiptsByBlockHashResponse{
Receipts: receipts,
}, nil
}
// BlockLogs implements the Query/BlockLogs gRPC method
func (k Keeper) BlockLogs(c context.Context, req *types.QueryBlockLogsRequest) (*types.QueryBlockLogsResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if types.IsEmptyHash(req.Hash) {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.InvalidArgument,
types.ErrEmptyHash.Error(),
)
}
ctx := sdk.UnwrapSDKContext(c)
txLogs := k.GetAllTxLogs(ctx)
return &types.QueryBlockLogsResponse{
TxLogs: txLogs,
@@ -179,14 +334,28 @@ func (q Keeper) BlockLogs(c context.Context, req *types.QueryBlockLogsRequest) (
}
// BlockBloom implements the Query/BlockBloom gRPC method
func (q Keeper) BlockBloom(c context.Context, _ *types.QueryBlockBloomRequest) (*types.QueryBlockBloomResponse, error) {
func (k Keeper) BlockBloom(c context.Context, req *types.QueryBlockBloomRequest) (*types.QueryBlockBloomResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(c)
// use block height provided through the gRPC header
bloom, found := q.GetBlockBloom(ctx, ctx.BlockHeight())
height := ctx.BlockHeight()
if setHeight := req.Height; setHeight > 0 {
height = setHeight
}
bloom, found := k.GetBlockBloom(ctx, height)
if !found {
return nil, status.Errorf(
codes.NotFound, "%s: height %d", types.ErrBloomNotFound.Error(), ctx.BlockHeight(),
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(
codes.NotFound, types.ErrBloomNotFound.Error(),
)
}
@@ -196,11 +365,73 @@ func (q Keeper) BlockBloom(c context.Context, _ *types.QueryBlockBloomRequest) (
}
// Params implements the Query/Params gRPC method
func (q Keeper) Params(c context.Context, _ *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
func (k Keeper) Params(c context.Context, req *types.QueryParamsRequest) (*types.QueryParamsResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
if req == nil {
metrics.ReportFuncError(k.svcTags)
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(c)
params := q.GetParams(ctx)
params := k.GetParams(ctx)
return &types.QueryParamsResponse{
Params: params,
}, nil
}
// StaticCall implements Query/StaticCall gRPCP method
func (k Keeper) StaticCall(c context.Context, req *types.QueryStaticCallRequest) (*types.QueryStaticCallResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
ctx := sdk.UnwrapSDKContext(c)
// 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 := ethcmn.BytesToHash(txHash)
var recipient *ethcmn.Address
if len(req.Address) > 0 {
addr := ethcmn.HexToAddress(req.Address)
recipient = &addr
}
so := k.GetOrNewStateObject(ctx, *recipient)
sender := ethcmn.HexToAddress("0xaDd00275E3d9d213654Ce5223f0FADE8b106b707")
st := &types.StateTransition{
AccountNonce: so.Nonce(),
Price: new(big.Int).SetBytes(big.NewInt(0).Bytes()),
GasLimit: 100000000,
Recipient: recipient,
Amount: new(big.Int).SetBytes(big.NewInt(0).Bytes()),
Payload: req.Input,
Csdb: k.CommitStateDB.WithContext(ctx),
ChainID: chainIDEpoch,
TxHash: &ethHash,
Sender: sender,
Simulate: ctx.IsCheckTx(),
}
config, found := k.GetChainConfig(ctx)
if !found {
return nil, types.ErrChainConfigNotFound
}
ret, err := st.StaticCall(ctx, config)
if err != nil {
return nil, err
}
return &types.QueryStaticCallResponse{Data: ret}, nil
}
-499
View File
@@ -1,499 +0,0 @@
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)
}
+2 -4
View File
@@ -4,10 +4,8 @@ import (
"math/big"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
ethermint "github.com/cosmos/ethermint/types"
ethcmn "github.com/ethereum/go-ethereum/common"
)
@@ -27,7 +25,7 @@ func (suite *KeeperTestSuite) TestBalanceInvariant() {
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), ethermint.NewPhotonCoinInt64(1))
suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), ethermint.NewInjectiveCoinInt64(1))
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
@@ -40,7 +38,7 @@ func (suite *KeeperTestSuite) TestBalanceInvariant() {
func() {
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, address.Bytes())
suite.Require().NotNil(acc)
suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), ethermint.NewPhotonCoinInt64(1))
suite.app.BankKeeper.SetBalance(suite.ctx, acc.GetAddress(), ethermint.NewInjectiveCoinInt64(1))
suite.Require().NoError(err)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
+235 -28
View File
@@ -1,20 +1,17 @@
package keeper
import (
"fmt"
"math/big"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/cosmos/ethermint/x/evm/types"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/ethermint/metrics"
"github.com/cosmos/ethermint/x/evm/types"
)
// Keeper wraps the CommitStateDB, allowing us to pass in SDK context while adhering
@@ -27,11 +24,12 @@ type Keeper struct {
// - storing Account's Code
// - storing transaction Logs
// - storing block height -> bloom filter map. Needed for the Web3 API.
// - storing block hash -> block height map. Needed for the Web3 API.
// - storing block hash -> block height map. Needed for the Web3 API. TODO: remove
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.
@@ -39,6 +37,12 @@ type Keeper struct {
// on the KVStore or adding it as a field on the EVM genesis state.
TxCount int
Bloom *big.Int
// LogsCache keeps mapping of contract address -> eth logs emitted
// during EVM execution in the current block.
LogsCache map[common.Address][]*ethtypes.Log
svcTags metrics.Tags
}
// NewKeeper generates new evm module keeper
@@ -53,6 +57,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{
svcTags: metrics.Tags{
"svc": "evm_k",
},
cdc: cdc,
accountKeeper: ak,
bankKeeper: bankKeeper,
@@ -60,19 +68,116 @@ func NewKeeper(
CommitStateDB: types.NewCommitStateDB(sdk.Context{}, storeKey, paramSpace, ak, bankKeeper),
TxCount: 0,
Bloom: big.NewInt(0),
LogsCache: map[common.Address][]*ethtypes.Log{},
}
}
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName))
return ctx.Logger().With("module", types.ModuleName)
}
// ----------------------------------------------------------------------------
// Epoch Height -> hash mapping functions
// Required by EVM context's GetHashFunc
// Block bloom bits mapping functions
// Required by Web3 API.
// ----------------------------------------------------------------------------
// GetBlockBloom gets bloombits from block height
func (k Keeper) GetBlockBloom(ctx sdk.Context, height int64) (ethtypes.Bloom, bool) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
store := ctx.KVStore(k.storeKey)
key := types.BloomKey(height)
has := store.Has(key)
if !has {
return ethtypes.Bloom{}, true // sometimes bloom not found, fix this
}
bz := store.Get(key)
return ethtypes.BytesToBloom(bz), true
}
// SetBlockBloom sets the mapping from block height to bloom bits
func (k Keeper) SetBlockBloom(ctx sdk.Context, height int64, bloom ethtypes.Bloom) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
store := ctx.KVStore(k.storeKey)
key := types.BloomKey(height)
store.Set(key, bloom.Bytes())
}
// GetBlockHash gets block height from block consensus hash
func (k Keeper) GetBlockHashFromHeight(ctx sdk.Context, height int64) ([]byte, bool) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyBlockHeightHash(uint64(height)))
if len(bz) == 0 {
return common.Hash{}.Bytes(), false
}
return common.BytesToHash(bz).Bytes(), true
}
// SetBlockHash sets the mapping from block consensus hash to block height
func (k Keeper) SetBlockHash(ctx sdk.Context, hash []byte, height int64) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
store := ctx.KVStore(k.storeKey)
bz := sdk.Uint64ToBigEndian(uint64(height))
store.Set(types.KeyBlockHash(common.BytesToHash(hash)), bz)
}
// GetBlockHash gets block height from block consensus hash
func (k Keeper) GetBlockHeightByHash(ctx sdk.Context, hash common.Hash) (int64, bool) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyBlockHash(hash))
if len(bz) == 0 {
return 0, false
}
height := sdk.BigEndianToUint64(bz)
return int64(height), true
}
// SetBlockHash sets the mapping from block consensus hash to block height
func (k Keeper) SetBlockHeightToHash(ctx sdk.Context, hash []byte, height int64) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
store := ctx.KVStore(k.storeKey)
store.Set(types.KeyBlockHeightHash(uint64(height)), hash)
}
// SetTxReceiptToHash sets the mapping from tx hash to tx receipt
func (k Keeper) SetTxReceiptToHash(ctx sdk.Context, hash common.Hash, receipt *types.TxReceipt) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
data := k.cdc.MustMarshalBinaryBare(receipt)
store := ctx.KVStore(k.storeKey)
store.Set(types.KeyHashTxReceipt(hash), data)
}
// GetHeightHash returns the block header hash associated with a given block height and chain epoch number.
func (k Keeper) GetHeightHash(ctx sdk.Context, height uint64) common.Hash {
return k.CommitStateDB.WithContext(ctx).GetHeightHash(height)
@@ -83,31 +188,121 @@ func (k Keeper) SetHeightHash(ctx sdk.Context, height uint64, hash common.Hash)
k.CommitStateDB.WithContext(ctx).SetHeightHash(height, hash)
}
// ----------------------------------------------------------------------------
// Block bloom bits mapping functions
// Required by Web3 API.
// ----------------------------------------------------------------------------
// GetTxReceiptFromHash gets tx receipt by tx hash.
func (k Keeper) GetTxReceiptFromHash(ctx sdk.Context, hash common.Hash) (*types.TxReceipt, bool) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
// GetBlockBloom gets bloombits from block height
func (k Keeper) GetBlockBloom(ctx sdk.Context, height int64) (ethtypes.Bloom, bool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixBloom)
has := store.Has(types.BloomKey(height))
if !has {
return ethtypes.Bloom{}, false
store := ctx.KVStore(k.storeKey)
data := store.Get(types.KeyHashTxReceipt(hash))
if data == nil || len(data) == 0 {
return nil, false
}
bz := store.Get(types.BloomKey(height))
return ethtypes.BytesToBloom(bz), true
var receipt types.TxReceipt
k.cdc.MustUnmarshalBinaryBare(data, &receipt)
return &receipt, true
}
// SetBlockBloom sets the mapping from block height to bloom bits
func (k Keeper) SetBlockBloom(ctx sdk.Context, height int64, bloom ethtypes.Bloom) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixBloom)
store.Set(types.BloomKey(height), bloom.Bytes())
// AddTxHashToBlock stores tx hash in the list of tx for the block.
func (k Keeper) AddTxHashToBlock(ctx sdk.Context, blockHeight int64, txHash common.Hash) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
key := types.KeyBlockHeightTxs(uint64(blockHeight))
list := types.BytesList{}
store := ctx.KVStore(k.storeKey)
data := store.Get(key)
if len(data) > 0 {
k.cdc.MustUnmarshalBinaryBare(data, &list)
}
list.Bytes = append(list.Bytes, txHash.Bytes())
data = k.cdc.MustMarshalBinaryBare(&list)
store.Set(key, data)
}
// GetTxsFromBlock returns list of tx hash in the block by height.
func (k Keeper) GetTxsFromBlock(ctx sdk.Context, blockHeight int64) []common.Hash {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
key := types.KeyBlockHeightTxs(uint64(blockHeight))
store := ctx.KVStore(k.storeKey)
data := store.Get(key)
if len(data) > 0 {
list := types.BytesList{}
k.cdc.MustUnmarshalBinaryBare(data, &list)
txs := make([]common.Hash, 0, len(list.Bytes))
for _, b := range list.Bytes {
txs = append(txs, common.BytesToHash(b))
}
return txs
}
return nil
}
// GetTxReceiptsByBlockHeight gets tx receipts by block height.
func (k Keeper) GetTxReceiptsByBlockHeight(ctx sdk.Context, blockHeight int64) []*types.TxReceipt {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
txs := k.GetTxsFromBlock(ctx, blockHeight)
if len(txs) == 0 {
return nil
}
store := ctx.KVStore(k.storeKey)
receipts := make([]*types.TxReceipt, 0, len(txs))
for idx, txHash := range txs {
data := store.Get(types.KeyHashTxReceipt(txHash))
if data == nil || len(data) == 0 {
continue
}
var receipt types.TxReceipt
k.cdc.MustUnmarshalBinaryBare(data, &receipt)
receipt.Index = uint64(idx)
receipts = append(receipts, &receipt)
}
return receipts
}
// GetTxReceiptsByBlockHash gets tx receipts by block hash.
func (k Keeper) GetTxReceiptsByBlockHash(ctx sdk.Context, hash common.Hash) []*types.TxReceipt {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
blockHeight, ok := k.GetBlockHeightByHash(ctx, hash)
if !ok {
return nil
}
return k.GetTxReceiptsByBlockHeight(ctx, blockHeight)
}
// GetAllTxLogs return all the transaction logs from the store.
func (k Keeper) GetAllTxLogs(ctx sdk.Context) []types.TransactionLogs {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, types.KeyPrefixLogs)
defer iterator.Close()
@@ -125,6 +320,10 @@ func (k Keeper) GetAllTxLogs(ctx sdk.Context) []types.TransactionLogs {
// GetAccountStorage return state storage associated with an account
func (k Keeper) GetAccountStorage(ctx sdk.Context, address common.Address) (types.Storage, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
storage := types.Storage{}
err := k.ForEachStorage(ctx, address, func(key, value common.Hash) bool {
@@ -140,6 +339,10 @@ 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) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.KeyPrefixChainConfig)
if len(bz) == 0 {
@@ -153,6 +356,10 @@ 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) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryBare(&config)
store.Set(types.KeyPrefixChainConfig, bz)
+8 -18
View File
@@ -7,7 +7,6 @@ import (
"github.com/stretchr/testify/suite"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
@@ -32,24 +31,20 @@ var (
type KeeperTestSuite struct {
suite.Suite
ctx sdk.Context
app *app.EthermintApp
queryClient types.QueryClient
address ethcmn.Address
ctx sdk.Context
querier sdk.Querier
app *app.InjectiveApp
address ethcmn.Address
}
func (suite *KeeperTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: "ethermint-3", Time: time.Now().UTC()})
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()})
suite.address = ethcmn.HexToAddress(addrHex)
queryHelper := baseapp.NewQueryServerTestHelper(suite.ctx, suite.app.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, suite.app.EvmKeeper)
suite.queryClient = types.NewQueryClient(queryHelper)
balance := ethermint.NewPhotonCoin(sdk.ZeroInt())
balance := ethermint.NewInjectiveCoin(sdk.ZeroInt())
acc := &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0),
CodeHash: ethcrypto.Keccak256(nil),
@@ -69,13 +64,11 @@ 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}
@@ -90,7 +83,6 @@ 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)
@@ -99,19 +91,17 @@ 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].EthLogs())
suite.Require().Equal([]*ethtypes.Log{log2, log3}, txLogs[0].Logs)
suite.Require().Equal(ethHash.String(), txLogs[1].Hash)
suite.Require().Equal([]*ethtypes.Log{log}, txLogs[1].EthLogs())
suite.Require().Equal([]*ethtypes.Log{log}, txLogs[1].Logs)
}
func (suite *KeeperTestSuite) TestDBStorage() {
+288 -36
View File
@@ -2,57 +2,68 @@ package keeper
import (
"context"
"math/big"
"github.com/armon/go-metrics"
"github.com/pkg/errors"
log "github.com/xlab/suplog"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
ethcmn "github.com/ethereum/go-ethereum/common"
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"
"github.com/cosmos/ethermint/metrics"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
)
var _ types.MsgServer = Keeper{}
var _ types.MsgServer = &Keeper{}
func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
// EthereumTx implements the Msg/EthereumTx gRPC method.
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 {
metrics.ReportFuncError(k.svcTags)
return nil, err
}
// Verify signature and retrieve sender address
sender, err := msg.VerifySig(chainIDEpoch)
if err != nil {
return nil, err
var homesteadErr error
sender, eip155Err := msg.VerifySig(chainIDEpoch)
if eip155Err != nil {
sender, homesteadErr = msg.VerifySigHomestead()
if homesteadErr != nil {
log.WithFields(log.Fields{
"eip155_err": eip155Err.Error(),
"homestead_err": homesteadErr.Error(),
}).Warningln("failed to verify signatures with EIP155 and Homestead signers")
metrics.ReportFuncError(k.svcTags)
return nil, errors.New("no valid signatures")
}
}
txHash := tmtypes.Tx(ctx.TxBytes()).Hash()
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)
if len(msg.Data.Recipient) > 0 {
addr := ethcmn.BytesToAddress(msg.Data.Recipient)
recipient = &addr
labels = []metrics.Label{telemetry.NewLabel("operation", "call")}
}
st := types.StateTransition{
st := &types.StateTransition{
AccountNonce: msg.Data.AccountNonce,
Price: msg.Data.Price.BigInt(),
Price: new(big.Int).SetBytes(msg.Data.Price),
GasLimit: msg.Data.GasLimit,
Recipient: recipient,
Amount: msg.Data.Amount.BigInt(),
Amount: new(big.Int).SetBytes(msg.Data.Amount),
Payload: msg.Data.Payload,
Csdb: k.CommitStateDB.WithContext(ctx),
ChainID: chainIDEpoch,
@@ -66,18 +77,47 @@ func (k Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*ty
// other nodes, causing a consensus error
if !st.Simulate {
// Prepare db for logs
blockHash := types.HashFromContext(ctx)
k.Prepare(ctx, ethHash, blockHash, k.TxCount)
hash, _ := k.GetBlockHashFromHeight(ctx, ctx.BlockHeight())
k.Prepare(ctx, ethHash, ethcmn.BytesToHash(hash), k.TxCount)
k.TxCount++
}
config, found := k.GetChainConfig(ctx)
if !found {
metrics.ReportFuncError(k.svcTags)
return nil, types.ErrChainConfigNotFound
}
executionResult, err := st.TransitionDb(ctx, config)
if err != nil {
if err.Error() == "execution reverted" && executionResult != nil {
// keep the execution result for revert reason
executionResult.Response.Reverted = true
metrics.ReportFuncError(k.svcTags)
if !st.Simulate {
blockHash, _ := k.GetBlockHashFromHeight(ctx, ctx.BlockHeight())
k.SetTxReceiptToHash(ctx, ethHash, &types.TxReceipt{
Hash: ethHash.Bytes(),
From: sender.Bytes(),
Data: msg.Data,
BlockHeight: uint64(ctx.BlockHeight()),
BlockHash: blockHash,
Result: &types.TxResult{
ContractAddress: executionResult.Response.ContractAddress,
Bloom: executionResult.Response.Bloom,
TxLogs: executionResult.Response.TxLogs,
Ret: executionResult.Response.Ret,
Reverted: executionResult.Response.Reverted,
GasUsed: executionResult.GasInfo.GasConsumed,
},
})
}
return executionResult.Response, nil
}
metrics.ReportFuncError(k.svcTags)
return nil, err
}
@@ -86,28 +126,42 @@ func (k Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*ty
k.Bloom.Or(k.Bloom, executionResult.Bloom)
// update transaction logs in KVStore
err = k.SetLogs(ctx, ethcmn.BytesToHash(txHash), executionResult.Logs)
err = k.SetLogs(ctx, ethHash, 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,
)
blockHash, _ := k.GetBlockHashFromHeight(ctx, ctx.BlockHeight())
k.SetTxReceiptToHash(ctx, ethHash, &types.TxReceipt{
Hash: ethHash.Bytes(),
From: sender.Bytes(),
Data: msg.Data,
Index: uint64(st.Csdb.TxIndex()),
BlockHeight: uint64(ctx.BlockHeight()),
BlockHash: blockHash,
Result: &types.TxResult{
ContractAddress: executionResult.Response.ContractAddress,
Bloom: executionResult.Response.Bloom,
TxLogs: executionResult.Response.TxLogs,
Ret: executionResult.Response.Ret,
Reverted: executionResult.Response.Reverted,
GasUsed: executionResult.GasInfo.GasConsumed,
},
})
k.AddTxHashToBlock(ctx, ctx.BlockHeight(), ethHash)
for _, ethLog := range executionResult.Logs {
k.LogsCache[ethLog.Address] = append(k.LogsCache[ethLog.Address], ethLog)
}
}()
}
// emit events
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeEthereumTx,
sdk.NewAttribute(sdk.AttributeKeyAmount, st.Amount.String()),
sdk.NewAttribute(types.AttributeKeyTxHash, ethcmn.BytesToHash(txHash).Hex()),
),
sdk.NewEvent(
sdk.EventTypeMessage,
@@ -116,11 +170,209 @@ func (k Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*ty
),
})
if msg.Data.Recipient != nil {
if len(msg.Data.Recipient) > 0 {
ethAddr := ethcmn.BytesToAddress(msg.Data.Recipient)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeEthereumTx,
sdk.NewAttribute(types.AttributeKeyRecipient, msg.Data.Recipient.Address),
sdk.NewAttribute(types.AttributeKeyRecipient, ethAddr.Hex()),
),
)
}
metrics.ReportFuncError(k.svcTags)
return executionResult.Response, nil
}
func (k *Keeper) SendInternalEthereumTx(
ctx sdk.Context,
payload []byte,
senderAddress common.Address,
recipientAddress common.Address,
) (*types.MsgEthereumTxResponse, error) {
accAddress := sdk.AccAddress(senderAddress.Bytes())
acc := k.accountKeeper.GetAccount(ctx, accAddress)
if acc == nil {
acc = k.accountKeeper.NewAccountWithAddress(ctx, accAddress)
k.accountKeeper.SetAccount(ctx, acc)
}
ethAccount, ok := acc.(*ethermint.EthAccount)
if !ok {
return nil, errors.New("could not cast account to EthAccount")
}
if err := ethAccount.SetSequence(ethAccount.GetSequence() + 1); err != nil {
return nil, errors.New("failed to set acc sequence")
}
k.accountKeeper.SetAccount(ctx, ethAccount)
res, err := k.InternalEthereumTx(sdk.WrapSDKContext(ctx), senderAddress, &types.TxData{
AccountNonce: ethAccount.GetSequence(),
Recipient: recipientAddress.Bytes(),
Amount: big.NewInt(0).Bytes(),
Price: big.NewInt(0).Bytes(),
GasLimit: 10000000, // TODO: don't hardcode, maybe set a limit?
Payload: payload,
})
if err != nil {
err = errors.Wrapf(err, "failed to execute InternalEthereumTx at contract %s", recipientAddress.Hex())
return nil, err
}
return res, nil
}
func (k *Keeper) InternalEthereumTx(
goCtx context.Context,
sender common.Address,
tx *types.TxData,
) (*types.MsgEthereumTxResponse, error) {
metrics.ReportFuncCall(k.svcTags)
doneFn := metrics.ReportFuncTiming(k.svcTags)
defer doneFn()
ctx := sdk.UnwrapSDKContext(goCtx)
// parse the chainID from a string to a base-10 integer
chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID())
if err != nil {
metrics.ReportFuncError(k.svcTags)
return nil, err
}
// true Ethereum tx hash based on its data
ethHash := (&types.MsgEthereumTx{
Data: tx,
}).RLPSignBytes(chainIDEpoch)
var recipient *ethcmn.Address
if len(tx.Recipient) > 0 {
addr := ethcmn.BytesToAddress(tx.Recipient)
recipient = &addr
}
st := &types.StateTransition{
AccountNonce: tx.AccountNonce,
Price: new(big.Int).SetBytes(tx.Price),
GasLimit: tx.GasLimit,
Recipient: recipient,
Amount: new(big.Int).SetBytes(tx.Amount),
Payload: tx.Payload,
Csdb: k.CommitStateDB.WithContext(ctx),
ChainID: chainIDEpoch,
TxHash: &ethHash,
Sender: sender,
Simulate: ctx.IsCheckTx(),
}
// since the txCount is used by the stateDB, and a simulated tx is run only on the node it's submitted to,
// then this will cause the txCount/stateDB of the node that ran the simulated tx to be different than the
// other nodes, causing a consensus error
if !st.Simulate {
// Prepare db for logs
hash, _ := k.GetBlockHashFromHeight(ctx, ctx.BlockHeight())
k.Prepare(ctx, ethHash, ethcmn.BytesToHash(hash), k.TxCount)
k.TxCount++
}
config, found := k.GetChainConfig(ctx)
if !found {
metrics.ReportFuncError(k.svcTags)
return nil, types.ErrChainConfigNotFound
}
executionResult, err := st.TransitionDb(ctx, config)
if err != nil {
if err.Error() == "execution reverted" && executionResult != nil {
// keep the execution result for revert reason
executionResult.Response.Reverted = true
metrics.ReportFuncError(k.svcTags)
if !st.Simulate {
blockHash, _ := k.GetBlockHashFromHeight(ctx, ctx.BlockHeight())
k.SetTxReceiptToHash(ctx, ethHash, &types.TxReceipt{
Hash: ethHash.Bytes(),
From: sender.Bytes(),
Data: tx,
BlockHeight: uint64(ctx.BlockHeight()),
BlockHash: blockHash,
Result: &types.TxResult{
ContractAddress: executionResult.Response.ContractAddress,
Bloom: executionResult.Response.Bloom,
TxLogs: executionResult.Response.TxLogs,
Ret: executionResult.Response.Ret,
Reverted: executionResult.Response.Reverted,
GasUsed: executionResult.GasInfo.GasConsumed,
},
})
}
return executionResult.Response, err
}
metrics.ReportFuncError(k.svcTags)
return nil, err
}
blockHash, _ := k.GetBlockHashFromHeight(ctx, ctx.BlockHeight())
k.SetTxReceiptToHash(ctx, ethHash, &types.TxReceipt{
Hash: ethHash.Bytes(),
From: sender.Bytes(),
Data: tx,
Index: uint64(st.Csdb.TxIndex()),
BlockHeight: uint64(ctx.BlockHeight()),
BlockHash: blockHash,
Result: &types.TxResult{
ContractAddress: executionResult.Response.ContractAddress,
Bloom: executionResult.Response.Bloom,
TxLogs: executionResult.Response.TxLogs,
Ret: executionResult.Response.Ret,
Reverted: executionResult.Response.Reverted,
GasUsed: executionResult.GasInfo.GasConsumed,
},
})
k.AddTxHashToBlock(ctx, ctx.BlockHeight(), ethHash)
if !st.Simulate {
// update block bloom filter
k.Bloom.Or(k.Bloom, executionResult.Bloom)
// update transaction logs in KVStore
err = k.SetLogs(ctx, ethHash, executionResult.Logs)
if err != nil {
panic(err)
}
for _, ethLog := range executionResult.Logs {
k.LogsCache[ethLog.Address] = append(k.LogsCache[ethLog.Address], ethLog)
}
}
// emit events
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeEthereumTx,
sdk.NewAttribute(sdk.AttributeKeyAmount, st.Amount.String()),
sdk.NewAttribute(types.AttributeKeyTxHash, ethHash.Hex()),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
sdk.NewAttribute(sdk.AttributeKeySender, sender.String()),
),
})
if len(tx.Recipient) > 0 {
ethAddr := ethcmn.BytesToAddress(tx.Recipient)
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeEthereumTx,
sdk.NewAttribute(types.AttributeKeyRecipient, ethAddr.Hex()),
),
)
}
+1 -1
View File
@@ -7,7 +7,7 @@ import (
func (suite *KeeperTestSuite) TestParams() {
params := suite.app.EvmKeeper.GetParams(suite.ctx)
suite.Require().Equal(types.DefaultParams(), params)
params.EvmDenom = "ara"
params.EvmDenom = "inj"
suite.app.EvmKeeper.SetParams(suite.ctx, params)
newParams := suite.app.EvmKeeper.GetParams(suite.ctx)
suite.Require().Equal(newParams, params)
+7 -2
View File
@@ -49,6 +49,11 @@ func (k *Keeper) SetCode(ctx sdk.Context, addr ethcmn.Address, code []byte) {
// SetLogs calls CommitStateDB.SetLogs using the passed in context
func (k *Keeper) SetLogs(ctx sdk.Context, hash ethcmn.Hash, logs []*ethtypes.Log) error {
// TODO:@albert
// since SetLogs is only called for non-simulation mode, GasEstimation is quite not correct
// I suggest using ctx.ConsumeGas(XXX) where XXX is max of gas consume for set logs.
ctx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
return k.CommitStateDB.WithContext(ctx).SetLogs(hash, logs)
}
@@ -225,8 +230,8 @@ func (k *Keeper) Reset(ctx sdk.Context, root ethcmn.Hash) error {
}
// Prepare calls CommitStateDB.Prepare using the passed in context
func (k *Keeper) Prepare(ctx sdk.Context, thash ethcmn.Hash, txi int) {
k.CommitStateDB.WithContext(ctx).Prepare(thash, txi)
func (k *Keeper) Prepare(ctx sdk.Context, thash, bhash ethcmn.Hash, txi int) {
k.CommitStateDB.WithContext(ctx).Prepare(thash, bhash, txi)
}
// CreateAccount calls CommitStateDB.CreateAccount using the passed in context
+2 -4
View File
@@ -18,7 +18,7 @@ import (
func (suite *KeeperTestSuite) TestBloomFilter() {
// Prepare db for logs
tHash := ethcmn.BytesToHash([]byte{0x1})
suite.app.EvmKeeper.Prepare(suite.ctx, tHash, 0)
suite.app.EvmKeeper.Prepare(suite.ctx, tHash, ethcmn.Hash{}, 0)
contractAddress := ethcmn.BigToAddress(big.NewInt(1))
log := ethtypes.Log{Address: contractAddress, Topics: []ethcmn.Hash{}}
@@ -230,7 +230,6 @@ func (suite *KeeperTestSuite) TestStateDB_Logs() {
suite.Require().Empty(dbLogs, tc.name)
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.
@@ -360,8 +359,7 @@ func (suite *KeeperTestSuite) TestSuiteDB_Prepare() {
bhash := ethcmn.BytesToHash([]byte("bhash"))
txi := 1
suite.app.EvmKeeper.Prepare(suite.ctx, thash, txi)
suite.app.EvmKeeper.CommitStateDB.SetBlockHash(bhash)
suite.app.EvmKeeper.Prepare(suite.ctx, thash, bhash, txi)
suite.Require().Equal(txi, suite.app.EvmKeeper.TxIndex(suite.ctx))
suite.Require().Equal(bhash, suite.app.EvmKeeper.BlockHash(suite.ctx))
+15 -12
View File
@@ -57,17 +57,16 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, _ client.TxEncodi
// RegisterRESTRoutes performs a no-op as the EVM module doesn't expose REST
// endpoints
func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {
func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Router) {
}
// 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 {
func (b AppModuleBasic) RegisterGRPCGatewayRoutes(c client.Context, serveMux *runtime.ServeMux) {
if err := types.RegisterQueryHandlerClient(context.Background(), serveMux, types.NewQueryClient(c)); err != nil {
panic(err)
}
}
// GetTxCmd returns nil as the evm module doesn't support transactions through the CLI.
// GetTxCmd returns the root tx command for the evm module.
func (AppModuleBasic) GetTxCmd() *cobra.Command {
return nil
}
@@ -82,7 +81,7 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry)
types.RegisterInterfaces(registry)
}
// ____________________________________________________________________________
//____________________________________________________________________________
// AppModule implements an application module for the evm module.
type AppModule struct {
@@ -107,20 +106,23 @@ func (AppModule) Name() string {
return types.ModuleName
}
// RegisterInvariants interface for registering invariants
// RegisterInvariants interface for registering invariants. Performs a no-op
// as the evm module doesn't expose invariants.
func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
keeper.RegisterInvariants(ir, *am.keeper)
// Invariats lead to performance degradation
//
// keeper.RegisterInvariants(ir, *am.keeper)
}
// RegisterServices registers the evm module Msg and gRPC services.
// RegisterQueryService registers a GRPC query service to respond to the
// module-specific GRPC queries.
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), am.keeper)
types.RegisterQueryServer(cfg.QueryServer(), 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))
return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper))
}
// QuerierRoute returns the evm module's querier route name.
@@ -149,7 +151,8 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j
var genesisState types.GenesisState
cdc.MustUnmarshalJSON(data, &genesisState)
return InitGenesis(ctx, *am.keeper, am.ak, am.bk, genesisState)
InitGenesis(ctx, *am.keeper, am.ak, am.bk, genesisState)
return []abci.ValidatorUpdate{}
}
// ExportGenesis returns the exported genesis state as raw bytes for the evm
+6 -15
View File
@@ -28,12 +28,13 @@ func (cc ChainConfig) EthereumConfig(chainID *big.Int) *params.ChainConfig {
PetersburgBlock: getBlockValue(cc.PetersburgBlock),
IstanbulBlock: getBlockValue(cc.IstanbulBlock),
MuirGlacierBlock: getBlockValue(cc.MuirGlacierBlock),
YoloV2Block: getBlockValue(cc.YoloV2Block),
EWASMBlock: getBlockValue(cc.EWASMBlock),
//TODO(xlab): after upgrading ethereum to newer version, this should be set to YoloV2Block
YoloV2Block: getBlockValue(cc.YoloV2Block),
EWASMBlock: getBlockValue(cc.EWASMBlock),
}
}
// DefaultChainConfig returns default evm parameters.
// DefaultChainConfig returns default evm parameters. Th
func DefaultChainConfig() ChainConfig {
return ChainConfig{
HomesteadBlock: sdk.ZeroInt(),
@@ -46,8 +47,8 @@ func DefaultChainConfig() ChainConfig {
ByzantiumBlock: sdk.ZeroInt(),
ConstantinopleBlock: sdk.ZeroInt(),
PetersburgBlock: sdk.ZeroInt(),
IstanbulBlock: sdk.ZeroInt(),
MuirGlacierBlock: sdk.ZeroInt(),
IstanbulBlock: sdk.NewInt(-1),
MuirGlacierBlock: sdk.NewInt(-1),
YoloV2Block: sdk.NewInt(-1),
EWASMBlock: sdk.NewInt(-1),
}
@@ -125,13 +126,3 @@ 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
}
+1 -1
View File
@@ -226,7 +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:"-1" muir_glacier_block:"-1" yolo_v2_block:"-1" ewasm_block:"-1" `
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())
}
+16 -11
View File
@@ -4,28 +4,33 @@ 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"
)
type (
ExtensionOptionsEthereumTxI interface{}
ExtensionOptionsWeb3TxI interface{}
)
// 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{},
)
msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc)
registry.RegisterInterface("injective.evm.v1beta1.ExtensionOptionsEthereumTx", (*ExtensionOptionsEthereumTxI)(nil))
registry.RegisterImplementations(
(*ExtensionOptionsEthereumTxI)(nil),
&ExtensionOptionsEthereumTx{},
)
registry.RegisterInterface("injective.evm.v1beta1.ExtensionOptionsWeb3Tx", (*ExtensionOptionsWeb3TxI)(nil))
registry.RegisterImplementations(
(*ExtensionOptionsWeb3TxI)(nil),
&ExtensionOptionsWeb3Tx{},
)
}
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())
)
+14 -2
View File
@@ -25,9 +25,21 @@ var (
// ErrBloomNotFound returns an error if the block bloom cannot be found on the store.
ErrBloomNotFound = sdkerrors.Register(ModuleName, 7, "block bloom not found")
// ErrInvalidValue returns an error resulting from an invalid value.
ErrInvalidValue = sdkerrors.Register(ModuleName, 8, "invalid value")
// ErrInvalidChainID returns an error resulting from an invalid chain ID.
ErrInvalidChainID = sdkerrors.Register(ModuleName, 9, "invalid chain ID")
// ErrVMExecution returns an error resulting from an error in EVM execution.
ErrVMExecution = sdkerrors.Register(ModuleName, 10, "error while executing evm transaction")
// ErrTxReceiptNotFound returns an error if the transaction receipt could not be found
ErrTxReceiptNotFound = sdkerrors.Register(ModuleName, 11, "transaction receipt not found")
// ErrCreateDisabled returns an error if the EnableCreate parameter is false.
ErrCreateDisabled = sdkerrors.Register(ModuleName, 8, "EVM Create operation is disabled")
ErrCreateDisabled = sdkerrors.Register(ModuleName, 12, "EVM Create operation is disabled")
// ErrCallDisabled returns an error if the EnableCall parameter is false.
ErrCallDisabled = sdkerrors.Register(ModuleName, 9, "EVM Call operation is disabled")
ErrCallDisabled = sdkerrors.Register(ModuleName, 13, "EVM Call operation is disabled")
)
+1
View File
@@ -6,5 +6,6 @@ const (
AttributeKeyContractAddress = "contract"
AttributeKeyRecipient = "recipient"
AttributeKeyTxHash = "txHash"
AttributeValueCategory = ModuleName
)
+1614 -97
View File
File diff suppressed because it is too large Load Diff
+1 -2
View File
@@ -4,13 +4,12 @@ import (
"errors"
"fmt"
ethermint "github.com/cosmos/ethermint/types"
ethcmn "github.com/ethereum/go-ethereum/common"
)
// Validate performs a basic validation of a GenesisAccount fields.
func (ga GenesisAccount) Validate() error {
if ethermint.IsZeroAddress(ga.Address) {
if IsZeroAddress(ga.Address) {
return fmt.Errorf("address cannot be the zero address %s", ga.Address)
}
if len(ethcmn.Hex2Bytes(ga.Code)) == 0 {
+37 -42
View File
@@ -1,5 +1,5 @@
// Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: ethermint/evm/v1alpha1/genesis.proto
// source: injective/evm/v1beta1/genesis.proto
package types
@@ -38,7 +38,7 @@ 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}
return fileDescriptor_edebcfd612cffc8a, []int{0}
}
func (m *GenesisState) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -111,7 +111,7 @@ 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}
return fileDescriptor_edebcfd612cffc8a, []int{1}
}
func (m *GenesisAccount) XXX_Unmarshal(b []byte) error {
return m.Unmarshal(b)
@@ -162,42 +162,43 @@ func (m *GenesisAccount) GetStorage() Storage {
}
func init() {
proto.RegisterType((*GenesisState)(nil), "ethermint.evm.v1alpha1.GenesisState")
proto.RegisterType((*GenesisAccount)(nil), "ethermint.evm.v1alpha1.GenesisAccount")
proto.RegisterType((*GenesisState)(nil), "injective.evm.v1beta1.GenesisState")
proto.RegisterType((*GenesisAccount)(nil), "injective.evm.v1beta1.GenesisAccount")
}
func init() {
proto.RegisterFile("ethermint/evm/v1alpha1/genesis.proto", fileDescriptor_8205a12b97b89a87)
proto.RegisterFile("injective/evm/v1beta1/genesis.proto", fileDescriptor_edebcfd612cffc8a)
}
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,
var fileDescriptor_edebcfd612cffc8a = []byte{
// 420 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0xc1, 0x8e, 0xd2, 0x40,
0x18, 0xc7, 0xdb, 0x85, 0x6c, 0x77, 0x87, 0x8d, 0x9b, 0x8c, 0x1a, 0x1b, 0xd4, 0x96, 0xd4, 0x68,
0xb8, 0xd8, 0x06, 0xbc, 0xe9, 0xc9, 0x72, 0x20, 0x24, 0x1c, 0x4c, 0xf1, 0xc4, 0x85, 0x4c, 0xa7,
0xe3, 0x50, 0x43, 0x3b, 0xa4, 0x33, 0x34, 0xf0, 0x04, 0x5e, 0x7d, 0x0e, 0x9f, 0x84, 0x23, 0x07,
0x0f, 0x9e, 0xd0, 0xc0, 0x1b, 0xf8, 0x04, 0x66, 0xa6, 0x2d, 0xb2, 0x09, 0xbd, 0xcd, 0x24, 0xbf,
0xff, 0x6f, 0xfe, 0xfd, 0xfa, 0x81, 0x57, 0x71, 0xfa, 0x95, 0x60, 0x11, 0xe7, 0xc4, 0x23, 0x79,
0xe2, 0xe5, 0xbd, 0x90, 0x08, 0xd4, 0xf3, 0x28, 0x49, 0x09, 0x8f, 0xb9, 0xbb, 0xcc, 0x98, 0x60,
0xf0, 0xe9, 0x09, 0x72, 0x49, 0x9e, 0xb8, 0x25, 0xd4, 0x7e, 0x42, 0x19, 0x65, 0x8a, 0xf0, 0xe4,
0xa9, 0x80, 0xdb, 0xf6, 0x65, 0xa3, 0x0c, 0x2a, 0xc0, 0xf9, 0x79, 0x05, 0xee, 0x86, 0x85, 0x7f,
0x22, 0x90, 0x20, 0x70, 0x08, 0x6e, 0x10, 0xc6, 0x6c, 0x95, 0x0a, 0x6e, 0xea, 0x9d, 0x46, 0xb7,
0xd5, 0x7f, 0xed, 0x5e, 0x7c, 0xd1, 0x2d, 0x63, 0x1f, 0x0b, 0xda, 0x6f, 0x6e, 0xf7, 0xb6, 0x16,
0x9c, 0xc2, 0x30, 0x04, 0x77, 0x78, 0x8e, 0xe2, 0x74, 0x86, 0x59, 0xfa, 0x25, 0xa6, 0xe6, 0x55,
0x47, 0xef, 0xb6, 0xfa, 0x4e, 0x8d, 0x6c, 0x20, 0xd1, 0x81, 0x22, 0xfd, 0xe7, 0xd2, 0xf4, 0x77,
0x6f, 0x3f, 0xde, 0xa0, 0x64, 0xf1, 0xde, 0x39, 0xb7, 0x38, 0x41, 0x0b, 0xff, 0x27, 0xe1, 0x07,
0x70, 0xbd, 0x44, 0x19, 0x4a, 0xb8, 0xd9, 0x50, 0xf6, 0x97, 0x35, 0xf6, 0x4f, 0x0a, 0x2a, 0x2b,
0x96, 0x11, 0x38, 0x05, 0x37, 0x62, 0xcd, 0x67, 0x0b, 0x46, 0xb9, 0xd9, 0x54, 0x5f, 0xfa, 0xa6,
0x26, 0xfe, 0x39, 0x43, 0x29, 0x47, 0x58, 0xc4, 0x2c, 0x1d, 0x33, 0xca, 0xfd, 0x67, 0x65, 0xc1,
0xfb, 0xa2, 0x60, 0x65, 0x71, 0x02, 0x43, 0xac, 0xb9, 0x24, 0x9c, 0x6f, 0x3a, 0x78, 0xf4, 0x70,
0x3e, 0xd0, 0x04, 0x06, 0x8a, 0xa2, 0x8c, 0x70, 0x39, 0x57, 0xbd, 0x7b, 0x1b, 0x54, 0x57, 0x08,
0x41, 0x13, 0xb3, 0x88, 0xa8, 0x09, 0xdd, 0x06, 0xea, 0x0c, 0x87, 0xc0, 0xe0, 0x82, 0x65, 0x88,
0x12, 0xb3, 0xa1, 0xba, 0xbd, 0xa8, 0xe9, 0xa6, 0xfe, 0x9a, 0x7f, 0x2f, 0x1b, 0xfd, 0xf8, 0x6d,
0x1b, 0x93, 0x22, 0x14, 0x54, 0x69, 0x1f, 0x6f, 0x0f, 0x96, 0xbe, 0x3b, 0x58, 0xfa, 0x9f, 0x83,
0xa5, 0x7f, 0x3f, 0x5a, 0xda, 0xee, 0x68, 0x69, 0xbf, 0x8e, 0x96, 0x36, 0x1d, 0xd1, 0x58, 0xcc,
0x57, 0xa1, 0x8b, 0x59, 0xe2, 0x8d, 0x2a, 0xf7, 0x18, 0x85, 0xdc, 0x3b, 0xbd, 0xf4, 0x16, 0xb3,
0x8c, 0x9c, 0x5f, 0xe5, 0xec, 0xbd, 0x84, 0x45, 0xab, 0x05, 0xe1, 0x6a, 0xa3, 0xc4, 0x66, 0x49,
0x78, 0x78, 0xad, 0x96, 0xe9, 0xdd, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xed, 0x3b, 0xae, 0x70,
0xc1, 0x02, 0x00, 0x00,
}
func (m *GenesisState) Marshal() (dAtA []byte, err error) {
@@ -556,10 +557,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
@@ -707,10 +705,7 @@ func (m *GenesisAccount) Unmarshal(dAtA []byte) error {
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) < 0 {
if (skippy < 0) || (iNdEx+skippy) < 0 {
return ErrInvalidLengthGenesis
}
if (iNdEx + skippy) > l {
+26
View File
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/suite"
sdk "github.com/cosmos/cosmos-sdk/types"
ethcmn "github.com/ethereum/go-ethereum/common"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
@@ -42,6 +43,7 @@ func (suite *GenesisTestSuite) TestValidateGenesisAccount() {
"valid genesis account",
GenesisAccount{
Address: suite.address,
Balance: sdk.OneInt(),
Code: suite.code,
Storage: Storage{
NewState(suite.hash, suite.hash),
@@ -53,6 +55,23 @@ func (suite *GenesisTestSuite) TestValidateGenesisAccount() {
"empty account address bytes",
GenesisAccount{
Address: ethcmn.Address{}.String(),
Balance: sdk.OneInt(),
},
false,
},
{
"empty account balance",
GenesisAccount{
Address: suite.address,
Balance: sdk.Int{},
},
false,
},
{
"negative account balance",
GenesisAccount{
Address: suite.address,
Balance: sdk.NewInt(-1),
},
false,
},
@@ -60,6 +79,7 @@ func (suite *GenesisTestSuite) TestValidateGenesisAccount() {
"empty code bytes",
GenesisAccount{
Address: suite.address,
Balance: sdk.OneInt(),
Code: "",
},
false,
@@ -78,6 +98,7 @@ func (suite *GenesisTestSuite) TestValidateGenesisAccount() {
}
func (suite *GenesisTestSuite) TestValidateGenesis() {
testCases := []struct {
name string
genState *GenesisState
@@ -94,6 +115,7 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
Accounts: []GenesisAccount{
{
Address: suite.address,
Balance: sdk.OneInt(),
Code: suite.code,
Storage: Storage{
{Key: suite.hash.String()},
@@ -145,6 +167,7 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
Accounts: []GenesisAccount{
{
Address: suite.address,
Balance: sdk.OneInt(),
Code: suite.code,
Storage: Storage{
NewState(suite.hash, suite.hash),
@@ -152,6 +175,7 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
},
{
Address: suite.address,
Balance: sdk.OneInt(),
Code: suite.code,
Storage: Storage{
NewState(suite.hash, suite.hash),
@@ -167,6 +191,7 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
Accounts: []GenesisAccount{
{
Address: suite.address,
Balance: sdk.OneInt(),
Code: suite.code,
Storage: Storage{
{Key: suite.hash.String()},
@@ -216,6 +241,7 @@ func (suite *GenesisTestSuite) TestValidateGenesis() {
Accounts: []GenesisAccount{
{
Address: suite.address,
Balance: sdk.OneInt(),
Code: suite.code,
Storage: Storage{
{Key: suite.hash.String()},
+7 -6
View File
@@ -5,14 +5,14 @@ import (
"os"
"testing"
ethermint "github.com/cosmos/ethermint/types"
"github.com/stretchr/testify/suite"
tmlog "github.com/tendermint/tendermint/libs/log"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
tmdb "github.com/tendermint/tm-db"
"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"
authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper"
@@ -26,9 +26,10 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
ethermintcodec "github.com/cosmos/ethermint/codec"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
ethcodec "github.com/cosmos/ethermint/codec"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
ethermint "github.com/cosmos/ethermint/types"
)
func newTestCodec() (codec.BinaryMarshaler, *codec.LegacyAmino) {
@@ -38,7 +39,7 @@ func newTestCodec() (codec.BinaryMarshaler, *codec.LegacyAmino) {
sdk.RegisterLegacyAminoCodec(amino)
ethermintcodec.RegisterInterfaces(interfaceRegistry)
ethcodec.RegisterInterfaces(interfaceRegistry)
return cdc, amino
}
@@ -61,7 +62,7 @@ func (suite *JournalTestSuite) SetupTest() {
suite.address = ethcmn.BytesToAddress(privkey.PubKey().Address().Bytes())
suite.journal = newJournal()
balance := ethermint.NewPhotonCoin(sdk.NewInt(100))
balance := ethermint.NewInjectiveCoin(sdk.NewInt(100))
acc := &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0),
CodeHash: ethcrypto.Keccak256(nil),
+32 -17
View File
@@ -21,26 +21,21 @@ const (
// KVStore key prefixes
var (
KeyPrefixBloom = []byte{0x01}
KeyPrefixLogs = []byte{0x02}
KeyPrefixCode = []byte{0x03}
KeyPrefixStorage = []byte{0x04}
KeyPrefixChainConfig = []byte{0x05}
KeyPrefixHeightHash = []byte{0x06}
KeyPrefixBlockHash = []byte{0x01}
KeyPrefixBloom = []byte{0x02}
KeyPrefixLogs = []byte{0x03}
KeyPrefixCode = []byte{0x04}
KeyPrefixStorage = []byte{0x05}
KeyPrefixChainConfig = []byte{0x06}
KeyPrefixBlockHeightHash = []byte{0x07}
KeyPrefixHashTxReceipt = []byte{0x08}
KeyPrefixBlockHeightTxs = []byte{0x09}
)
// HeightHashKey returns the key for the given chain epoch and height.
// The key will be composed in the following order:
// key = prefix + bytes(height)
// This ordering facilitates the iteration by height for the EVM GetHashFn
// queries.
func HeightHashKey(height uint64) []byte {
return sdk.Uint64ToBigEndian(height)
}
// BloomKey defines the store key for a block Bloom
func BloomKey(height int64) []byte {
return sdk.Uint64ToBigEndian(uint64(height))
heightBytes := sdk.Uint64ToBigEndian(uint64(height))
return append(KeyPrefixBloom, heightBytes...)
}
// AddressStoragePrefix returns a prefix to iterate over a given account storage.
@@ -53,4 +48,24 @@ func StateKey(address ethcmn.Address, key []byte) []byte {
return append(AddressStoragePrefix(address), key...)
}
// TODO: fix Logs key and append block hash
// KeyBlockHash returns a key for accessing block hash data.
func KeyBlockHash(hash ethcmn.Hash) []byte {
return append(KeyPrefixBlockHash, hash.Bytes()...)
}
// KeyBlockHash returns a key for accessing block hash data.
func KeyBlockHeightHash(height uint64) []byte {
heightBytes := sdk.Uint64ToBigEndian(height)
return append(KeyPrefixBlockHeightHash, heightBytes...)
}
// KeyHashTxReceipt returns a key for accessing tx receipt data by hash.
func KeyHashTxReceipt(hash ethcmn.Hash) []byte {
return append(KeyPrefixHashTxReceipt, hash.Bytes()...)
}
// KeyBlockHeightTxs returns a key for accessing tx hash list by block height.
func KeyBlockHeightTxs(height uint64) []byte {
heightBytes := sdk.Uint64ToBigEndian(height)
return append(KeyPrefixBlockHeightTxs, heightBytes...)
}
+13 -4
View File
@@ -1,10 +1,12 @@
package types
import (
"bytes"
"errors"
"fmt"
ethermint "github.com/cosmos/ethermint/types"
log "github.com/xlab/suplog"
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
)
@@ -32,7 +34,7 @@ func NewTransactionLogsFromEth(hash ethcmn.Hash, ethlogs []*ethtypes.Log) Transa
// Validate performs a basic validation of a GenesisAccount fields.
func (tx TransactionLogs) Validate() error {
if ethermint.IsEmptyHash(tx.Hash) {
if bytes.Equal(ethcmn.Hex2Bytes(tx.Hash), ethcmn.Hash{}.Bytes()) {
return fmt.Errorf("hash cannot be the empty %s", tx.Hash)
}
@@ -57,7 +59,7 @@ func (tx TransactionLogs) EthLogs() []*ethtypes.Log {
// Validate performs a basic validation of an ethereum Log fields.
func (log *Log) Validate() error {
if ethermint.IsZeroAddress(log.Address) {
if IsZeroAddress(log.Address) {
return fmt.Errorf("log address cannot be empty %s", log.Address)
}
if IsEmptyHash(log.BlockHash) {
@@ -66,7 +68,7 @@ func (log *Log) Validate() error {
if log.BlockNumber == 0 {
return errors.New("block number cannot be zero")
}
if ethermint.IsEmptyHash(log.TxHash) {
if IsEmptyHash(log.TxHash) {
return fmt.Errorf("tx hash cannot be the empty %s", log.TxHash)
}
return nil
@@ -86,6 +88,7 @@ func (log *Log) ToEthereum() *ethtypes.Log {
BlockNumber: log.BlockNumber,
TxHash: ethcmn.HexToHash(log.TxHash),
TxIndex: uint(log.TxIndex),
Index: uint(log.Index),
BlockHash: ethcmn.HexToHash(log.BlockHash),
Removed: log.Removed,
}
@@ -95,6 +98,12 @@ func (log *Log) ToEthereum() *ethtypes.Log {
func LogsToEthereum(logs []*Log) []*ethtypes.Log {
ethLogs := make([]*ethtypes.Log, len(logs))
for i := range logs {
err := logs[i].Validate()
if err != nil {
log.WithError(err).Errorln("failed log validation", logs[i].String())
continue
}
ethLogs[i] = logs[i].ToEthereum()
}
return ethLogs
+41 -26
View File
@@ -1,10 +1,21 @@
package types
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
ethcmn "github.com/ethereum/go-ethereum/common"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
)
func (suite *GenesisTestSuite) TestTransactionLogsValidate() {
func TestTransactionLogsValidate(t *testing.T) {
priv, err := ethsecp256k1.GenerateKey()
require.NoError(t, err)
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey).String()
testCases := []struct {
name string
txLogs TransactionLogs
@@ -13,16 +24,16 @@ func (suite *GenesisTestSuite) TestTransactionLogsValidate() {
{
"valid log",
TransactionLogs{
Hash: suite.hash.String(),
Hash: ethcmn.BytesToHash([]byte("tx_hash")).String(),
Logs: []*Log{
{
Address: suite.address,
Topics: []string{suite.hash.String()},
Address: addr,
Topics: []string{ethcmn.BytesToHash([]byte("topic")).String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: suite.hash.String(),
TxHash: ethcmn.BytesToHash([]byte("tx_hash")).String(),
TxIndex: 1,
BlockHash: suite.hash.String(),
BlockHash: ethcmn.BytesToHash([]byte("block_hash")).String(),
Index: 1,
Removed: false,
},
@@ -40,24 +51,24 @@ func (suite *GenesisTestSuite) TestTransactionLogsValidate() {
{
"invalid log",
TransactionLogs{
Hash: suite.hash.String(),
Logs: []*Log{nil},
Hash: ethcmn.BytesToHash([]byte("tx_hash")).String(),
Logs: []*Log{{}},
},
false,
},
{
"hash mismatch log",
TransactionLogs{
Hash: suite.hash.String(),
Hash: ethcmn.BytesToHash([]byte("tx_hash")).String(),
Logs: []*Log{
{
Address: suite.address,
Topics: []string{suite.hash.String()},
Address: addr,
Topics: []string{ethcmn.BytesToHash([]byte("topic")).String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: ethcmn.BytesToHash([]byte("other_hash")).String(),
TxIndex: 1,
BlockHash: suite.hash.String(),
BlockHash: ethcmn.BytesToHash([]byte("block_hash")).String(),
Index: 1,
Removed: false,
},
@@ -71,14 +82,18 @@ func (suite *GenesisTestSuite) TestTransactionLogsValidate() {
tc := tc
err := tc.txLogs.Validate()
if tc.expPass {
suite.Require().NoError(err, tc.name)
require.NoError(t, err, tc.name)
} else {
suite.Require().Error(err, tc.name)
require.Error(t, err, tc.name)
}
}
}
func (suite *GenesisTestSuite) TestValidateLog() {
func TestValidateLog(t *testing.T) {
priv, err := ethsecp256k1.GenerateKey()
require.NoError(t, err)
addr := ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey).String()
testCases := []struct {
name string
log *Log
@@ -87,13 +102,13 @@ func (suite *GenesisTestSuite) TestValidateLog() {
{
"valid log",
&Log{
Address: suite.address,
Topics: []string{suite.hash.String()},
Address: addr,
Topics: []string{ethcmn.BytesToHash([]byte("topic")).String()},
Data: []byte("data"),
BlockNumber: 1,
TxHash: suite.hash.String(),
TxHash: ethcmn.BytesToHash([]byte("tx_hash")).String(),
TxIndex: 1,
BlockHash: suite.hash.String(),
BlockHash: ethcmn.BytesToHash([]byte("block_hash")).String(),
Index: 1,
Removed: false,
},
@@ -112,7 +127,7 @@ func (suite *GenesisTestSuite) TestValidateLog() {
{
"empty block hash",
&Log{
Address: suite.address,
Address: addr,
BlockHash: ethcmn.Hash{}.String(),
},
false,
@@ -120,8 +135,8 @@ func (suite *GenesisTestSuite) TestValidateLog() {
{
"zero block number",
&Log{
Address: suite.address,
BlockHash: suite.hash.String(),
Address: addr,
BlockHash: ethcmn.BytesToHash([]byte("block_hash")).String(),
BlockNumber: 0,
},
false,
@@ -129,8 +144,8 @@ func (suite *GenesisTestSuite) TestValidateLog() {
{
"empty tx hash",
&Log{
Address: suite.address,
BlockHash: suite.hash.String(),
Address: addr,
BlockHash: ethcmn.BytesToHash([]byte("block_hash")).String(),
BlockNumber: 1,
TxHash: ethcmn.Hash{}.String(),
},
@@ -142,9 +157,9 @@ func (suite *GenesisTestSuite) TestValidateLog() {
tc := tc
err := tc.log.Validate()
if tc.expPass {
suite.Require().NoError(err, tc.name)
require.NoError(t, err, tc.name)
} else {
suite.Require().Error(err, tc.name)
require.Error(t, err, tc.name)
}
}
}
+76 -106
View File
@@ -2,13 +2,10 @@ package types
import (
"crypto/ecdsa"
"errors"
"fmt"
"io"
"math/big"
ethermint "github.com/cosmos/ethermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
@@ -27,7 +24,7 @@ var big8 = big.NewInt(8)
// message type and route constants
const (
// TypeMsgEthereumTx defines the type string of an Ethereum transaction
// TypeMsgEthereumTx defines the type string of an Ethereum tranasction
TypeMsgEthereumTx = "ethereum"
)
@@ -55,28 +52,28 @@ func newMsgEthereumTx(
payload = ethcmn.CopyBytes(payload)
}
var recipient *Recipient
var toBz []byte
if to != nil {
recipient = &Recipient{Address: to.String()}
toBz = to.Bytes()
}
txData := &TxData{
AccountNonce: nonce,
Recipient: recipient,
Recipient: toBz,
Payload: payload,
GasLimit: gasLimit,
Amount: sdk.ZeroInt(),
Price: sdk.ZeroInt(),
Amount: []byte{},
Price: []byte{},
V: []byte{},
R: []byte{},
S: []byte{},
}
if amount != nil {
txData.Amount = sdk.NewIntFromBigInt(amount)
txData.Amount = amount.Bytes()
}
if gasPrice != nil {
txData.Price = sdk.NewIntFromBigInt(gasPrice)
txData.Price = gasPrice.Bytes()
}
return &MsgEthereumTx{Data: txData}
@@ -91,17 +88,19 @@ func (msg MsgEthereumTx) Type() string { return TypeMsgEthereumTx }
// ValidateBasic implements the sdk.Msg interface. It performs basic validation
// checks of a Transaction. If returns an error if validation fails.
func (msg MsgEthereumTx) ValidateBasic() error {
if msg.Data.Price.IsZero() {
return sdkerrors.Wrapf(ethermint.ErrInvalidValue, "gas price cannot be 0")
}
gasPrice := new(big.Int).SetBytes(msg.Data.Price)
// if gasPrice.Sign() == 0 {
// return sdkerrors.Wrapf(ErrInvalidValue, "gas price cannot be 0")
// }
if msg.Data.Price.IsNegative() {
return sdkerrors.Wrapf(ethermint.ErrInvalidValue, "gas price cannot be negative %s", msg.Data.Price)
if gasPrice.Sign() == -1 {
return sdkerrors.Wrapf(ErrInvalidValue, "gas price cannot be negative %s", gasPrice)
}
// Amount can be 0
if msg.Data.Amount.IsNegative() {
return sdkerrors.Wrapf(ethermint.ErrInvalidValue, "amount cannot be negative %s", msg.Data.Amount)
amount := new(big.Int).SetBytes(msg.Data.Amount)
if amount.Sign() == -1 {
return sdkerrors.Wrapf(ErrInvalidValue, "amount cannot be negative %s", amount)
}
return nil
@@ -110,11 +109,11 @@ func (msg MsgEthereumTx) ValidateBasic() error {
// To returns the recipient address of the transaction. It returns nil if the
// transaction is a contract creation.
func (msg MsgEthereumTx) To() *ethcmn.Address {
if msg.Data.Recipient == nil {
if len(msg.Data.Recipient) == 0 {
return nil
}
recipient := ethcmn.HexToAddress(msg.Data.Recipient.Address)
recipient := ethcmn.BytesToAddress(msg.Data.Recipient)
return &recipient
}
@@ -149,52 +148,33 @@ func (msg MsgEthereumTx) GetSignBytes() []byte {
func (msg MsgEthereumTx) RLPSignBytes(chainID *big.Int) ethcmn.Hash {
return rlpHash([]interface{}{
msg.Data.AccountNonce,
msg.Data.Price.BigInt(),
new(big.Int).SetBytes(msg.Data.Price),
msg.Data.GasLimit,
msg.To(),
msg.Data.Amount.BigInt(),
msg.Data.Payload,
new(big.Int).SetBytes(msg.Data.Amount),
new(big.Int).SetBytes(msg.Data.Payload),
chainID,
uint(0),
uint(0),
})
}
// RLPSignHomesteadBytes returns the RLP hash of an Ethereum transaction message with a
// a Homestead layout without chainID.
func (msg MsgEthereumTx) RLPSignHomesteadBytes() ethcmn.Hash {
return rlpHash([]interface{}{
msg.Data.AccountNonce,
msg.Data.Price,
msg.Data.GasLimit,
msg.To(),
msg.Data.Amount,
msg.Data.Payload,
})
}
// EncodeRLP implements the rlp.Encoder interface.
func (msg *MsgEthereumTx) EncodeRLP(w io.Writer) error {
var hash ethcmn.Hash
if len(msg.Data.Hash) > 0 {
hash = ethcmn.HexToHash(msg.Data.Hash)
}
data := struct {
AccountNonce uint64
Price *big.Int `json:"gasPrice"`
GasLimit uint64 `json:"gas"`
Recipient *ethcmn.Address `json:"to" rlp:"nil"` // nil means contract creation
Amount *big.Int `json:"value"`
Payload []byte `json:"input"`
// signature values
V *big.Int `json:"v"`
R *big.Int `json:"r"`
S *big.Int `json:"s"`
// hash is only used when marshaling to JSON
Hash *ethcmn.Hash `json:"hash" rlp:"-"`
}{
AccountNonce: msg.Data.AccountNonce,
Price: msg.Data.Price.BigInt(),
GasLimit: msg.Data.GasLimit,
Recipient: msg.To(),
Amount: msg.Data.Amount.BigInt(),
Payload: msg.Data.Payload,
V: new(big.Int).SetBytes(msg.Data.V),
R: new(big.Int).SetBytes(msg.Data.R),
S: new(big.Int).SetBytes(msg.Data.S),
Hash: &hash,
}
return rlp.Encode(w, data)
return rlp.Encode(w, &msg.Data)
}
// DecodeRLP implements the rlp.Decoder interface.
@@ -205,50 +185,10 @@ func (msg *MsgEthereumTx) DecodeRLP(s *rlp.Stream) error {
return err
}
var data struct {
AccountNonce uint64
Price *big.Int `json:"gasPrice"`
GasLimit uint64 `json:"gas"`
Recipient *ethcmn.Address `json:"to" rlp:"nil"` // nil means contract creation
Amount *big.Int `json:"value"`
Payload []byte `json:"input"`
// signature values
V *big.Int `json:"v"`
R *big.Int `json:"r"`
S *big.Int `json:"s"`
// hash is only used when marshaling to JSON
Hash *ethcmn.Hash `json:"hash" rlp:"-"`
}
if err := s.Decode(&data); err != nil {
if err := s.Decode(&msg.Data); err != nil {
return err
}
var hash string
if data.Hash != nil {
hash = data.Hash.String()
}
var recipient *Recipient
if data.Recipient != nil {
recipient = &Recipient{Address: data.Recipient.String()}
}
msg.Data = &TxData{
AccountNonce: data.AccountNonce,
Price: sdk.NewIntFromBigInt(data.Price),
GasLimit: data.GasLimit,
Recipient: recipient,
Amount: sdk.NewIntFromBigInt(data.Amount),
Payload: data.Payload,
V: data.V.Bytes(),
R: data.R.Bytes(),
S: data.S.Bytes(),
Hash: hash,
}
msg.Size_ = float64(ethcmn.StorageSize(rlp.ListSize(size)))
return nil
}
@@ -292,23 +232,27 @@ func (msg *MsgEthereumTx) Sign(chainID *big.Int, priv *ecdsa.PrivateKey) error {
// VerifySig attempts to verify a Transaction's signature for a given chainID.
// A derived address is returned upon success or an error if recovery fails.
func (msg *MsgEthereumTx) VerifySig(chainID *big.Int) (ethcmn.Address, error) {
v, r, s := msg.RawSignatureValues()
signer := ethtypes.NewEIP155Signer(chainID)
if msg.From != nil {
if msg.From.Signer == nil {
return msg.VerifySigHomestead()
}
// If the signer used to derive from in a previous call is not the same as
// used current, invalidate the cache.
fromSigner := ethtypes.NewEIP155Signer(new(big.Int).SetBytes(msg.From.Signer.chainId))
if signer.Equal(fromSigner) {
return ethcmn.HexToAddress(msg.From.Address), nil
return ethcmn.BytesToAddress(msg.From.Address), nil
}
}
// do not allow recovery for transactions with an unprotected chainID
if chainID.Sign() == 0 {
return ethcmn.Address{}, errors.New("chainID cannot be zero")
return msg.VerifySigHomestead()
}
v, r, s := msg.RawSignatureValues()
chainIDMul := new(big.Int).Mul(chainID, big.NewInt(2))
V := new(big.Int).Sub(v, chainIDMul)
V.Sub(V, big8)
@@ -324,8 +268,35 @@ func (msg *MsgEthereumTx) VerifySig(chainID *big.Int) (ethcmn.Address, error) {
chainId: chainID.Bytes(),
chainIdMul: new(big.Int).Mul(chainID, big.NewInt(2)).Bytes(),
},
Address: sender.String(),
Address: sender.Bytes(),
}
return sender, nil
}
// VerifySigHomestead attempts to verify a Transaction's signature in legacy way (no EIP155).
// A derived address is returned upon success or an error if recovery fails.
func (msg *MsgEthereumTx) VerifySigHomestead() (ethcmn.Address, error) {
// signer := ethtypes.HomesteadSigner{}
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 msg.From.Signer == nil {
return ethcmn.BytesToAddress(msg.From.Address), nil
}
}
v, r, s := msg.RawSignatureValues()
sigHash := msg.RLPSignHomesteadBytes()
sender, err := recoverEthSig(r, s, v, sigHash)
if err != nil {
return ethcmn.Address{}, err
}
msg.From = &SigCache{
Address: sender.Bytes(),
}
return sender, nil
}
@@ -336,21 +307,20 @@ func (msg MsgEthereumTx) GetGas() uint64 {
// Fee returns gasprice * gaslimit.
func (msg MsgEthereumTx) Fee() *big.Int {
gasPrice := msg.Data.Price.BigInt()
gasPrice := new(big.Int).SetBytes(msg.Data.Price)
gasLimit := new(big.Int).SetUint64(msg.Data.GasLimit)
return new(big.Int).Mul(gasPrice, gasLimit)
}
// ChainID returns which chain id this transaction was signed for (if at all)
func (msg *MsgEthereumTx) ChainID() *big.Int {
v := new(big.Int).SetBytes(msg.Data.V)
return deriveChainID(v)
return deriveChainID(new(big.Int).SetBytes(msg.Data.V))
}
// Cost returns amount + gasprice * gaslimit.
func (msg MsgEthereumTx) Cost() *big.Int {
total := msg.Fee()
total.Add(total, msg.Data.Amount.BigInt())
total.Add(total, new(big.Int).SetBytes(msg.Data.Amount))
return total
}
@@ -369,7 +339,7 @@ func (msg *MsgEthereumTx) GetFrom() sdk.AccAddress {
return nil
}
return sdk.AccAddress(ethcmn.HexToAddress(msg.From.Address).Bytes())
return sdk.AccAddress(msg.From.Address)
}
// deriveChainID derives the chain id from the given v parameter
+4 -16
View File
@@ -16,23 +16,12 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
// GenerateEthAddress generates an Ethereum address.
func GenerateEthAddress() ethcmn.Address {
priv, err := ethsecp256k1.GenerateKey()
if err != nil {
panic(err)
}
return ethcmn.BytesToAddress(priv.PubKey().Address().Bytes())
}
func TestMsgEthereumTx(t *testing.T) {
addr := GenerateEthAddress()
msg := NewMsgEthereumTx(0, &addr, nil, 100000, nil, []byte("test"))
require.NotNil(t, msg)
require.NotNil(t, msg.Data.Recipient)
require.Equal(t, msg.Data.Recipient.Address, addr.String())
require.EqualValues(t, msg.Data.Recipient, addr.Bytes())
require.Equal(t, msg.Route(), RouterKey)
require.Equal(t, msg.Type(), TypeMsgEthereumTx)
require.NotNil(t, msg.To())
@@ -42,7 +31,7 @@ func TestMsgEthereumTx(t *testing.T) {
msg = NewMsgEthereumTxContract(0, nil, 100000, nil, []byte("test"))
require.NotNil(t, msg)
require.Empty(t, msg.Data.Recipient)
require.Nil(t, msg.Data.Recipient)
require.Nil(t, msg.To())
}
@@ -62,11 +51,10 @@ 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.NoError(t, err, "valid test %d failed: %s", i, tc.msg)
require.Nil(t, msg.ValidateBasic(), "valid test %d failed: %s", i, tc.msg)
} else {
require.Error(t, err, "invalid test %d passed: %s", i, tc.msg)
require.NotNil(t, msg.ValidateBasic(), "invalid test %d passed: %s", i, tc.msg)
}
}
}
+1 -4
View File
@@ -7,10 +7,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
"github.com/ethereum/go-ethereum/core/vm"
ethermint "github.com/cosmos/ethermint/types"
)
var _ paramtypes.ParamSet = &Params{}
@@ -41,7 +38,7 @@ func NewParams(evmDenom string, enableCreate, enableCall bool, extraEIPs ...int6
// DefaultParams returns default evm parameters
func DefaultParams() Params {
return Params{
EvmDenom: ethermint.AttoPhoton,
EvmDenom: "inj",
EnableCreate: true,
EnableCall: true,
ExtraEIPs: []int64(nil), // TODO: define default values
+2 -2
View File
@@ -53,7 +53,7 @@ func TestParamsValidate(t *testing.T) {
func TestParamsValidatePriv(t *testing.T) {
require.Error(t, validateEVMDenom(false))
require.NoError(t, validateEVMDenom("aphoton"))
require.NoError(t, validateEVMDenom("inj"))
require.Error(t, validateBool(""))
require.NoError(t, validateBool(true))
require.Error(t, validateEIPs(""))
@@ -61,5 +61,5 @@ func TestParamsValidatePriv(t *testing.T) {
}
func TestParams_String(t *testing.T) {
require.Equal(t, "evm_denom: aphoton\nenable_create: true\nenable_call: true\nextra_eips: []\n", DefaultParams().String())
require.Equal(t, "evm_denom: inj\nenable_create: true\nenable_call: true\nextra_eips: []\n", DefaultParams().String())
}
+9
View File
@@ -0,0 +1,9 @@
package types
// Constants to match up protocol versions and messages
const (
eth65 = 65
// ProtocolVersion is the latest supported version of the eth protocol.
ProtocolVersion = eth65
)
-26
View File
@@ -1,26 +0,0 @@
package types
import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
"strings"
"testing"
)
func TestQueryETHLogs_String(t *testing.T) {
const expectedQueryETHLogsStr = `{0x0000000000000000000000000000000000000000 [] [1 2 3 4] 9 0x0000000000000000000000000000000000000000000000000000000000000000 0 0x0000000000000000000000000000000000000000000000000000000000000000 0 false}
{0x0000000000000000000000000000000000000000 [] [5 6 7 8] 10 0x0000000000000000000000000000000000000000000000000000000000000000 0 0x0000000000000000000000000000000000000000000000000000000000000000 0 false}
`
logs := []*ethtypes.Log{
{
Data: []byte{1, 2, 3, 4},
BlockNumber: 9,
},
{
Data: []byte{5, 6, 7, 8},
BlockNumber: 10,
},
}
require.True(t, strings.EqualFold(expectedQueryETHLogsStr, QueryETHLogs{logs}.String()))
}
+2196 -164
View File
File diff suppressed because it is too large Load Diff
+499 -9
View File
@@ -1,5 +1,5 @@
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
// source: ethermint/evm/v1alpha1/query.proto
// source: injective/evm/v1beta1/query.proto
/*
Package types is a reverse proxy.
@@ -85,6 +85,60 @@ func local_request_Query_Account_0(ctx context.Context, marshaler runtime.Marsha
}
func request_Query_CosmosAccount_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryCosmosAccountRequest
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.CosmosAccount(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_CosmosAccount_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryCosmosAccountRequest
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.CosmosAccount(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
@@ -323,6 +377,168 @@ func local_request_Query_TxLogs_0(ctx context.Context, marshaler runtime.Marshal
}
func request_Query_TxReceipt_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryTxReceiptRequest
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.TxReceipt(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_TxReceipt_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryTxReceiptRequest
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.TxReceipt(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_TxReceiptsByBlockHeight_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryTxReceiptsByBlockHeightRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["height"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "height")
}
protoReq.Height, err = runtime.Int64(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "height", err)
}
msg, err := client.TxReceiptsByBlockHeight(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_TxReceiptsByBlockHeight_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryTxReceiptsByBlockHeightRequest
var metadata runtime.ServerMetadata
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["height"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "height")
}
protoReq.Height, err = runtime.Int64(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "height", err)
}
msg, err := server.TxReceiptsByBlockHeight(ctx, &protoReq)
return msg, metadata, err
}
func request_Query_TxReceiptsByBlockHash_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryTxReceiptsByBlockHashRequest
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.TxReceiptsByBlockHash(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_TxReceiptsByBlockHash_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryTxReceiptsByBlockHashRequest
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.TxReceiptsByBlockHash(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
@@ -377,10 +593,21 @@ func local_request_Query_BlockLogs_0(ctx context.Context, marshaler runtime.Mars
}
var (
filter_Query_BlockBloom_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
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
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_BlockBloom_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.BlockBloom(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
@@ -390,6 +617,13 @@ func local_request_Query_BlockBloom_0(ctx context.Context, marshaler runtime.Mar
var protoReq QueryBlockBloomRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_BlockBloom_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.BlockBloom(ctx, &protoReq)
return msg, metadata, err
@@ -413,6 +647,42 @@ func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshal
}
var (
filter_Query_StaticCall_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Query_StaticCall_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryStaticCallRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_StaticCall_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.StaticCall(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Query_StaticCall_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq QueryStaticCallRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_StaticCall_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.StaticCall(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.
@@ -439,6 +709,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
})
mux.Handle("GET", pattern_Query_CosmosAccount_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_CosmosAccount_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_CosmosAccount_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()
@@ -519,6 +809,66 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
})
mux.Handle("GET", pattern_Query_TxReceipt_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_TxReceipt_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_TxReceipt_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_TxReceiptsByBlockHeight_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_TxReceiptsByBlockHeight_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_TxReceiptsByBlockHeight_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_TxReceiptsByBlockHash_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_TxReceiptsByBlockHash_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_TxReceiptsByBlockHash_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()
@@ -579,6 +929,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
})
mux.Handle("GET", pattern_Query_StaticCall_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_StaticCall_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_StaticCall_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
@@ -640,6 +1010,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
})
mux.Handle("GET", pattern_Query_CosmosAccount_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_CosmosAccount_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_CosmosAccount_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()
@@ -720,6 +1110,66 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
})
mux.Handle("GET", pattern_Query_TxReceipt_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_TxReceipt_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_TxReceipt_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_TxReceiptsByBlockHeight_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_TxReceiptsByBlockHeight_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_TxReceiptsByBlockHeight_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("GET", pattern_Query_TxReceiptsByBlockHash_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_TxReceiptsByBlockHash_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_TxReceiptsByBlockHash_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()
@@ -780,30 +1230,62 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
})
mux.Handle("GET", pattern_Query_StaticCall_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_StaticCall_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_StaticCall_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_Account_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"injective", "evm", "v1beta1", "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_CosmosAccount_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"injective", "evm", "v1beta1", "cosmos_account", "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_Balance_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"injective", "evm", "v1beta1", "balances", "address"}, "", 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_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{"injective", "evm", "v1beta1", "storage", "address", "key"}, "", 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_Code_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"injective", "evm", "v1beta1", "codes", "address"}, "", 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_TxLogs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"injective", "evm", "v1beta1", "tx_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_TxReceipt_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"injective", "evm", "v1beta1", "tx_receipt", "hash"}, "", 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)))
pattern_Query_TxReceiptsByBlockHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"injective", "evm", "v1beta1", "tx_receipts_block", "height"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_TxReceiptsByBlockHash_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"injective", "evm", "v1beta1", "tx_receipts_block_hash", "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{"injective", "evm", "v1beta1", "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{"injective", "evm", "v1beta1", "block_bloom"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"injective", "evm", "v1beta1", "params"}, "", runtime.AssumeColonVerbOpt(true)))
pattern_Query_StaticCall_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"injective", "evm", "v1beta1", "static_call"}, "", runtime.AssumeColonVerbOpt(true)))
)
var (
forward_Query_Account_0 = runtime.ForwardResponseMessage
forward_Query_CosmosAccount_0 = runtime.ForwardResponseMessage
forward_Query_Balance_0 = runtime.ForwardResponseMessage
forward_Query_Storage_0 = runtime.ForwardResponseMessage
@@ -812,9 +1294,17 @@ var (
forward_Query_TxLogs_0 = runtime.ForwardResponseMessage
forward_Query_TxReceipt_0 = runtime.ForwardResponseMessage
forward_Query_TxReceiptsByBlockHeight_0 = runtime.ForwardResponseMessage
forward_Query_TxReceiptsByBlockHash_0 = runtime.ForwardResponseMessage
forward_Query_BlockLogs_0 = runtime.ForwardResponseMessage
forward_Query_BlockBloom_0 = runtime.ForwardResponseMessage
forward_Query_Params_0 = runtime.ForwardResponseMessage
forward_Query_StaticCall_0 = runtime.ForwardResponseMessage
)
+10 -11
View File
@@ -10,7 +10,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/types"
ethcmn "github.com/ethereum/go-ethereum/common"
ethstate "github.com/ethereum/go-ethereum/core/state"
@@ -53,7 +53,7 @@ type StateObject interface {
// Account values can be accessed and modified through the object.
// Finally, call CommitTrie to write the modified storage trie into a database.
type stateObject struct {
code ethermint.Code // contract bytecode, which gets set when code is loaded
code types.Code // contract bytecode, which gets set when code is loaded
// State objects are used by the consensus core and VM which are
// unable to deal with database-level errors. Any error that occurs
// during a database read is memoized here and will eventually be returned
@@ -64,7 +64,7 @@ type stateObject struct {
// DB error
dbErr error
stateDB *CommitStateDB
account *ethermint.EthAccount
account *types.EthAccount
// balance represents the amount of the EVM denom token that an account holds
balance sdk.Int
@@ -83,21 +83,21 @@ type stateObject struct {
}
func newStateObject(db *CommitStateDB, accProto authtypes.AccountI, balance sdk.Int) *stateObject {
ethermintAccount, ok := accProto.(*ethermint.EthAccount)
ethAccount, ok := accProto.(*types.EthAccount)
if !ok {
panic(fmt.Sprintf("invalid account type for state object: %T", accProto))
}
// set empty code hash
if ethermintAccount.CodeHash == nil {
ethermintAccount.CodeHash = emptyCodeHash
if ethAccount.CodeHash == nil {
ethAccount.CodeHash = emptyCodeHash
}
return &stateObject{
stateDB: db,
account: ethermintAccount,
account: ethAccount,
balance: balance,
address: ethermintAccount.EthAddress(),
address: ethAccount.EthAddress(),
originStorage: Storage{},
dirtyStorage: Storage{},
keyToOriginStorageIndex: make(map[ethcmn.Hash]int),
@@ -250,9 +250,8 @@ func (so *stateObject) commitState() {
key := ethcmn.HexToHash(state.Key)
value := ethcmn.HexToHash(state.Value)
// delete empty values from the store
if ethermint.IsEmptyHash(state.Value) {
if IsEmptyHash(state.Value) {
store.Delete(key.Bytes())
}
@@ -264,7 +263,7 @@ func (so *stateObject) commitState() {
continue
}
if ethermint.IsEmptyHash(state.Value) {
if IsEmptyHash(state.Value) {
delete(so.keyToOriginStorageIndex, key)
continue
}
+142 -33
View File
@@ -1,18 +1,22 @@
package types
import (
"errors"
"math/big"
"os"
"sync"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/pkg/errors"
log "github.com/xlab/suplog"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/ethermint/metrics"
)
// StateTransition defines data to transitionDB in evm
@@ -30,6 +34,18 @@ type StateTransition struct {
TxHash *common.Hash
Sender common.Address
Simulate bool // i.e CheckTx execution
Debug bool // enable EVM debugging
once sync.Once
svcTags metrics.Tags
}
func (st *StateTransition) initOnce() {
st.once.Do(func() {
st.svcTags = metrics.Tags{
"svc": "evm_state",
}
})
}
// GasInfo returns the gas limit, gas consumed and gas refunded from the EVM transition
@@ -49,16 +65,16 @@ type ExecutionResult struct {
}
// GetHashFn implements vm.GetHashFunc for Ethermint. It handles 3 cases:
// 1. The requested height matches the current height (and thus same epoch number)
// 1. The requested height matches the current height from context (and thus same epoch number)
// 2. The requested height is from an previous height from the same chain epoch
// 3. The requested height is from a height greater than the latest one
func GetHashFn(ctx sdk.Context, csdb *CommitStateDB) vm.GetHashFunc {
return func(height uint64) common.Hash {
switch {
case ctx.BlockHeight() == int64(height):
// Case 1: The requested height matches the one from the CommitStateDB so we can retrieve the block
// hash directly from the CommitStateDB.
return csdb.bhash
// Case 1: The requested height matches the one from the context so we can retrieve the header
// hash directly from the context.
return HashFromContext(ctx)
case ctx.BlockHeight() > int64(height):
// Case 2: if the chain is not the current height we need to retrieve the hash from the store for the
@@ -72,7 +88,7 @@ func GetHashFn(ctx sdk.Context, csdb *CommitStateDB) vm.GetHashFunc {
}
}
func (st StateTransition) newEVM(
func (st *StateTransition) newEVM(
ctx sdk.Context,
csdb *CommitStateDB,
gasLimit uint64,
@@ -80,13 +96,14 @@ func (st StateTransition) newEVM(
config ChainConfig,
extraEIPs []int64,
) *vm.EVM {
// Create context for evm
st.initOnce()
// Create context for evm
blockCtx := vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
GetHash: GetHashFn(ctx, csdb),
Coinbase: common.Address{}, // there's no beneficiary since we're not mining
Coinbase: common.Address{}, // there's no benefitiary since we're not mining
BlockNumber: big.NewInt(ctx.BlockHeight()),
Time: big.NewInt(ctx.BlockHeader().Time.Unix()),
Difficulty: big.NewInt(0), // unused. Only required in PoW context
@@ -106,18 +123,35 @@ func (st StateTransition) newEVM(
vmConfig := vm.Config{
ExtraEips: eips,
}
if st.Debug {
vmConfig.Tracer = vm.NewJSONLogger(&vm.LogConfig{
Debug: true,
}, os.Stderr)
vmConfig.Debug = true
}
return vm.NewEVM(blockCtx, txCtx, csdb, config.EthereumConfig(st.ChainID), vmConfig)
}
// TransitionDb will transition the state by applying the current transaction and
// returning the evm execution result.
// NOTE: State transition checks are run during AnteHandler execution.
func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*ExecutionResult, error) {
func (st *StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (resp *ExecutionResult, err error) {
st.initOnce()
metrics.ReportFuncCall(st.svcTags)
doneFn := metrics.ReportFuncTiming(st.svcTags)
defer doneFn()
contractCreation := st.Recipient == nil
cost, err := core.IntrinsicGas(st.Payload, contractCreation, config.IsHomestead(), config.IsIstanbul())
cost, err := core.IntrinsicGas(st.Payload, contractCreation, true, false)
if err != nil {
return nil, sdkerrors.Wrap(err, "invalid intrinsic gas for transaction")
metrics.ReportFuncError(st.svcTags)
err = sdkerrors.Wrap(err, "invalid intrinsic gas for transaction")
return nil, err
}
// This gas limit the the transaction gas limit with intrinsic gas subtracted
@@ -149,8 +183,10 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
params := csdb.GetParams()
gasPrice := ctx.MinGasPrices().AmountOf(params.EvmDenom)
//gasPrice := sdk.ZeroDec()
if gasPrice.IsNil() {
return nil, errors.New("gas price cannot be nil")
metrics.ReportFuncError(st.svcTags)
return nil, errors.New("min gas price cannot be nil")
}
evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.BigInt(), config, params.ExtraEIPs)
@@ -176,6 +212,24 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
ret, contractAddress, leftOverGas, err = evm.Create(senderRef, st.Payload, gasLimit, st.Amount)
if err != nil {
log.WithField("simulate?", st.Simulate).
WithField("AccountNonce", st.AccountNonce).
WithField("contract", contractAddress.String()).
WithError(err).Warningln("evm contract creation failed")
}
gasConsumed := gasLimit - leftOverGas
resp = &ExecutionResult{
Response: &MsgEthereumTxResponse{
Ret: ret,
},
GasInfo: GasInfo{
GasConsumed: gasConsumed,
GasLimit: gasLimit,
GasRefunded: leftOverGas,
},
}
default:
if !params.EnableCall {
return nil, ErrCallDisabled
@@ -183,15 +237,36 @@ 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)
}
gasConsumed := gasLimit - leftOverGas
ret, leftOverGas, err = evm.Call(senderRef, *st.Recipient, st.Payload, gasLimit, st.Amount)
// fmt.Println("EVM CALL!!!", senderRef.Address().Hex(), (*st.Recipient).Hex(), gasLimit)
// fmt.Println("EVM CALL RESULT", common.ToHex(ret), leftOverGas, err)
if err != nil {
log.WithField("recipient", st.Recipient.String()).
WithError(err).Debugln("evm call failed")
}
gasConsumed := gasLimit - leftOverGas
resp = &ExecutionResult{
Response: &MsgEthereumTxResponse{
Ret: ret,
},
GasInfo: GasInfo{
GasConsumed: gasConsumed,
GasLimit: gasLimit,
GasRefunded: leftOverGas,
},
}
}
if err != nil {
// Consume gas before returning
ctx.GasMeter().ConsumeGas(gasConsumed, "evm execution consumption")
return nil, err
metrics.EVMRevertedTx(st.svcTags)
metrics.EVMGasConsumed(resp.GasInfo.GasConsumed)
ctx.GasMeter().ConsumeGas(resp.GasInfo.GasConsumed, "evm execution consumption")
return resp, err
}
// Resets nonce to value pre state transition
@@ -208,6 +283,8 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
if st.TxHash != nil && !st.Simulate {
logs, err = csdb.GetLogs(*st.TxHash)
if err != nil {
metrics.ReportFuncError(st.svcTags)
err = errors.Wrap(err, "failed to get logs")
return nil, err
}
@@ -219,38 +296,70 @@ func (st StateTransition) TransitionDb(ctx sdk.Context, config ChainConfig) (*Ex
// Finalise state if not a simulated transaction
// TODO: change to depend on config
if err := csdb.Finalise(true); err != nil {
metrics.ReportFuncError(st.svcTags)
return nil, err
}
}
res := &MsgEthereumTxResponse{
resp.Logs = logs
resp.Bloom = bloomInt
resp.Response = &MsgEthereumTxResponse{
Bloom: bloomFilter.Bytes(),
TxLogs: NewTransactionLogsFromEth(*st.TxHash, logs),
Ret: ret,
}
if contractCreation {
res.ContractAddress = contractAddress.String()
}
executionResult := &ExecutionResult{
Logs: logs,
Bloom: bloomInt,
Response: res,
GasInfo: GasInfo{
GasConsumed: gasConsumed,
GasLimit: gasLimit,
GasRefunded: leftOverGas,
},
resp.Response.ContractAddress = contractAddress.String()
}
// TODO: Refund unused gas here, if intended in future
// Consume gas from evm execution
// Out of gas check does not need to be done here since it is done within the EVM execution
ctx.WithGasMeter(currentGasMeter).GasMeter().ConsumeGas(gasConsumed, "EVM execution consumption")
metrics.EVMGasConsumed(resp.GasInfo.GasConsumed)
// TODO: @albert, @maxim, decide if can take this out, since InternalEthereumTx may want to continue execution afterwards
// which will use gas.
_ = currentGasMeter
//ctx.WithGasMeter(currentGasMeter).GasMeter().ConsumeGas(resp.GasInfo.GasConsumed, "EVM execution consumption")
return executionResult, nil
return resp, nil
}
// StaticCall executes the contract associated with the addr with the given input
// as parameters while disallowing any modifications to the state during the call.
// Opcodes that attempt to perform such modifications will result in exceptions
// instead of performing the modifications.
func (st *StateTransition) StaticCall(ctx sdk.Context, config ChainConfig) ([]byte, error) {
st.initOnce()
// This gas limit the the transaction gas limit with intrinsic gas subtracted
gasLimit := st.GasLimit - ctx.GasMeter().GasConsumed()
csdb := st.Csdb.WithContext(ctx)
// This gas meter is set up to consume gas from gaskv during evm execution and be ignored
evmGasMeter := sdk.NewInfiniteGasMeter()
csdb.WithContext(ctx.WithGasMeter(evmGasMeter))
// Clear cache of accounts to handle changes outside of the EVM
csdb.UpdateAccounts()
params := csdb.GetParams()
gasPrice := ctx.MinGasPrices().AmountOf(params.EvmDenom)
if gasPrice.IsNil() {
return []byte{}, errors.New("min gas price cannot be nil")
}
evm := st.newEVM(ctx, csdb, gasLimit, gasPrice.BigInt(), config, params.ExtraEIPs)
senderRef := vm.AccountRef(st.Sender)
ret, _, err := evm.StaticCall(senderRef, *st.Recipient, st.Payload, gasLimit)
// fmt.Println("EVM STATIC CALL!!!", senderRef.Address().Hex(), (*st.Recipient).Hex(), st.Payload, gasLimit)
// fmt.Println("EVM STATIC CALL RESULT", common.ToHex(ret), leftOverGas, err)
return ret, err
}
// HashFromContext returns the Ethereum Header hash from the context's Tendermint
+2 -151
View File
@@ -3,127 +3,21 @@ package types_test
import (
"math/big"
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"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
ethermint "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/x/evm/types"
"github.com/ethereum/go-ethereum/common"
ethcmn "github.com/ethereum/go-ethereum/common"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
)
func (suite *StateDBTestSuite) TestGetHashFn() {
testCase := []struct {
name string
height uint64
malleate func()
expEmptyHash bool
}{
// {
// "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(
// 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(
tmproto.Header{
ChainID: "ethermint-1",
Height: 100,
ValidatorsHash: []byte("val_hash"),
Version: version.Consensus{
Block: tmversion.BlockProtocol,
},
},
)
},
true,
},
{
"empty hash, case 3",
1000,
func() {
suite.ctx = suite.ctx.WithBlockHeader(
tmproto.Header{
ChainID: "ethermint-1",
Height: 100,
ValidatorsHash: []byte("val_hash"),
Version: version.Consensus{
Block: tmversion.BlockProtocol,
},
},
)
},
true,
},
}
for _, tc := range testCase {
suite.Run(tc.name, func() {
suite.SetupTest() // reset
tc.malleate()
hash := types.GetHashFn(suite.ctx, suite.stateDB)(tc.height)
if tc.expEmptyHash {
suite.Require().Equal(common.Hash{}.String(), hash.String())
} else {
suite.Require().NotEqual(common.Hash{}.String(), hash.String())
}
})
}
}
func (suite *StateDBTestSuite) TestTransitionDb() {
suite.stateDB.SetNonce(suite.address, 123)
addr := sdk.AccAddress(suite.address.Bytes())
balance := ethermint.NewPhotonCoin(sdk.NewInt(5000))
balance := ethermint.NewInjectiveCoin(sdk.NewInt(5000))
acc := suite.app.AccountKeeper.GetAccount(suite.ctx, addr)
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
suite.app.BankKeeper.SetBalance(suite.ctx, addr, balance)
@@ -228,54 +122,11 @@ func (suite *StateDBTestSuite) TestTransitionDb() {
},
false,
},
{
"call disabled",
func() {
params := types.NewParams(ethermint.AttoPhoton, true, false)
suite.stateDB.SetParams(params)
},
types.StateTransition{
AccountNonce: 123,
Price: big.NewInt(10),
GasLimit: 11,
Recipient: &recipient,
Amount: big.NewInt(50),
Payload: []byte("data"),
ChainID: big.NewInt(1),
Csdb: suite.stateDB,
TxHash: &ethcmn.Hash{},
Sender: suite.address,
Simulate: suite.ctx.IsCheckTx(),
},
false,
},
{
"create disabled",
func() {
params := types.NewParams(ethermint.AttoPhoton, false, true)
suite.stateDB.SetParams(params)
},
types.StateTransition{
AccountNonce: 123,
Price: big.NewInt(10),
GasLimit: 11,
Recipient: nil,
Amount: big.NewInt(50),
Payload: []byte("data"),
ChainID: big.NewInt(1),
Csdb: suite.stateDB,
TxHash: &ethcmn.Hash{},
Sender: suite.address,
Simulate: suite.ctx.IsCheckTx(),
},
false,
},
{
"nil gas price",
func() {
suite.stateDB.SetParams(types.DefaultParams())
invalidGas := sdk.DecCoins{
{Denom: ethermint.AttoPhoton},
{Denom: ethermint.InjectiveCoin},
}
suite.ctx = suite.ctx.WithMinGasPrices(invalidGas)
},
+40 -31
View File
@@ -122,8 +122,8 @@ func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB {
// SetHeightHash sets the block header hash associated with a given height.
func (csdb *CommitStateDB) SetHeightHash(height uint64, hash ethcmn.Hash) {
store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixHeightHash)
key := HeightHashKey(height)
store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixBlockHeightHash)
key := KeyBlockHeightHash(height)
store.Set(key, hash.Bytes())
}
@@ -135,38 +135,49 @@ 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)
so.SetBalance(amount)
if so != nil {
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)
so.AddBalance(amount)
if so != nil {
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)
so.SubBalance(amount)
if so != nil {
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)
so.SetNonce(nonce)
if so != nil {
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)
so.SetState(nil, key, value)
if so != nil {
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)
so.SetCode(ethcrypto.Keccak256Hash(code), code)
if so != nil {
so.SetCode(ethcrypto.Keccak256Hash(code), code)
}
}
// ----------------------------------------------------------------------------
@@ -289,8 +300,8 @@ func (csdb *CommitStateDB) SlotInAccessList(addr ethcmn.Address, slot ethcmn.Has
// GetHeightHash returns the block header hash associated with a given block height and chain epoch number.
func (csdb *CommitStateDB) GetHeightHash(height uint64) ethcmn.Hash {
store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixHeightHash)
key := HeightHashKey(height)
store := prefix.NewStore(csdb.ctx.KVStore(csdb.storeKey), KeyPrefixBlockHeightHash)
key := KeyBlockHeightHash(height)
bz := store.Get(key)
if len(bz) == 0 {
return ethcmn.Hash{}
@@ -300,16 +311,8 @@ 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) {
ps := &params
for _, pair := range ps.ParamSetPairs() {
if csdb.paramSpace.Has(csdb.ctx, pair.Key) {
csdb.paramSpace.Get(csdb.ctx, pair.Key, pair.Value)
}
}
csdb.paramSpace.GetParamSet(csdb.ctx, &params)
return params
}
@@ -344,10 +347,6 @@ func (csdb *CommitStateDB) BlockHash() ethcmn.Hash {
return csdb.bhash
}
func (csdb *CommitStateDB) SetBlockHash(hash ethcmn.Hash) {
csdb.bhash = hash
}
// GetCode returns the code for a given account.
func (csdb *CommitStateDB) GetCode(addr ethcmn.Address) []byte {
so := csdb.getStateObject(addr)
@@ -417,7 +416,12 @@ func (csdb *CommitStateDB) GetLogs(hash ethcmn.Hash) ([]*ethtypes.Log, error) {
return []*ethtypes.Log{}, err
}
return txLogs.EthLogs(), nil
allLogs := []*ethtypes.Log{}
for _, txLog := range txLogs.Logs {
allLogs = append(allLogs, txLog.ToEthereum())
}
return allLogs, nil
}
// AllLogs returns all the current logs in the state.
@@ -430,7 +434,10 @@ func (csdb *CommitStateDB) AllLogs() []*ethtypes.Log {
for ; iterator.Valid(); iterator.Next() {
var txLogs TransactionLogs
ModuleCdc.MustUnmarshalBinaryBare(iterator.Value(), &txLogs)
allLogs = append(allLogs, txLogs.EthLogs()...)
for _, txLog := range txLogs.Logs {
allLogs = append(allLogs, txLog.ToEthereum())
}
}
return allLogs
@@ -705,7 +712,7 @@ func (csdb *CommitStateDB) UpdateAccounts() {
for _, stateEntry := range csdb.stateObjects {
address := sdk.AccAddress(stateEntry.address.Bytes())
currAccount := csdb.accountKeeper.GetAccount(csdb.ctx, address)
ethermintAcc, ok := currAccount.(*ethermint.EthAccount)
ethAcc, ok := currAccount.(*ethermint.EthAccount)
if !ok {
continue
}
@@ -717,8 +724,8 @@ func (csdb *CommitStateDB) UpdateAccounts() {
stateEntry.stateObject.balance = balance.Amount
}
if stateEntry.stateObject.Nonce() != ethermintAcc.GetSequence() {
stateEntry.stateObject.account = ethermintAcc
if stateEntry.stateObject.Nonce() != ethAcc.GetSequence() {
stateEntry.stateObject.account = ethAcc
}
}
}
@@ -738,8 +745,9 @@ func (csdb *CommitStateDB) clearJournalAndRefund() {
// Prepare sets the current transaction hash and index and block hash which is
// used when the EVM emits new state logs.
func (csdb *CommitStateDB) Prepare(thash ethcmn.Hash, txi int) {
func (csdb *CommitStateDB) Prepare(thash, bhash ethcmn.Hash, txi int) {
csdb.thash = thash
csdb.bhash = bhash
csdb.txIndex = txi
}
@@ -867,7 +875,8 @@ 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 {
+18 -34
View File
@@ -26,7 +26,7 @@ type StateDBTestSuite struct {
suite.Suite
ctx sdk.Context
app *app.EthermintApp
app *app.InjectiveApp
stateDB *types.CommitStateDB
address ethcmn.Address
stateObject types.StateObject
@@ -40,7 +40,7 @@ func (suite *StateDBTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(checkTx)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: "ethermint-1"})
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1})
suite.stateDB = suite.app.EvmKeeper.CommitStateDB.WithContext(suite.ctx)
privkey, err := ethsecp256k1.GenerateKey()
@@ -48,7 +48,7 @@ func (suite *StateDBTestSuite) SetupTest() {
suite.address = ethcmn.BytesToAddress(privkey.PubKey().Address().Bytes())
balance := ethermint.NewPhotonCoin(sdk.ZeroInt())
balance := ethermint.NewInjectiveCoin(sdk.ZeroInt())
acc := &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0),
CodeHash: ethcrypto.Keccak256(nil),
@@ -64,32 +64,18 @@ func (suite *StateDBTestSuite) SetupTest() {
func (suite *StateDBTestSuite) TestParams() {
params := suite.stateDB.GetParams()
suite.Require().Equal(types.DefaultParams(), params)
params.EvmDenom = "ara"
params.EvmDenom = "inj"
suite.stateDB.SetParams(params)
newParams := suite.stateDB.GetParams()
suite.Require().Equal(newParams, params)
}
func (suite *StateDBTestSuite) TestGetHeightHash() {
hash := suite.stateDB.GetHeightHash(0)
suite.Require().Equal(ethcmn.Hash{}.String(), hash.String())
expHash := ethcmn.BytesToHash([]byte("hash"))
suite.stateDB.SetHeightHash(10, expHash)
hash = suite.stateDB.GetHeightHash(10)
suite.Require().Equal(expHash.String(), hash.String())
}
func (suite *StateDBTestSuite) TestBloomFilter() {
// Prepare db for logs
tHash := ethcmn.BytesToHash([]byte{0x1})
suite.stateDB.Prepare(tHash, 0)
suite.stateDB.Prepare(tHash, ethcmn.Hash{}, 0)
contractAddress := ethcmn.BigToAddress(big.NewInt(1))
log := ethtypes.Log{
Address: contractAddress,
Topics: []ethcmn.Hash{},
}
log := ethtypes.Log{Address: contractAddress}
testCase := []struct {
name string
@@ -130,8 +116,8 @@ func (suite *StateDBTestSuite) TestBloomFilter() {
}
} else {
// get logs bloom from the log
bloomBytes := ethtypes.LogsBloom(logs)
bloomFilter := ethtypes.BytesToBloom(bloomBytes)
bloomInt := ethtypes.LogsBloom(logs)
bloomFilter := ethtypes.BytesToBloom(bloomInt)
suite.Require().True(ethtypes.BloomLookup(bloomFilter, contractAddress), tc.name)
suite.Require().False(ethtypes.BloomLookup(bloomFilter, ethcmn.BigToAddress(big.NewInt(2))), tc.name)
}
@@ -306,7 +292,6 @@ 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.
@@ -433,8 +418,7 @@ func (suite *StateDBTestSuite) TestSuiteDB_Prepare() {
bhash := ethcmn.BytesToHash([]byte("bhash"))
txi := 1
suite.stateDB.Prepare(thash, txi)
suite.stateDB.SetBlockHash(bhash)
suite.stateDB.Prepare(thash, bhash, txi)
suite.Require().Equal(txi, suite.stateDB.TxIndex())
suite.Require().Equal(bhash, suite.stateDB.BlockHash())
@@ -675,7 +659,7 @@ func (suite *StateDBTestSuite) TestCommitStateDB_ForEachStorage() {
name string
malleate func()
callback func(key, value ethcmn.Hash) (stop bool)
expValues []string
expValues []ethcmn.Hash
}{
{
"aggregate state",
@@ -688,12 +672,12 @@ func (suite *StateDBTestSuite) TestCommitStateDB_ForEachStorage() {
storage = append(storage, types.NewState(key, value))
return false
},
[]string{
ethcmn.BytesToHash([]byte("value0")).String(),
ethcmn.BytesToHash([]byte("value1")).String(),
ethcmn.BytesToHash([]byte("value2")).String(),
ethcmn.BytesToHash([]byte("value3")).String(),
ethcmn.BytesToHash([]byte("value4")).String(),
[]ethcmn.Hash{
ethcmn.BytesToHash([]byte("value0")),
ethcmn.BytesToHash([]byte("value1")),
ethcmn.BytesToHash([]byte("value2")),
ethcmn.BytesToHash([]byte("value3")),
ethcmn.BytesToHash([]byte("value4")),
},
},
{
@@ -709,8 +693,8 @@ func (suite *StateDBTestSuite) TestCommitStateDB_ForEachStorage() {
}
return false
},
[]string{
ethcmn.BytesToHash([]byte("filtervalue")).String(),
[]ethcmn.Hash{
ethcmn.BytesToHash([]byte("filtervalue")),
},
},
}
+2 -3
View File
@@ -1,12 +1,11 @@
package types
import (
"bytes"
"fmt"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ethermint "github.com/cosmos/ethermint/types"
ethcmn "github.com/ethereum/go-ethereum/common"
)
@@ -51,7 +50,7 @@ func (s Storage) Copy() Storage {
// Validate performs a basic validation of the State fields.
func (s State) Validate() error {
if ethermint.IsEmptyHash(s.Key) {
if bytes.Equal(ethcmn.Hex2Bytes(s.Key), ethcmn.Hash{}.Bytes()) {
return sdkerrors.Wrap(ErrInvalidState, "state key hash cannot be empty")
}
// NOTE: state value can be empty
+1 -2
View File
@@ -80,7 +80,6 @@ func TestStorageCopy(t *testing.T) {
func TestStorageString(t *testing.T) {
storage := Storage{NewState(ethcmn.BytesToHash([]byte("key")), ethcmn.BytesToHash([]byte("value")))}
str := `key:"0x00000000000000000000000000000000000000000000000000000000006b6579" value:"0x00000000000000000000000000000000000000000000000000000076616c7565"
`
str := "key:\"0x00000000000000000000000000000000000000000000000000000000006b6579\" value:\"0x00000000000000000000000000000000000000000000000000000076616c7565\"\n"
require.Equal(t, str, storage.String())
}
+320 -802
View File
File diff suppressed because it is too large Load Diff
+38 -6
View File
@@ -5,10 +5,13 @@ import (
"fmt"
"math/big"
log "github.com/xlab/suplog"
"github.com/gogo/protobuf/proto"
"github.com/pkg/errors"
"golang.org/x/crypto/sha3"
sdk "github.com/cosmos/cosmos-sdk/types"
ethcmn "github.com/ethereum/go-ethereum/common"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
@@ -44,13 +47,42 @@ func EncodeTxResponse(res *MsgEthereumTxResponse) ([]byte, error) {
}
// 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 MsgEthereumTxResponse{}, err
func DecodeTxResponse(in []byte) (*MsgEthereumTxResponse, error) {
var txMsgData sdk.TxMsgData
if err := proto.Unmarshal(in, &txMsgData); err != nil {
log.WithError(err).Errorln("failed to unmarshal TxMsgData")
return nil, err
}
return txResponse, nil
dataList := txMsgData.GetData()
if len(dataList) == 0 {
return &MsgEthereumTxResponse{}, nil
}
var res MsgEthereumTxResponse
err := proto.Unmarshal(dataList[0].GetData(), &res)
if err != nil {
err = errors.Wrap(err, "proto.Unmarshal failed")
return nil, err
}
return &res, nil
}
// EncodeTransactionLogs encodes TransactionLogs slice into a protobuf-encoded byte slice.
func EncodeTransactionLogs(res *TransactionLogs) ([]byte, error) {
return proto.Marshal(res)
}
// DecodeTxResponse decodes an protobuf-encoded byte slice into TransactionLogs
func DecodeTransactionLogs(data []byte) (TransactionLogs, error) {
var logs TransactionLogs
err := proto.Unmarshal(data, &logs)
if err != nil {
return TransactionLogs{}, err
}
return logs, nil
}
// ----------------------------------------------------------------------------
+13 -32
View File
@@ -1,15 +1,27 @@
package types
import (
"strings"
"testing"
"github.com/cosmos/ethermint/crypto/ethsecp256k1"
"github.com/stretchr/testify/require"
ethcmn "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
)
// GenerateEthAddress generates an Ethereum address.
func GenerateEthAddress() ethcmn.Address {
priv, err := ethsecp256k1.GenerateKey()
if err != nil {
panic(err)
}
return ethcrypto.PubkeyToAddress(priv.ToECDSA().PublicKey)
}
func TestEvmDataEncoding(t *testing.T) {
addr := "0x5dE8a020088a2D6d0a23c204FFbeD02790466B49"
bloom := ethtypes.BytesToBloom([]byte{0x1, 0x3})
@@ -39,34 +51,3 @@ func TestEvmDataEncoding(t *testing.T) {
require.Equal(t, data.TxLogs, res.TxLogs)
require.Equal(t, ret, res.Ret)
}
func TestResultData_String(t *testing.T) {
const expectedResultDataStr = `ResultData:
ContractAddress: 0x5dE8a020088a2D6d0a23c204FFbeD02790466B49
Bloom: 259
Ret: [5 8]
TxHash: 0x0000000000000000000000000000000000000000000000000000000000000000
Logs:
{0x0000000000000000000000000000000000000000 [] [1 2 3 4] 17 0x0000000000000000000000000000000000000000000000000000000000000000 0 0x0000000000000000000000000000000000000000000000000000000000000000 0 false}
{0x0000000000000000000000000000000000000000 [] [5 6 7 8] 18 0x0000000000000000000000000000000000000000000000000000000000000000 0 0x0000000000000000000000000000000000000000000000000000000000000000 0 false}`
addr := ethcmn.HexToAddress("0x5dE8a020088a2D6d0a23c204FFbeD02790466B49")
bloom := ethtypes.BytesToBloom([]byte{0x1, 0x3})
ret := []byte{0x5, 0x8}
data := ResultData{
ContractAddress: addr,
Bloom: bloom,
Logs: []*ethtypes.Log{
{
Data: []byte{1, 2, 3, 4},
BlockNumber: 17,
},
{
Data: []byte{5, 6, 7, 8},
BlockNumber: 18,
}},
Ret: ret,
}
require.True(t, strings.EqualFold(expectedResultDataStr, data.String()))
}