Skip to content

Commit

Permalink
fix(eth): proper gas calculation for eth_getBlockReceipts (#12514)
Browse files Browse the repository at this point in the history
  • Loading branch information
rvagg authored Sep 26, 2024
1 parent c965d7d commit f8857f1
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 43 deletions.
8 changes: 8 additions & 0 deletions itests/eth_deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 4 additions & 0 deletions itests/fevm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
26 changes: 17 additions & 9 deletions node/impl/full/eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,20 @@ 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)
ts, err := a.Chain.GetTipSetFromKey(ctx, msgLookup.TipSet)
if err != nil {
return nil, xerrors.Errorf("failed to lookup tipset %s when constructing the eth txn receipt: %w", msgLookup.TipSet, err)
}

// The tx is located in the parent tipset
parentTs, err := a.Chain.LoadTipSet(ctx, ts.Parents())
if err != nil {
return nil, xerrors.Errorf("failed to lookup tipset %s when constructing the eth txn receipt: %w", ts.Parents(), err)
}

baseFee := parentTs.Blocks()[0].ParentBaseFee

receipt, err := newEthTxReceipt(ctx, tx, baseFee, msgLookup.Receipt, a.EthEventHandler)
if err != nil {
return nil, xerrors.Errorf("failed to create Eth receipt: %w", err)
}
Expand Down Expand Up @@ -575,23 +588,18 @@ func (a *EthModule) EthGetBlockReceiptsLimited(ctx context.Context, blockParam e
return nil, xerrors.Errorf("failed to load state tree: %w", err)
}

baseFee := ts.Blocks()[0].ParentBaseFee

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, baseFee, receipts[i], a.EthEventHandler)
if err != nil {
return nil, xerrors.Errorf("failed to create Eth receipt: %w", err)
}
Expand Down
54 changes: 20 additions & 34 deletions node/impl/full/eth_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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, baseFee big.Int, msgReceipt types.MessageReceipt, ev *EthEventHandler) (api.EthTxReceipt, error) {
var (
transactionIndex ethtypes.EthUint64
blockHash ethtypes.EthHash
Expand All @@ -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,
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down

0 comments on commit f8857f1

Please sign in to comment.