Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Change evm_hook to use Transaction Receipt #849

Merged
merged 11 commits into from
Jan 3, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
6 changes: 3 additions & 3 deletions client/docs/statik/statik.go

Large diffs are not rendered by default.

1,715 changes: 79 additions & 1,636 deletions client/docs/swagger-ui/swagger.yaml

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/api/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ MsgEthereumTxResponse defines the Msg/EthereumTx response type.
| `ret` | [bytes](#bytes) | | returned data from evm function (result or data supplied with revert opcode) |
| `vm_error` | [string](#string) | | vm error is the error returned by vm execution |
| `gas_used` | [uint64](#uint64) | | gas consumed by the transaction |
| `contract_address` | [string](#string) | | hex address of the contract created / called |



Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ require (
github.com/tendermint/tm-db v0.6.4
github.com/tyler-smith/go-bip39 v1.1.0
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb
google.golang.org/grpc v1.43.0
google.golang.org/protobuf v1.27.1
gopkg.in/yaml.v2 v2.4.0
Expand Down Expand Up @@ -136,7 +136,7 @@ require (
github.com/tklauser/go-sysconf v0.3.7 // indirect
github.com/tklauser/numcpus v0.2.3 // indirect
github.com/zondax/hid v0.9.0 // indirect
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
Expand Down
11 changes: 6 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1125,8 +1125,8 @@ golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWP
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8 h1:5QRxNnVsaJP6NAse0UdkRgL3zHMvCRRkrDVLNdNpdy4=
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand Down Expand Up @@ -1227,8 +1227,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a h1:c83jeVQW0KGKNaKBRfelNYNHaev+qawl9yaA825s8XE=
golang.org/x/net v0.0.0-20211111160137-58aab5ef257a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
Expand Down Expand Up @@ -1572,8 +1572,9 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb h1:ZrsicilzPCS/Xr8qtBZZLpy4P9TYXAfl49ctG1/5tgw=
google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
Expand Down
2 changes: 2 additions & 0 deletions proto/ethermint/evm/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,6 @@ message MsgEthereumTxResponse {
string vm_error = 4;
// gas consumed by the transaction
uint64 gas_used = 5;
// hex address of the contract created / called
string contract_address = 6;
}
21 changes: 20 additions & 1 deletion types/account.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package types

import (
"bytes"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"

Expand All @@ -14,6 +16,15 @@ var (
_ codectypes.UnpackInterfacesMessage = (*EthAccount)(nil)
)

var emptyCodeHash = crypto.Keccak256(nil)

const (
// AccountTypeEOA defines the type for externally owned accounts (EOAs)
AccountTypeEOA = int8(iota + 1)
// AccountTypeContract defines the type for contract accounts
AccountTypeContract
)

// ----------------------------------------------------------------------------
// Main Ethermint account
// ----------------------------------------------------------------------------
Expand All @@ -23,7 +34,7 @@ var (
func ProtoAccount() authtypes.AccountI {
return &EthAccount{
BaseAccount: &authtypes.BaseAccount{},
CodeHash: common.BytesToHash(crypto.Keccak256(nil)).String(),
CodeHash: common.BytesToHash(emptyCodeHash).String(),
}
}

Expand All @@ -36,3 +47,11 @@ func (acc EthAccount) EthAddress() common.Address {
func (acc EthAccount) GetCodeHash() common.Hash {
return common.HexToHash(acc.CodeHash)
}

// Type returns the type of Ethereum Account (EOA or Contract)
func (acc EthAccount) Type() int8 {
if bytes.Equal(emptyCodeHash, common.Hex2Bytes(acc.CodeHash)) {
return AccountTypeEOA
}
return AccountTypeContract
}
4 changes: 2 additions & 2 deletions x/evm/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -682,13 +682,13 @@ func (suite *EvmTestSuite) TestContractDeploymentRevert() {
// DummyHook implements EvmHooks interface
type DummyHook struct{}

func (dh *DummyHook) PostTxProcessing(ctx sdk.Context, txHash common.Hash, logs []*ethtypes.Log) error {
func (dh *DummyHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
return nil
}

// FailureHook implements EvmHooks interface
type FailureHook struct{}

func (dh *FailureHook) PostTxProcessing(ctx sdk.Context, txHash common.Hash, logs []*ethtypes.Log) error {
func (dh *FailureHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
return errors.New("mock error")
}
4 changes: 2 additions & 2 deletions x/evm/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ func NewMultiEvmHooks(hooks ...types.EvmHooks) MultiEvmHooks {
}

// PostTxProcessing delegate the call to underlying hooks
func (mh MultiEvmHooks) PostTxProcessing(ctx sdk.Context, txHash common.Hash, logs []*ethtypes.Log) error {
func (mh MultiEvmHooks) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
for i := range mh {
if err := mh[i].PostTxProcessing(ctx, txHash, logs); err != nil {
if err := mh[i].PostTxProcessing(ctx, from, to, receipt); err != nil {
return sdkerrors.Wrapf(err, "EVM hook %T failed", mh[i])
}
}
Expand Down
12 changes: 8 additions & 4 deletions x/evm/keeper/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ type LogRecordHook struct {
Logs []*ethtypes.Log
}

func (dh *LogRecordHook) PostTxProcessing(ctx sdk.Context, txHash common.Hash, logs []*ethtypes.Log) error {
dh.Logs = logs
func (dh *LogRecordHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
dh.Logs = receipt.Logs
return nil
}

// FailureHook always fail
type FailureHook struct{}

func (dh FailureHook) PostTxProcessing(ctx sdk.Context, txHash common.Hash, logs []*ethtypes.Log) error {
func (dh FailureHook) PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
return errors.New("post tx processing failed")
}

Expand Down Expand Up @@ -69,7 +69,11 @@ func (suite *KeeperTestSuite) TestEvmHooks() {
Address: suite.address,
})
logs := k.GetTxLogsTransient(txHash)
result := k.PostTxProcessing(txHash, logs)
receipt := &ethtypes.Receipt{
TxHash: txHash,
Logs: logs,
}
result := k.PostTxProcessing(common.Address{}, nil, receipt)

tc.expFunc(hook, result)
}
Expand Down
4 changes: 2 additions & 2 deletions x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,11 +363,11 @@ func (k *Keeper) SetHooks(eh types.EvmHooks) *Keeper {
}

// PostTxProcessing delegate the call to the hooks. If no hook has been registered, this function returns with a `nil` error
func (k *Keeper) PostTxProcessing(txHash common.Hash, logs []*ethtypes.Log) error {
func (k *Keeper) PostTxProcessing(from common.Address, to *common.Address, receipt *ethtypes.Receipt) error {
if k.hooks == nil {
return nil
}
return k.hooks.PostTxProcessing(k.Ctx(), txHash, logs)
return k.hooks.PostTxProcessing(k.Ctx(), from, to, receipt)
}

// Tracer return a default vm.Tracer based on current keeper state
Expand Down
73 changes: 53 additions & 20 deletions x/evm/keeper/state_transition.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
"math"
"math/big"

tmtypes "github.com/tendermint/tendermint/types"
Expand Down Expand Up @@ -208,22 +209,8 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
}

res.Hash = txHash.Hex()

logs := k.GetTxLogsTransient(txHash)

if !res.Failed() {
// Only call hooks if tx executed successfully.
if err = k.PostTxProcessing(txHash, logs); err != nil {
// If hooks return error, revert the whole tx.
res.VmError = types.ErrPostTxProcessing.Error()
k.Logger(k.Ctx()).Error("tx post processing failed", "error", err)
} else if commit != nil {
// PostTxProcessing is successful, commit the cache context
commit()
ctx.EventManager().EmitEvents(k.Ctx().EventManager().Events())
}
}

// change to original context
k.WithContext(ctx)

Expand All @@ -232,16 +219,53 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
return nil, sdkerrors.Wrapf(err, "failed to refund gas leftover gas to sender %s", msg.From())
}

var bloomReceipt ethtypes.Bloom
if len(logs) > 0 {
res.Logs = types.NewLogsFromEth(logs)
// Update transient block bloom filter
bloom := k.GetBlockBloomTransient()
bloom.Or(bloom, big.NewInt(0).SetBytes(ethtypes.LogsBloom(logs)))
k.SetBlockBloomTransient(bloom)
bloomReceipt = ethtypes.BytesToBloom(bloom.Bytes())
}

k.IncreaseTxIndexTransient()

if !res.Failed() {
cumulativeGasUsed := res.GasUsed
if ctx.BlockGasMeter() != nil {
limit := ctx.BlockGasMeter().Limit()
consumed := ctx.BlockGasMeter().GasConsumed()
cumulativeGasUsed = uint64(math.Min(float64(cumulativeGasUsed+consumed), float64(limit)))
}

receipt := &ethtypes.Receipt{
Type: tx.Type(),
PostState: nil, // TODO: intermediate state root
Status: ethtypes.ReceiptStatusSuccessful,
CumulativeGasUsed: cumulativeGasUsed,
Bloom: bloomReceipt,
Logs: logs,
TxHash: txHash,
ContractAddress: common.HexToAddress(res.ContractAddress),
GasUsed: res.GasUsed,
BlockHash: common.BytesToHash(ctx.HeaderHash()),
BlockNumber: big.NewInt(ctx.BlockHeight()),
TransactionIndex: uint(k.GetTxIndexTransient()),
}

// Only call hooks if tx executed successfully.
if err = k.PostTxProcessing(msg.From(), tx.To(), receipt); err != nil {
// If hooks return error, revert the whole tx.
res.VmError = types.ErrPostTxProcessing.Error()
k.Logger(ctx).Error("tx post processing failed", "error", err)
} else if commit != nil {
// PostTxProcessing is successful, commit the cache context
commit()
ctx.EventManager().EmitEvents(k.Ctx().EventManager().Events())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hooks execution is moved under the k.WithContext(ctx), this changed the context hooks executed in.
And k.Ctx() is same as ctx here, we'll lose events emitted by hooks, and re-emit events in `ctx.

}
}

// update the gas used after refund
k.ResetGasMeterAndConsumeGas(res.GasUsed)
return res, nil
Expand Down Expand Up @@ -288,8 +312,9 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT
// If commit is true, the cache context stack will be committed, otherwise discarded.
func (k *Keeper) ApplyMessageWithConfig(msg core.Message, tracer vm.Tracer, commit bool, cfg *types.EVMConfig) (*types.MsgEthereumTxResponse, error) {
var (
ret []byte // return bytes from evm execution
vmErr error // vm errors do not effect consensus and are therefore not assigned to err
ret []byte // return bytes from evm execution
vmErr error // vm errors do not effect consensus and are therefore not assigned to err
contractAddr common.Address
)

if !k.ctxStack.IsEmpty() {
Expand Down Expand Up @@ -337,10 +362,17 @@ func (k *Keeper) ApplyMessageWithConfig(msg core.Message, tracer vm.Tracer, comm
// - reset sender's nonce to msg.Nonce() before calling evm.
// - increase sender's nonce by one no matter the result.
k.SetNonce(sender.Address(), msg.Nonce())
ret, _, leftoverGas, vmErr = evm.Create(sender, msg.Data(), leftoverGas, msg.Value())
ret, contractAddr, leftoverGas, vmErr = evm.Create(sender, msg.Data(), leftoverGas, msg.Value())
k.SetNonce(sender.Address(), msg.Nonce()+1)
} else {
ret, leftoverGas, vmErr = evm.Call(sender, *msg.To(), msg.Data(), leftoverGas, msg.Value())
to := *msg.To()
acc := k.accountKeeper.GetAccount(k.Ctx(), sdk.AccAddress(to.Bytes()))
if acc != nil {
if ethAcc, ok := acc.(*ethermint.EthAccount); ok && ethAcc.Type() == ethermint.AccountTypeContract {
contractAddr = to
}
}
}

refundQuotient := params.RefundQuotient
Expand Down Expand Up @@ -376,9 +408,10 @@ func (k *Keeper) ApplyMessageWithConfig(msg core.Message, tracer vm.Tracer, comm
}

return &types.MsgEthereumTxResponse{
GasUsed: gasUsed,
VmError: vmError,
Ret: ret,
GasUsed: gasUsed,
VmError: vmError,
Ret: ret,
ContractAddress: contractAddr.String(),
}, nil
}

Expand Down
7 changes: 3 additions & 4 deletions x/evm/types/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"

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

ethtypes "github.com/ethereum/go-ethereum/core/types"
feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types"
)

// AccountKeeper defines the expected account keeper interface
Expand Down Expand Up @@ -54,5 +53,5 @@ type FeeMarketKeeper interface {
// EvmHooks event hooks for evm tx processing
type EvmHooks interface {
// Must be called after tx is processed successfully, if return an error, the whole transaction is reverted.
PostTxProcessing(ctx sdk.Context, txHash common.Hash, logs []*ethtypes.Log) error
PostTxProcessing(ctx sdk.Context, from common.Address, to *common.Address, receipt *ethtypes.Receipt) error
}
Loading