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 6 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 = 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
}
11 changes: 11 additions & 0 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Keeper struct {
CommitStateDB *types.CommitStateDB
TxCount *count
Bloom *big.Int
CurrentLogs []*ethtypes.Log
}

// TODO: move to types
Expand Down Expand Up @@ -106,6 +107,16 @@ func (k *Keeper) GetBlockBloomMapping(ctx sdk.Context, height int64) ethtypes.Bl
return ethtypes.BytesToBloom(bloom)
}

// SetBlockLogs sets the block's logs in the KVStore
func (k *Keeper) SetBlockLogs(ctx sdk.Context, logs []*ethtypes.Log) {

}

// GetBlockLogs gets the logs for a block from the KVStore
func (k *Keeper) GetBlockLogs(ctx sdk.Context) []*ethtypes.Log {
return nil
}

// ----------------------------------------------------------------------------
// Genesis
// ----------------------------------------------------------------------------
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
39 changes: 32 additions & 7 deletions x/evm/types/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,23 @@ type StateTransition struct {
Simulate bool
}

// ReturnData represents what's returned from a transition
type ReturnData struct {
Logs []*ethtypes.Log
Bloom *big.Int
Result sdk.Result
}

// TransitionCSDB performs an evm state transition from a transaction
func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result) {
func (st StateTransition) TransitionCSDB(ctx sdk.Context) *ReturnData {
returnData := new(ReturnData)

contractCreation := st.Recipient == nil

cost, err := core.IntrinsicGas(st.Payload, contractCreation, true)
if err != nil {
return nil, sdk.ErrOutOfGas("invalid intrinsic gas for transaction").Result()
returnData.Result = sdk.ErrOutOfGas("invalid intrinsic gas for transaction").Result()
return returnData
}

// This gas limit the the transaction gas limit with intrinsic gas subtracted
Expand Down Expand Up @@ -106,25 +115,38 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
// Generate bloom filter to be saved in tx receipt data
bloomInt := big.NewInt(0)
var bloomFilter ethtypes.Bloom
var logs []*ethtypes.Log
if st.THash != nil && !st.Simulate {
logs := csdb.GetLogs(*st.THash)
logs = csdb.GetLogs(*st.THash)
bloomInt = ethtypes.LogsBloom(logs)
bloomFilter = ethtypes.BytesToBloom(bloomInt.Bytes())
}

// Encode all necessary data into slice of bytes to return in sdk result
returnData := EncodeReturnData(addr, bloomFilter, ret)
res := &ResultData{
Address: addr,
Bloom: bloomFilter,
Logs: logs,
Ret: ret,
}
resultData, err := EncodeResultData(res)
if err != nil {
// TODO: where are the ethermint error types?
//returnData.Result = sdk.Err()
noot marked this conversation as resolved.
Show resolved Hide resolved
return returnData
}

// handle errors
if vmerr != nil {
res := emint.ErrVMExecution(vmerr.Error()).Result()
if vmerr == vm.ErrOutOfGas || vmerr == vm.ErrCodeStoreOutOfGas {
res = sdk.ErrOutOfGas("EVM execution went out of gas").Result()
}
res.Data = returnData
res.Data = resultData
// Consume gas before returning
ctx.GasMeter().ConsumeGas(gasLimit-leftOverGas, "EVM execution consumption")
return nil, res
returnData.Result = res
return returnData
}

// TODO: Refund unused gas here, if intended in future
Expand All @@ -138,5 +160,8 @@ func (st StateTransition) TransitionCSDB(ctx sdk.Context) (*big.Int, sdk.Result)
// Out of gas check does not need to be done here since it is done within the EVM execution
ctx.WithGasMeter(currentGasMeter).GasMeter().ConsumeGas(gasLimit-leftOverGas, "EVM execution consumption")

return bloomInt, sdk.Result{Data: returnData, GasUsed: st.GasLimit - leftOverGas}
returnData.Logs = logs
returnData.Bloom = bloomInt
returnData.Result = sdk.Result{Data: resultData, GasUsed: st.GasLimit - leftOverGas}
return returnData
}
4 changes: 4 additions & 0 deletions x/evm/types/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ func (csdb *CommitStateDB) GetCommittedState(addr ethcmn.Address, hash ethcmn.Ha

// GetLogs returns the current logs for a given hash in the state.
func (csdb *CommitStateDB) GetLogs(hash ethcmn.Hash) []*ethtypes.Log {
// TODO: if logs aren't in the cache, then reconstruct the logs

// question: how to get transaction details and what block it was included in from the hash? assuming the input is a tx hash

return csdb.logs[hash]
}

Expand Down
Loading