From 972158b595aae2fd2f24d844a3c4b18b1bdbd4e0 Mon Sep 17 00:00:00 2001 From: Rod Vagg Date: Thu, 26 Sep 2024 15:03:37 +1000 Subject: [PATCH] fix(eth): proper gas calculation for eth_getBlockReceipts --- itests/eth_deploy_test.go | 8 ++++++ itests/fevm_test.go | 4 +++ node/impl/full/eth.go | 21 ++++++++------- node/impl/full/eth_utils.go | 54 ++++++++++++++----------------------- 4 files changed, 44 insertions(+), 43 deletions(-) diff --git a/itests/eth_deploy_test.go b/itests/eth_deploy_test.go index 13d2742c7ea..6f5e67af3cf 100644 --- a/itests/eth_deploy_test.go +++ b/itests/eth_deploy_test.go @@ -153,7 +153,15 @@ func TestDeployment(t *testing.T) { } } require.NotNil(t, matchingReceipt, "No matching receipt found") + + require.NotNil(t, receipt.ContractAddress) + require.NotNil(t, matchingReceipt.ContractAddress) + require.Equal(t, *receipt.ContractAddress, *matchingReceipt.ContractAddress) + originalReceiptContractAddress := receipt.ContractAddress + receipt.ContractAddress = nil + matchingReceipt.ContractAddress = nil require.Equal(t, receipt, matchingReceipt) + receipt.ContractAddress = originalReceiptContractAddress // logs must be an empty array, not a nil value, to avoid tooling compatibility issues require.Empty(t, receipt.Logs) diff --git a/itests/fevm_test.go b/itests/fevm_test.go index 8830bd6c664..78bac325d20 100644 --- a/itests/fevm_test.go +++ b/itests/fevm_test.go @@ -1157,6 +1157,10 @@ func TestEthGetBlockReceipts(t *testing.T) { if i > 0 { require.Equal(t, blockReceipts[i-1].BlockHash, receipt.BlockHash, "All receipts should have the same block hash") } + + txReceipt, err := client.EthGetTransactionReceipt(ctx, receipt.TransactionHash) + require.NoError(t, err) + require.Equal(t, txReceipt, receipt) } } diff --git a/node/impl/full/eth.go b/node/impl/full/eth.go index d8d0779aefe..166fccaa051 100644 --- a/node/impl/full/eth.go +++ b/node/impl/full/eth.go @@ -527,7 +527,12 @@ func (a *EthModule) EthGetTransactionReceiptLimited(ctx context.Context, txHash return nil, xerrors.Errorf("failed to convert %s into an Eth Txn: %w", txHash, err) } - receipt, err := newEthTxReceipt(ctx, tx, msgLookup, a.ChainAPI, a.EthEventHandler) + parentTs, err := a.Chain.GetTipSetFromKey(ctx, msgLookup.TipSet) + if err != nil { + return nil, xerrors.Errorf("failed to load parent tipset: %w", err) + } + + receipt, err := newEthTxReceipt(ctx, tx, parentTs, parentTs.Blocks()[0].ParentBaseFee, msgLookup.Receipt, a.ChainAPI, a.EthEventHandler) if err != nil { return nil, xerrors.Errorf("failed to create Eth receipt: %w", err) } @@ -575,23 +580,21 @@ func (a *EthModule) EthGetBlockReceiptsLimited(ctx context.Context, blockParam e return nil, xerrors.Errorf("failed to load state tree: %w", err) } + baseFee, err := a.StateManager.ChainStore().ComputeBaseFee(ctx, ts) + if err != nil { + return nil, xerrors.Errorf("failed to compute base fee: %w", err) + } + ethReceipts := make([]*api.EthTxReceipt, 0, len(msgs)) for i, msg := range msgs { msg := msg - msgLookup := &api.MsgLookup{ - Message: msg.Cid(), - Receipt: receipts[i], - TipSet: ts.Key(), - Height: ts.Height(), - } - tx, err := newEthTx(ctx, a.Chain, stateTree, ts.Height(), tsCid, msg.Cid(), i) if err != nil { return nil, xerrors.Errorf("failed to create EthTx: %w", err) } - receipt, err := newEthTxReceipt(ctx, tx, msgLookup, a.ChainAPI, a.EthEventHandler) + receipt, err := newEthTxReceipt(ctx, tx, ts, baseFee, receipts[i], a.ChainAPI, a.EthEventHandler) if err != nil { return nil, xerrors.Errorf("failed to create Eth receipt: %w", err) } diff --git a/node/impl/full/eth_utils.go b/node/impl/full/eth_utils.go index 20422cf94bf..0c9cb32192c 100644 --- a/node/impl/full/eth_utils.go +++ b/node/impl/full/eth_utils.go @@ -679,7 +679,7 @@ func newEthTx(ctx context.Context, cs *store.ChainStore, st *state.StateTree, bl return tx, nil } -func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLookup, ca ChainAPI, ev *EthEventHandler) (api.EthTxReceipt, error) { +func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, parentTs *types.TipSet, baseFee big.Int, msgReceipt types.MessageReceipt, ca ChainAPI, ev *EthEventHandler) (api.EthTxReceipt, error) { var ( transactionIndex ethtypes.EthUint64 blockHash ethtypes.EthHash @@ -696,7 +696,7 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook blockNumber = *tx.BlockNumber } - receipt := api.EthTxReceipt{ + txReceipt := api.EthTxReceipt{ TransactionHash: tx.Hash, From: tx.From, To: tx.To, @@ -708,30 +708,16 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook LogsBloom: ethtypes.NewEmptyEthBloom(), } - if lookup.Receipt.ExitCode.IsSuccess() { - receipt.Status = 1 + if msgReceipt.ExitCode.IsSuccess() { + txReceipt.Status = 1 } else { - receipt.Status = 0 + txReceipt.Status = 0 } - receipt.GasUsed = ethtypes.EthUint64(lookup.Receipt.GasUsed) + txReceipt.GasUsed = ethtypes.EthUint64(msgReceipt.GasUsed) // TODO: handle CumulativeGasUsed - receipt.CumulativeGasUsed = ethtypes.EmptyEthInt - - // TODO: avoid loading the tipset twice (once here, once when we convert the message to a txn) - ts, err := ca.Chain.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) - } - - // The tx is located in the parent tipset - parentTs, err := ca.Chain.LoadTipSet(ctx, ts.Parents()) - if err != nil { - return api.EthTxReceipt{}, xerrors.Errorf("failed to lookup tipset %s when constructing the eth txn receipt: %w", ts.Parents(), err) - } - - baseFee := parentTs.Blocks()[0].ParentBaseFee + txReceipt.CumulativeGasUsed = ethtypes.EmptyEthInt gasFeeCap, err := tx.GasFeeCap() if err != nil { @@ -742,44 +728,44 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook return api.EthTxReceipt{}, xerrors.Errorf("failed to get gas premium: %w", err) } - gasOutputs := vm.ComputeGasOutputs(lookup.Receipt.GasUsed, int64(tx.Gas), baseFee, big.Int(gasFeeCap), + gasOutputs := vm.ComputeGasOutputs(msgReceipt.GasUsed, int64(tx.Gas), baseFee, big.Int(gasFeeCap), big.Int(gasPremium), true) totalSpent := big.Sum(gasOutputs.BaseFeeBurn, gasOutputs.MinerTip, gasOutputs.OverEstimationBurn) effectiveGasPrice := big.Zero() - if lookup.Receipt.GasUsed > 0 { - effectiveGasPrice = big.Div(totalSpent, big.NewInt(lookup.Receipt.GasUsed)) + if msgReceipt.GasUsed > 0 { + effectiveGasPrice = big.Div(totalSpent, big.NewInt(msgReceipt.GasUsed)) } - receipt.EffectiveGasPrice = ethtypes.EthBigInt(effectiveGasPrice) + txReceipt.EffectiveGasPrice = ethtypes.EthBigInt(effectiveGasPrice) - if receipt.To == nil && lookup.Receipt.ExitCode.IsSuccess() { + if txReceipt.To == nil && msgReceipt.ExitCode.IsSuccess() { // Create and Create2 return the same things. var ret eam.CreateExternalReturn - if err := ret.UnmarshalCBOR(bytes.NewReader(lookup.Receipt.Return)); err != nil { + if err := ret.UnmarshalCBOR(bytes.NewReader(msgReceipt.Return)); err != nil { return api.EthTxReceipt{}, xerrors.Errorf("failed to parse contract creation result: %w", err) } addr := ethtypes.EthAddress(ret.EthAddress) - receipt.ContractAddress = &addr + txReceipt.ContractAddress = &addr } - if rct := lookup.Receipt; rct.EventsRoot != nil { + if rct := msgReceipt; rct.EventsRoot != nil { logs, err := ev.getEthLogsForBlockAndTransaction(ctx, &blockHash, tx.Hash) if err != nil { return api.EthTxReceipt{}, xerrors.Errorf("failed to get eth logs for block and transaction: %w", err) } if len(logs) > 0 { - receipt.Logs = logs + txReceipt.Logs = logs } } - for _, log := range receipt.Logs { + for _, log := range txReceipt.Logs { for _, topic := range log.Topics { - ethtypes.EthBloomSet(receipt.LogsBloom, topic[:]) + ethtypes.EthBloomSet(txReceipt.LogsBloom, topic[:]) } - ethtypes.EthBloomSet(receipt.LogsBloom, log.Address[:]) + ethtypes.EthBloomSet(txReceipt.LogsBloom, log.Address[:]) } - return receipt, nil + return txReceipt, nil } func encodeFilecoinParamsAsABI(method abi.MethodNum, codec uint64, params []byte) []byte {