Skip to content
This repository has been archived by the owner on Nov 30, 2021. It is now read-only.

store logs in keeper after transition #210

Merged
merged 37 commits into from
Mar 18, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
fe5cfe5
add some comments
noot Mar 4, 2020
d00e3c6
begin log handler test
noot Mar 9, 2020
496edc2
update TransitionCSDB to return ReturnData
noot Mar 11, 2020
57eaae2
use rlp for result data encode/decode
noot Mar 11, 2020
beaccb4
update tests
noot Mar 11, 2020
dec0d62
merge with development
noot Mar 11, 2020
b4df9f9
implement SetBlockLogs
noot Mar 13, 2020
11d7add
implement GetBlockLogs
noot Mar 13, 2020
5a6f4e1
test log set/get
noot Mar 13, 2020
ce5e4a4
Merge branch 'development' of github.com:ChainSafe/ethermint into noo…
noot Mar 13, 2020
7b0d0bf
update keeper get/set logs to use hash as key
noot Mar 13, 2020
5869475
fix test
noot Mar 13, 2020
d668e7b
move logsKey to csdb
noot Mar 13, 2020
1ed2483
attempt to fix test
noot Mar 13, 2020
a8fee1d
attempt to fix test
noot Mar 13, 2020
b5cf096
attempt to fix test
noot Mar 13, 2020
9114d47
lint
noot Mar 13, 2020
6741a87
lint
noot Mar 13, 2020
d5fce93
lint
noot Mar 13, 2020
5bbf735
save logs after handling msg
noot Mar 13, 2020
e66bf4c
update k.Logs
noot Mar 13, 2020
ebf52d3
cleanup
noot Mar 16, 2020
79e9b76
remove unused
noot Mar 16, 2020
bcbd905
fix issues
noot Mar 16, 2020
bd493e7
merge wtih development
noot Mar 16, 2020
0202547
merge with version bump
noot Mar 17, 2020
e285fd0
comment out handler test
noot Mar 17, 2020
e11b238
merge with development
noot Mar 17, 2020
045e41a
address comments
noot Mar 17, 2020
7f47916
lint
noot Mar 17, 2020
a22277e
fix handler test
noot Mar 17, 2020
6a9e1bf
address comments
noot Mar 17, 2020
5e615f4
use amino
noot Mar 17, 2020
22e16bf
lint
noot Mar 17, 2020
a9ecb7f
address comments
noot Mar 18, 2020
977f06f
merge
noot Mar 18, 2020
4a8e64a
merge
noot Mar 18, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions rpc/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,9 @@ func (e *PublicEthAPI) Call(args CallArgs, blockNr rpc.BlockNumber, overrides *m
return []byte{}, err
}

_, _, ret, err := types.DecodeReturnData(result.Data)
data, err := types.DecodeResultData(result.Data)

return (hexutil.Bytes)(ret), err
return (hexutil.Bytes)(data.Ret), err
}

// account indicates the overriding fields of account during the execution of
Expand Down Expand Up @@ -727,7 +727,10 @@ func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]inter
e.cliCtx.Codec.MustUnmarshalJSON(res, &logs)

txData := tx.TxResult.GetData()
contractAddress, bloomFilter, _, _ := types.DecodeReturnData(txData)
data, err := types.DecodeResultData(txData)
if err != nil {
return nil, err
}

fields := map[string]interface{}{
"blockHash": blockHash,
Expand All @@ -740,12 +743,12 @@ func (e *PublicEthAPI) GetTransactionReceipt(hash common.Hash) (map[string]inter
"cumulativeGasUsed": nil, // ignore until needed
"contractAddress": nil,
"logs": logs.Logs,
"logsBloom": bloomFilter,
"logsBloom": data.Bloom,
"status": status,
}

if contractAddress != (common.Address{}) {
fields["contractAddress"] = contractAddress
if data.Address != (common.Address{}) {
fields["contractAddress"] = data.Address
}

return fields, nil
Expand Down
25 changes: 25 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package utils

import (
"encoding/hex"
"errors"
"strings"
)

// HexToBytes turns a 0x prefixed hex string into a byte slice
func HexToBytes(in string) ([]byte, error) {
if len(in) < 2 {
return nil, errors.New("invalid string")
}

if strings.Compare(in[:2], "0x") != 0 {
return nil, errors.New("could not byteify non 0x prefixed string")
}
// Ensure we have an even length, otherwise hex.DecodeString will fail and return zero hash
if len(in)%2 != 0 {
return nil, errors.New("cannot decode a odd length string")
}
in = in[2:]
out, err := hex.DecodeString(in)
return out, err
}
26 changes: 16 additions & 10 deletions x/evm/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import (
func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case types.EthereumTxMsg:
case *types.EthereumTxMsg:
return handleETHTxMsg(ctx, k, msg)
case *types.EmintMsg:
return handleEmintMsg(ctx, k, *msg)
return handleEmintMsg(ctx, k, msg)
default:
errMsg := fmt.Sprintf("Unrecognized ethermint Msg type: %v", msg.Type())
return sdk.ErrUnknownRequest(errMsg).Result()
Expand All @@ -30,7 +30,7 @@ func NewHandler(k Keeper) sdk.Handler {
}

// Handle an Ethereum specific tx
func handleETHTxMsg(ctx sdk.Context, k Keeper, msg types.EthereumTxMsg) sdk.Result {
func handleETHTxMsg(ctx sdk.Context, k Keeper, msg *types.EthereumTxMsg) sdk.Result {
noot marked this conversation as resolved.
Show resolved Hide resolved
if err := msg.ValidateBasic(); err != nil {
return err.Result()
}
Expand All @@ -56,6 +56,10 @@ func handleETHTxMsg(ctx sdk.Context, k Keeper, msg types.EthereumTxMsg) sdk.Resu
txHash := tmtypes.Tx(txBytes).Hash()
ethHash := common.BytesToHash(txHash)

if k.CommitStateDB == nil {
noot marked this conversation as resolved.
Show resolved Hide resolved
panic("keeper.CommitStateDB is nil")
}

st := types.StateTransition{
Sender: sender,
AccountNonce: msg.Data.AccountNonce,
Expand All @@ -73,14 +77,16 @@ func handleETHTxMsg(ctx sdk.Context, k Keeper, msg types.EthereumTxMsg) sdk.Resu
k.CommitStateDB.Prepare(ethHash, common.Hash{}, k.TxCount.Get())
k.TxCount.Increment()

bloom, res := st.TransitionCSDB(ctx)
if res.IsOK() {
k.Bloom.Or(k.Bloom, bloom)
returnData := st.TransitionCSDB(ctx)
if returnData.Result.IsOK() {
k.Bloom.Or(k.Bloom, returnData.Bloom)
k.CurrentLogs = append(k.CurrentLogs, returnData.Logs...)
}
return res

return returnData.Result
}

func handleEmintMsg(ctx sdk.Context, k Keeper, msg types.EmintMsg) sdk.Result {
func handleEmintMsg(ctx sdk.Context, k Keeper, msg *types.EmintMsg) sdk.Result {
noot marked this conversation as resolved.
Show resolved Hide resolved
if err := msg.ValidateBasic(); err != nil {
return err.Result()
}
Expand Down Expand Up @@ -112,6 +118,6 @@ func handleEmintMsg(ctx sdk.Context, k Keeper, msg types.EmintMsg) sdk.Result {
k.CommitStateDB.Prepare(common.Hash{}, common.Hash{}, k.TxCount.Get()) // Cannot provide tx hash
k.TxCount.Increment()

_, res := st.TransitionCSDB(ctx)
return res
returnData := st.TransitionCSDB(ctx)
return returnData.Result
}
112 changes: 112 additions & 0 deletions x/evm/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package evm

import (
"math/big"
"testing"

"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/ethermint/crypto"
"github.com/cosmos/ethermint/types"
eminttypes "github.com/cosmos/ethermint/types"
"github.com/cosmos/ethermint/utils"
evmtypes "github.com/cosmos/ethermint/x/evm/types"
ethcmn "github.com/ethereum/go-ethereum/common"
abci "github.com/tendermint/tendermint/abci/types"
tmlog "github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db"
)

// pragma solidity ^0.5.1;

// contract Test {
// event Hello(uint256 indexed world);

// constructor() public {
// emit Hello(17);
// }
// }

// {
// "linkReferences": {},
// "object": "6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029",
// "opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH1 0xF JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x11 PUSH32 0x775A94827B8FD9B519D36CD827093C664F93347070A554F65E4A6F56CD738898 PUSH1 0x40 MLOAD PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 LOG2 PUSH1 0x35 DUP1 PUSH1 0x4B PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x0 DUP1 REVERT INVALID LOG1 PUSH6 0x627A7A723058 KECCAK256 PUSH13 0xAB665F0F557620554BB45ADF26 PUSH8 0x8D2BD349B8A4314 0xbd SELFDESTRUCT KECCAK256 0x5e 0xe8 DIFFICULTY 0xe EXTCODECOPY 0x24 STOP 0x29 ",
// "sourceMap": "25:119:0:-;;;90:52;8:9:-1;5:2;;;30:1;27;20:12;5:2;90:52:0;132:2;126:9;;;;;;;;;;25:119;;;;;;"
// }

var (
address = ethcmn.HexToAddress("0x756F45E3FA69347A9A973A725E3C98bC4db0b4c1")
noot marked this conversation as resolved.
Show resolved Hide resolved

accKey = sdk.NewKVStoreKey("acc")
storageKey = sdk.NewKVStoreKey(evmtypes.EvmStoreKey)
codeKey = sdk.NewKVStoreKey(evmtypes.EvmCodeKey)
blockKey = sdk.NewKVStoreKey(evmtypes.EvmBlockKey)

logger = tmlog.NewNopLogger()
)

func newTestCodec() *codec.Codec {
cdc := codec.New()

evmtypes.RegisterCodec(cdc)
types.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)

return cdc
}

func TestHandler_Logs(t *testing.T) {
noot marked this conversation as resolved.
Show resolved Hide resolved
// create logger, codec and root multi-store
cdc := newTestCodec()

// The ParamsKeeper handles parameter storage for the application
keyParams := sdk.NewKVStoreKey(params.StoreKey)
tkeyParams := sdk.NewTransientStoreKey(params.TStoreKey)
paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace)
// Set specific supspaces
authSubspace := paramsKeeper.Subspace(auth.DefaultParamspace)
ak := auth.NewAccountKeeper(cdc, accKey, authSubspace, eminttypes.ProtoBaseAccount)
ek := NewKeeper(ak, storageKey, codeKey, blockKey, cdc)

gasLimit := uint64(100000)
gasPrice := big.NewInt(1000000)

priv1, _ := crypto.GenerateKey()

bytecode, err := utils.HexToBytes("0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029")
noot marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
t.Fatal(err)
}

tx := evmtypes.NewEthereumTxMsg(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode)
tx.Sign(big.NewInt(1), priv1.ToECDSA())

db := dbm.NewMemDB()
cms := store.NewCommitMultiStore(db)
// mount stores
keys := []*sdk.KVStoreKey{accKey, storageKey, codeKey, blockKey}
for _, key := range keys {
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, nil)
}

err = cms.LoadLatestVersion()
if err != nil {
t.Fatal(err)
}

ms := cms.CacheMultiStore()
ctx := sdk.NewContext(ms, abci.Header{}, false, logger)
ctx = ctx.WithBlockHeight(1).WithChainID("1")

result := handleETHTxMsg(ctx, ek, tx)
t.Log(result.Data)
t.Log(ek.Bloom)
t.Log(ek.CurrentLogs)

// TODO: assert that we can set/get logs from the keeper
}
63 changes: 56 additions & 7 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"bytes"
"errors"
"fmt"

"github.com/cosmos/cosmos-sdk/codec"
Expand All @@ -28,6 +29,7 @@ type Keeper struct {
CommitStateDB *types.CommitStateDB
TxCount *count
Bloom *big.Int
CurrentLogs []*ethtypes.Log
}

// TODO: move to types
Expand Down Expand Up @@ -86,24 +88,71 @@ func (k *Keeper) GetBlockHashMapping(ctx sdk.Context, hash []byte) (height int64
// May be removed when using only as module (only required by rpc api)
// ----------------------------------------------------------------------------

var bloomPrefix = []byte("bloom")
var logsPrefix = []byte("logs")
noot marked this conversation as resolved.
Show resolved Hide resolved

func bloomKey(key []byte) []byte {
return append(bloomPrefix, key...)
}

func logsKey(key []byte) []byte {
noot marked this conversation as resolved.
Show resolved Hide resolved
return append(logsPrefix, key...)
}

// SetBlockBloomMapping sets the mapping from block height to bloom bits
func (k *Keeper) SetBlockBloomMapping(ctx sdk.Context, bloom ethtypes.Bloom, height int64) {
func (k *Keeper) SetBlockBloomMapping(ctx sdk.Context, bloom ethtypes.Bloom, height int64) error {
store := ctx.KVStore(k.storeKey)
heightHash := k.cdc.MustMarshalBinaryLengthPrefixed(height)
if !bytes.Equal(heightHash, []byte{}) {
store.Set(heightHash, bloom.Bytes())
if bytes.Equal(heightHash, []byte{}) {
noot marked this conversation as resolved.
Show resolved Hide resolved
return fmt.Errorf("block with bloombits %s not found", bloom)
noot marked this conversation as resolved.
Show resolved Hide resolved
noot marked this conversation as resolved.
Show resolved Hide resolved
}
store.Set(bloomKey(heightHash), bloom.Bytes())
return nil
}

// GetBlockBloomMapping gets bloombits from block height
func (k *Keeper) GetBlockBloomMapping(ctx sdk.Context, height int64) ethtypes.Bloom {
func (k *Keeper) GetBlockBloomMapping(ctx sdk.Context, height int64) (ethtypes.Bloom, error) {
store := ctx.KVStore(k.storeKey)
heightHash := k.cdc.MustMarshalBinaryLengthPrefixed(height)
bloom := store.Get(heightHash)
if bytes.Equal(heightHash, []byte{}) {
panic(fmt.Errorf("block with bloombits %s not found", bloom))
return ethtypes.BytesToBloom([]byte{}), fmt.Errorf("block with height %d not found", height)
}
return ethtypes.BytesToBloom(bloom)

bloom := store.Get(bloomKey(heightHash))
if bytes.Equal(bloom, []byte{}) {
return ethtypes.BytesToBloom([]byte{}), fmt.Errorf("block with bloombits %s not found", bloom)
}

return ethtypes.BytesToBloom(bloom), nil
}

// SetBlockLogs sets the block's logs in the KVStore
func (k *Keeper) SetBlockLogs(ctx sdk.Context, logs []*ethtypes.Log, height int64) error {
store := ctx.KVStore(k.storeKey)
heightHash := k.cdc.MustMarshalBinaryLengthPrefixed(height)
if len(heightHash) == 0 {
return errors.New("cannot set block logs")
}

encLogs, err := types.EncodeLogs(logs)
if err != nil {
return err
}
store.Set(heightHash, encLogs)

return nil
}

// GetBlockLogs gets the logs for a block from the KVStore
func (k *Keeper) GetBlockLogs(ctx sdk.Context, height int64) ([]*ethtypes.Log, error) {
store := ctx.KVStore(k.storeKey)
heightHash := k.cdc.MustMarshalBinaryLengthPrefixed(height)
encLogs := store.Get(heightHash)
if len(encLogs) == 0 {
return nil, errors.New("cannot get block logs")
}

return types.DecodeLogs(encLogs)
}

// ----------------------------------------------------------------------------
Expand Down
6 changes: 5 additions & 1 deletion x/evm/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,11 @@ func TestDBStorage(t *testing.T) {
require.Equal(t, ek.GetBlockHashMapping(ctx, ethcmn.FromHex("0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68")), int64(7))
require.Equal(t, ek.GetBlockHashMapping(ctx, []byte{0x43, 0x32}), int64(8))

require.Equal(t, ek.GetBlockBloomMapping(ctx, 4), testBloom)
bloom, err := ek.GetBlockBloomMapping(ctx, 4)
if err != nil {
t.Fatal(err)
}
noot marked this conversation as resolved.
Show resolved Hide resolved
require.Equal(t, bloom, testBloom)

// commit stateDB
_, err = ek.Commit(ctx, false)
Expand Down
5 changes: 4 additions & 1 deletion x/evm/keeper/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,10 @@ func queryBlockLogsBloom(ctx sdk.Context, path []string, keeper Keeper) ([]byte,
panic("could not unmarshall block number: " + err.Error())
}

bloom := keeper.GetBlockBloomMapping(ctx, num)
bloom, err := keeper.GetBlockBloomMapping(ctx, num)
if err != nil {
panic("failed to get block bloom mapping: " + err.Error())
noot marked this conversation as resolved.
Show resolved Hide resolved
noot marked this conversation as resolved.
Show resolved Hide resolved
}

bRes := types.QueryBloomFilter{Bloom: bloom}
res, err := codec.MarshalJSONIndent(keeper.cdc, bRes)
Expand Down
2 changes: 1 addition & 1 deletion x/evm/types/msg_encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func unmarshalAmino(td *EncodableTxData, text string) (err error) {
}

// MarshalAmino defines custom encoding scheme for TxData
func (td TxData) MarshalAmino() (string, error) {
func (td *TxData) MarshalAmino() (string, error) {
e := EncodableTxData{
AccountNonce: td.AccountNonce,
Price: utils.MarshalBigInt(td.Price),
Expand Down
Loading