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

Commit

Permalink
store logs in keeper after transition (#210)
Browse files Browse the repository at this point in the history
* add some comments

* begin log handler test

* update TransitionCSDB to return ReturnData

* use rlp for result data encode/decode

* update tests

* implement SetBlockLogs

* implement GetBlockLogs

* test log set/get

* update keeper get/set logs to use hash as key

* fix test

* move logsKey to csdb

* attempt to fix test

* attempt to fix test

* attempt to fix test

* lint

* lint

* lint

* save logs after handling msg

* update k.Logs

* cleanup

* remove unused

* fix issues

* comment out handler test

* address comments

* lint

* fix handler test

* address comments

* use amino

* lint

* address comments

* merge
  • Loading branch information
noot authored Mar 18, 2020
1 parent cc59134 commit d0aa494
Show file tree
Hide file tree
Showing 15 changed files with 320 additions and 151 deletions.
63 changes: 0 additions & 63 deletions go.sum

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion importer/importer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,10 @@ func applyTransaction(config *ethparams.ChainConfig, bc ethcore.ChainContext, au
receipt.ContractAddress = ethcrypto.CreateAddress(vmenv.Context.Origin, tx.Nonce())
}
// Set the receipt logs and create a bloom for filtering
receipt.Logs = statedb.GetLogs(tx.Hash())
receipt.Logs, err = statedb.GetLogs(tx.Hash())
if err != nil {
return nil, 0, err
}
receipt.Bloom = ethtypes.CreateBloom(ethtypes.Receipts{receipt})
receipt.BlockHash = statedb.BlockHash()
receipt.BlockNumber = header.Number
Expand Down
15 changes: 9 additions & 6 deletions rpc/eth_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,12 +358,12 @@ 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)
if err != nil {
return []byte{}, err
}

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

// account indicates the overriding fields of account during the execution of
Expand Down Expand Up @@ -745,7 +745,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 @@ -758,12 +761,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
5 changes: 4 additions & 1 deletion x/evm/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import (
func BeginBlock(k Keeper, ctx sdk.Context, req abci.RequestBeginBlock) {
// Consider removing this when using evm as module without web3 API
bloom := ethtypes.BytesToBloom(k.Bloom.Bytes())
k.SetBlockBloomMapping(ctx, bloom, req.Header.GetHeight()-1)
err := k.SetBlockBloomMapping(ctx, bloom, req.Header.GetHeight()-1)
if err != nil {
panic(err)
}
k.SetBlockHashMapping(ctx, req.Header.LastBlockId.GetHash(), req.Header.GetHeight()-1)
k.Bloom = big.NewInt(0)
k.TxCount = 0
Expand Down
32 changes: 19 additions & 13 deletions x/evm/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
switch msg := msg.(type) {
case types.MsgEthereumTx:
return handleEthTxMsg(ctx, k, msg)
case *types.MsgEthermint:
return handleMsgEthermint(ctx, k, *msg)
return HandleEthTxMsg(ctx, k, msg)
case types.MsgEthermint:
return HandleMsgEthermint(ctx, k, msg)
default:
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized ethermint message type: %T", msg)
}
}
}

// handleEthTxMsg handles an Ethereum specific tx
func handleEthTxMsg(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*sdk.Result, error) {
// HandleEthTxMsg handles an Ethereum specific tx
func HandleEthTxMsg(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*sdk.Result, error) {
// parse the chainID from a string to a base-10 integer
intChainID, ok := new(big.Int).SetString(ctx.ChainID(), 10)
if !ok {
Expand Down Expand Up @@ -69,13 +69,19 @@ func handleEthTxMsg(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*sdk.Re
k.TxCount++

// TODO: move to keeper
bloom, res, err := st.TransitionCSDB(ctx)
returnData, err := st.TransitionCSDB(ctx)
if err != nil {
return nil, err
}

// update block bloom filter
k.Bloom.Or(k.Bloom, bloom)
k.Bloom.Or(k.Bloom, returnData.Bloom)

// update transaction logs in KVStore
err = k.SetTransactionLogs(ctx, returnData.Logs, txHash)
if err != nil {
return nil, err
}

ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
Expand All @@ -99,11 +105,11 @@ func handleEthTxMsg(ctx sdk.Context, k Keeper, msg types.MsgEthereumTx) (*sdk.Re
}

// set the events to the result
res.Events = ctx.EventManager().Events()
return res, nil
returnData.Result.Events = ctx.EventManager().Events()
return returnData.Result, nil
}

func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk.Result, error) {
func HandleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk.Result, error) {
// parse the chainID from a string to a base-10 integer
intChainID, ok := new(big.Int).SetString(ctx.ChainID(), 10)
if !ok {
Expand Down Expand Up @@ -131,7 +137,7 @@ func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk
k.CommitStateDB.Prepare(common.Hash{}, common.Hash{}, k.TxCount) // Cannot provide tx hash
k.TxCount++

_, res, err := st.TransitionCSDB(ctx)
returnData, err := st.TransitionCSDB(ctx)
if err != nil {
return nil, err
}
Expand All @@ -158,6 +164,6 @@ func handleMsgEthermint(ctx sdk.Context, k Keeper, msg types.MsgEthermint) (*sdk
}

// set the events to the result
res.Events = ctx.EventManager().Events()
return res, nil
returnData.Result.Events = ctx.EventManager().Events()
return returnData.Result, nil
}
89 changes: 89 additions & 0 deletions x/evm/handler_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package evm_test

import (
"math/big"
"testing"
"time"

"github.com/stretchr/testify/suite"

sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"

"github.com/cosmos/ethermint/app"
"github.com/cosmos/ethermint/x/evm"
"github.com/cosmos/ethermint/x/evm/types"

abci "github.com/tendermint/tendermint/abci/types"
)

type EvmTestSuite struct {
suite.Suite

ctx sdk.Context
handler sdk.Handler
app *app.EthermintApp
}

func (suite *EvmTestSuite) SetupTest() {
checkTx := false

suite.app = app.Setup(checkTx)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, abci.Header{Height: 1, ChainID: "3", Time: time.Now().UTC()})
suite.handler = evm.NewHandler(suite.app.EvmKeeper)
}

func TestEvmTestSuite(t *testing.T) {
suite.Run(t, new(EvmTestSuite))
}

func (suite *EvmTestSuite) TestHandler_Logs() {
// Test contract:

// 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;;;;;;"
// }

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

priv, err := crypto.GenerateKey()
suite.Require().NoError(err, "failed to create key")

bytecode := common.FromHex("0x6080604052348015600f57600080fd5b5060117f775a94827b8fd9b519d36cd827093c664f93347070a554f65e4a6f56cd73889860405160405180910390a2603580604b6000396000f3fe6080604052600080fdfea165627a7a723058206cab665f0f557620554bb45adf266708d2bd349b8a4314bdff205ee8440e3c240029")
tx := types.NewMsgEthereumTx(1, nil, big.NewInt(0), gasLimit, gasPrice, bytecode)
tx.Sign(big.NewInt(3), priv)

result, err := evm.HandleEthTxMsg(suite.ctx, suite.app.EvmKeeper, *tx)
suite.Require().NoError(err, "failed to handle eth tx msg")

resultData, err := types.DecodeResultData(result.Data)
suite.Require().NoError(err, "failed to decode result data")

suite.Require().Equal(len(resultData.Logs), 1)
suite.Require().Equal(len(resultData.Logs[0].Topics), 2)

hash := []byte{1}
err = suite.app.EvmKeeper.SetTransactionLogs(suite.ctx, resultData.Logs, hash)
suite.Require().NoError(err, "failed to set logs")

logs, err := suite.app.EvmKeeper.GetTransactionLogs(suite.ctx, hash)
suite.Require().NoError(err, "failed to get logs")

suite.Require().Equal(logs, resultData.Logs)
}
62 changes: 49 additions & 13 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 Down Expand Up @@ -72,23 +73,53 @@ func (k *Keeper) GetBlockHashMapping(ctx sdk.Context, hash []byte) (height int64
// ----------------------------------------------------------------------------

// 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.blockKey)
heightHash := k.cdc.MustMarshalBinaryLengthPrefixed(height)
if !bytes.Equal(heightHash, []byte{}) {
store.Set(heightHash, bloom.Bytes())
if len(heightHash) == 0 {
return fmt.Errorf("block with bloombits %v not found", bloom)
}
store.Set(types.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.blockKey)
heightHash := k.cdc.MustMarshalBinaryLengthPrefixed(height)
bloom := store.Get(heightHash)
if bytes.Equal(heightHash, []byte{}) {
panic(fmt.Errorf("block with bloombits %s not found", bloom))
if len(heightHash) == 0 {
return ethtypes.BytesToBloom([]byte{}), fmt.Errorf("block with height %d not found", height)
}
return ethtypes.BytesToBloom(bloom)

bloom := store.Get(types.BloomKey(heightHash))
if len(bloom) == 0 {
return ethtypes.BytesToBloom([]byte{}), fmt.Errorf("block with bloombits %v not found", bloom)
}

return ethtypes.BytesToBloom(bloom), nil
}

// SetBlockLogs sets the transaction's logs in the KVStore
func (k *Keeper) SetTransactionLogs(ctx sdk.Context, logs []*ethtypes.Log, hash []byte) error {
store := ctx.KVStore(k.blockKey)
encLogs, err := types.EncodeLogs(logs)
if err != nil {
return err
}
store.Set(types.LogsKey(hash), encLogs)

return nil
}

// GetBlockLogs gets the logs for a transaction from the KVStore
func (k *Keeper) GetTransactionLogs(ctx sdk.Context, hash []byte) ([]*ethtypes.Log, error) {
store := ctx.KVStore(k.blockKey)
encLogs := store.Get(types.LogsKey(hash))
if len(encLogs) == 0 {
return nil, errors.New("cannot get transaction logs")
}

return types.DecodeLogs(encLogs)
}

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -210,13 +241,18 @@ func (k *Keeper) GetCommittedState(ctx sdk.Context, addr ethcmn.Address, hash et
}

// GetLogs calls CommitStateDB.GetLogs using the passed in context
func (k *Keeper) GetLogs(ctx sdk.Context, hash ethcmn.Hash) []*ethtypes.Log {
return k.CommitStateDB.WithContext(ctx).GetLogs(hash)
func (k *Keeper) GetLogs(ctx sdk.Context, hash ethcmn.Hash) ([]*ethtypes.Log, error) {
logs, err := k.CommitStateDB.WithContext(ctx).GetLogs(hash)
if err != nil {
return nil, err
}

return logs, nil
}

// Logs calls CommitStateDB.Logs using the passed in context
func (k *Keeper) Logs(ctx sdk.Context) []*ethtypes.Log {
return k.CommitStateDB.WithContext(ctx).Logs()
// AllLogs calls CommitStateDB.AllLogs using the passed in context
func (k *Keeper) AllLogs(ctx sdk.Context) []*ethtypes.Log {
return k.CommitStateDB.WithContext(ctx).AllLogs()
}

// GetRefund calls CommitStateDB.GetRefund using the passed in context
Expand Down
10 changes: 6 additions & 4 deletions x/evm/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ func (suite *KeeperTestSuite) TestDBStorage() {

// Test block height mapping functionality
testBloom := ethtypes.BytesToBloom([]byte{0x1, 0x3})
suite.app.EvmKeeper.SetBlockBloomMapping(suite.ctx, testBloom, 4)
err := suite.app.EvmKeeper.SetBlockBloomMapping(suite.ctx, testBloom, 4)
suite.Require().NoError(err, "failed to set block bloom mapping")

// Get those state transitions
suite.Require().Equal(suite.app.EvmKeeper.GetBalance(suite.ctx, address).Cmp(big.NewInt(5)), 0)
Expand All @@ -64,11 +65,12 @@ func (suite *KeeperTestSuite) TestDBStorage() {

suite.Require().Equal(suite.app.EvmKeeper.GetBlockHashMapping(suite.ctx, ethcmn.FromHex("0x0d87a3a5f73140f46aac1bf419263e4e94e87c292f25007700ab7f2060e2af68")), int64(7))
suite.Require().Equal(suite.app.EvmKeeper.GetBlockHashMapping(suite.ctx, []byte{0x43, 0x32}), int64(8))

suite.Require().Equal(suite.app.EvmKeeper.GetBlockBloomMapping(suite.ctx, 4), testBloom)
bloom, err := suite.app.EvmKeeper.GetBlockBloomMapping(suite.ctx, 4)
suite.Require().NoError(err)
suite.Require().Equal(bloom, testBloom)

// commit stateDB
_, err := suite.app.EvmKeeper.Commit(suite.ctx, false)
_, err = suite.app.EvmKeeper.Commit(suite.ctx, false)
suite.Require().NoError(err, "failed to commit StateDB")

// simulate BaseApp EndBlocker commitment
Expand Down
Loading

0 comments on commit d0aa494

Please sign in to comment.