feat: eth: Avoid StateCompute in EthTxnReceipt lookup (#10460)
Instead: 1. Use the receipt from the message search. 2. Re-compute the gas fees that would have been charged. fixes #10418 Co-authored-by: raulk <raul.kripalani@gmail.com>
This commit is contained in:
parent
afa36d3f62
commit
73a2b4152b
@ -39,6 +39,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/store"
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -427,20 +428,15 @@ func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtype
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, c)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var events []types.Event
|
var events []types.Event
|
||||||
if rct := replay.MsgRct; rct != nil && rct.EventsRoot != nil {
|
if rct := msgLookup.Receipt; rct.EventsRoot != nil {
|
||||||
events, err = a.ChainAPI.ChainGetEvents(ctx, *rct.EventsRoot)
|
events, err = a.ChainAPI.ChainGetEvents(ctx, *rct.EventsRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
receipt, err := newEthTxReceipt(ctx, tx, replay, events, a.StateAPI)
|
receipt, err := newEthTxReceipt(ctx, tx, msgLookup, events, a.Chain, a.StateAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -2046,7 +2042,7 @@ func newEthTxFromMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, tx
|
|||||||
return tx, nil
|
return tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, replay *api.InvocResult, events []types.Event, sa StateAPI) (api.EthTxReceipt, error) {
|
func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLookup, events []types.Event, cs *store.ChainStore, sa StateAPI) (api.EthTxReceipt, error) {
|
||||||
var (
|
var (
|
||||||
transactionIndex ethtypes.EthUint64
|
transactionIndex ethtypes.EthUint64
|
||||||
blockHash ethtypes.EthHash
|
blockHash ethtypes.EthHash
|
||||||
@ -2075,25 +2071,34 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, replay *api.InvocRe
|
|||||||
LogsBloom: ethtypes.EmptyEthBloom[:],
|
LogsBloom: ethtypes.EmptyEthBloom[:],
|
||||||
}
|
}
|
||||||
|
|
||||||
if replay.MsgRct.ExitCode.IsSuccess() {
|
if lookup.Receipt.ExitCode.IsSuccess() {
|
||||||
receipt.Status = 1
|
receipt.Status = 1
|
||||||
}
|
} else {
|
||||||
if replay.MsgRct.ExitCode.IsError() {
|
|
||||||
receipt.Status = 0
|
receipt.Status = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
receipt.GasUsed = ethtypes.EthUint64(replay.MsgRct.GasUsed)
|
receipt.GasUsed = ethtypes.EthUint64(lookup.Receipt.GasUsed)
|
||||||
|
|
||||||
// TODO: handle CumulativeGasUsed
|
// TODO: handle CumulativeGasUsed
|
||||||
receipt.CumulativeGasUsed = ethtypes.EmptyEthInt
|
receipt.CumulativeGasUsed = ethtypes.EmptyEthInt
|
||||||
|
|
||||||
effectiveGasPrice := big.Div(replay.GasCost.TotalCost, big.NewInt(replay.MsgRct.GasUsed))
|
// TODO: avoid loading the tipset twice (once here, once when we convert the message to a txn)
|
||||||
|
ts, err := cs.GetTipSetFromKey(ctx, lookup.TipSet)
|
||||||
|
if err != nil {
|
||||||
|
return api.EthTxReceipt{}, xerrors.Errorf("failed to lookup tipset %s when constructing the eth txn receipt: %w", lookup.TipSet, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
baseFee := ts.Blocks()[0].ParentBaseFee
|
||||||
|
gasOutputs := vm.ComputeGasOutputs(lookup.Receipt.GasUsed, int64(tx.Gas), baseFee, big.Int(tx.MaxFeePerGas), big.Int(tx.MaxPriorityFeePerGas), true)
|
||||||
|
totalSpent := big.Sum(gasOutputs.BaseFeeBurn, gasOutputs.MinerTip, gasOutputs.OverEstimationBurn)
|
||||||
|
|
||||||
|
effectiveGasPrice := big.Div(totalSpent, big.NewInt(lookup.Receipt.GasUsed))
|
||||||
receipt.EffectiveGasPrice = ethtypes.EthBigInt(effectiveGasPrice)
|
receipt.EffectiveGasPrice = ethtypes.EthBigInt(effectiveGasPrice)
|
||||||
|
|
||||||
if receipt.To == nil && replay.MsgRct.ExitCode.IsSuccess() {
|
if receipt.To == nil && lookup.Receipt.ExitCode.IsSuccess() {
|
||||||
// Create and Create2 return the same things.
|
// Create and Create2 return the same things.
|
||||||
var ret eam.CreateExternalReturn
|
var ret eam.CreateExternalReturn
|
||||||
if err := ret.UnmarshalCBOR(bytes.NewReader(replay.MsgRct.Return)); err != nil {
|
if err := ret.UnmarshalCBOR(bytes.NewReader(lookup.Receipt.Return)); err != nil {
|
||||||
return api.EthTxReceipt{}, xerrors.Errorf("failed to parse contract creation result: %w", err)
|
return api.EthTxReceipt{}, xerrors.Errorf("failed to parse contract creation result: %w", err)
|
||||||
}
|
}
|
||||||
addr := ethtypes.EthAddress(ret.EthAddress)
|
addr := ethtypes.EthAddress(ret.EthAddress)
|
||||||
|
Loading…
Reference in New Issue
Block a user