forked from cerc-io/laconicd-deprecated
evm: change Hook to use tx Receipt (#849)
* Change evm_hook to use Transaction Receipt * use ethtypes.Receipt * wip changes * fix receipt creation * receipt fixes * check for contract addr * changelog * test Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> Co-authored-by: Federico Kunze Küllmer <federico.kunze94@gmail.com>
This commit is contained in:
co-authored by
Federico Kunze Küllmer
Federico Kunze Küllmer
parent
9f4828e5bb
commit
b9804505a3
@@ -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])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -69,7 +69,11 @@ func (suite *KeeperTestSuite) TestEvmHooks() {
|
||||
Address: suite.address,
|
||||
})
|
||||
logs := k.GetTxLogsTransient(txHash)
|
||||
result := k.PostTxProcessing(txHash, logs)
|
||||
receipt := ðtypes.Receipt{
|
||||
TxHash: txHash,
|
||||
Logs: logs,
|
||||
}
|
||||
result := k.PostTxProcessing(common.Address{}, nil, receipt)
|
||||
|
||||
tc.expFunc(hook, result)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
@@ -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)
|
||||
|
||||
@@ -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 := ðtypes.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())
|
||||
}
|
||||
}
|
||||
|
||||
// update the gas used after refund
|
||||
k.ResetGasMeterAndConsumeGas(res.GasUsed)
|
||||
return res, nil
|
||||
@@ -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() {
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user