Skip to content

Commit 9cb1976

Browse files
committed
Update gas estimation to account for SetCode authorizations list
1 parent 9c316b3 commit 9cb1976

7 files changed

Lines changed: 185 additions & 86 deletions

File tree

api/api.go

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -562,18 +562,13 @@ func (b *BlockChainAPI) Call(
562562
return handleError[hexutil.Bytes](err, l, b.collector)
563563
}
564564

565-
tx, err := encodeTxFromArgs(args)
566-
if err != nil {
567-
return handleError[hexutil.Bytes](err, l, b.collector)
568-
}
569-
570565
// Default address in case user does not provide one
571566
from := b.config.Coinbase
572567
if args.From != nil {
573568
from = *args.From
574569
}
575570

576-
res, err := b.evm.Call(tx, from, height, stateOverrides, blockOverrides)
571+
res, err := b.evm.Call(args, from, height, stateOverrides, blockOverrides)
577572
if err != nil {
578573
return handleError[hexutil.Bytes](err, l, b.collector)
579574
}
@@ -722,11 +717,6 @@ func (b *BlockChainAPI) EstimateGas(
722717
return handleError[hexutil.Uint64](err, l, b.collector)
723718
}
724719

725-
tx, err := encodeTxFromArgs(args)
726-
if err != nil {
727-
return hexutil.Uint64(BlockGasLimit), nil // return block gas limit
728-
}
729-
730720
// Default address in case user does not provide one
731721
from := b.config.Coinbase
732722
if args.From != nil {
@@ -742,7 +732,7 @@ func (b *BlockChainAPI) EstimateGas(
742732
return handleError[hexutil.Uint64](err, l, b.collector)
743733
}
744734

745-
estimatedGas, err := b.evm.EstimateGas(tx, from, height, stateOverrides)
735+
estimatedGas, err := b.evm.EstimateGas(args, from, height, stateOverrides)
746736
if err != nil {
747737
return handleError[hexutil.Uint64](err, l, b.collector)
748738
}

api/debug.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/onflow/flow-go/fvm/evm/offchain/query"
1212
"github.com/onflow/flow-go/fvm/evm/types"
1313
gethCommon "github.com/onflow/go-ethereum/common"
14+
gethTypes "github.com/onflow/go-ethereum/core/types"
1415
"github.com/onflow/go-ethereum/eth/tracers"
1516
"github.com/onflow/go-ethereum/eth/tracers/logger"
1617
gethParams "github.com/onflow/go-ethereum/params"
@@ -39,7 +40,7 @@ import (
3940
// txTraceResult is the result of a single transaction trace.
4041
type txTraceResult struct {
4142
TxHash gethCommon.Hash `json:"txHash"` // transaction hash
42-
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
43+
Result any `json:"result,omitempty"` // Trace results produced by the tracer
4344
Error string `json:"error,omitempty"` // Trace failure produced by the tracer
4445
}
4546

@@ -135,15 +136,12 @@ func (d *DebugAPI) TraceCall(
135136
args ethTypes.TransactionArgs,
136137
blockNrOrHash rpc.BlockNumberOrHash,
137138
config *tracers.TraceCallConfig,
138-
) (interface{}, error) {
139+
) (any, error) {
139140
if err := d.rateLimiter.Apply(ctx, "TraceCall"); err != nil {
140141
return nil, err
141142
}
142143

143-
tx, err := encodeTxFromArgs(args)
144-
if err != nil {
145-
return nil, err
146-
}
144+
tx := args.ToTransaction(gethTypes.LegacyTxType, BlockGasLimit)
147145

148146
// Default address in case user does not provide one
149147
from := d.config.Coinbase
@@ -203,8 +201,8 @@ func (d *DebugAPI) TraceCall(
203201
}
204202

205203
to := gethCommon.Address{}
206-
if tx.To != nil {
207-
to = *tx.To
204+
if tx.To() != nil {
205+
to = *tx.To()
208206
}
209207
rca := requester.NewRemoteCadenceArch(cdcHeight, d.client, d.config.FlowNetworkID)
210208

@@ -241,9 +239,9 @@ func (d *DebugAPI) TraceCall(
241239
_, err = view.DryCall(
242240
from,
243241
to,
244-
tx.Data,
245-
tx.Value,
246-
tx.Gas,
242+
tx.Data(),
243+
tx.Value(),
244+
tx.Gas(),
247245
opts...,
248246
)
249247
if err != nil {

api/utils.go

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,13 @@ import (
44
"encoding/hex"
55
"errors"
66
"fmt"
7-
"math/big"
87
"strings"
98

10-
ethTypes "github.com/onflow/flow-evm-gateway/eth/types"
119
"github.com/onflow/flow-evm-gateway/metrics"
1210
errs "github.com/onflow/flow-evm-gateway/models/errors"
1311
"github.com/onflow/flow-evm-gateway/storage"
1412
"github.com/onflow/go-ethereum/common"
1513
"github.com/onflow/go-ethereum/core"
16-
"github.com/onflow/go-ethereum/core/types"
1714
"github.com/onflow/go-ethereum/rpc"
1815
"github.com/rs/zerolog"
1916
)
@@ -139,45 +136,3 @@ func handleError[T any](err error, log zerolog.Logger, collector metrics.Collect
139136
return zero, err
140137
}
141138
}
142-
143-
// encodeTxFromArgs will create a transaction from the given arguments.
144-
// The resulting unsigned transaction is only supposed to be used through
145-
// `EVM.dryRun` inside Cadence scripts, meaning that no state change
146-
// will occur.
147-
// This is only useful for `eth_estimateGas` and `eth_call` endpoints.
148-
func encodeTxFromArgs(args ethTypes.TransactionArgs) (*types.DynamicFeeTx, error) {
149-
var data []byte
150-
if args.Data != nil {
151-
data = *args.Data
152-
} else if args.Input != nil {
153-
data = *args.Input
154-
}
155-
156-
// provide a high enough gas for the tx to be able to execute,
157-
// capped by the gas set in transaction args.
158-
gasLimit := BlockGasLimit
159-
if args.Gas != nil {
160-
gasLimit = uint64(*args.Gas)
161-
}
162-
163-
value := big.NewInt(0)
164-
if args.Value != nil {
165-
value = args.Value.ToInt()
166-
}
167-
168-
accessList := types.AccessList{}
169-
if args.AccessList != nil {
170-
accessList = *args.AccessList
171-
}
172-
173-
return &types.DynamicFeeTx{
174-
Nonce: 0,
175-
To: args.To,
176-
Value: value,
177-
Gas: gasLimit,
178-
Data: data,
179-
GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas),
180-
GasFeeCap: (*big.Int)(args.MaxFeePerGas),
181-
AccessList: accessList,
182-
}, nil
183-
}

eth/types/types.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ import (
66
"fmt"
77
"math/big"
88

9+
"github.com/holiman/uint256"
910
"github.com/onflow/flow-evm-gateway/models"
1011
errs "github.com/onflow/flow-evm-gateway/models/errors"
1112

1213
"github.com/onflow/go-ethereum/common"
1314
"github.com/onflow/go-ethereum/common/hexutil"
1415
"github.com/onflow/go-ethereum/core/types"
16+
"github.com/onflow/go-ethereum/crypto/kzg4844"
1517
)
1618

1719
// TransactionArgs represents the arguments to construct a new transaction
@@ -35,6 +37,18 @@ type TransactionArgs struct {
3537
// Introduced by AccessListTxType transaction.
3638
AccessList *types.AccessList `json:"accessList,omitempty"`
3739
ChainID *hexutil.Big `json:"chainId,omitempty"`
40+
41+
// For BlobTxType
42+
BlobFeeCap *hexutil.Big `json:"maxFeePerBlobGas"`
43+
BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
44+
45+
// For BlobTxType transactions with blob sidecar
46+
Blobs []kzg4844.Blob `json:"blobs"`
47+
Commitments []kzg4844.Commitment `json:"commitments"`
48+
Proofs []kzg4844.Proof `json:"proofs"`
49+
50+
// For SetCodeTxType
51+
AuthorizationList []types.SetCodeAuthorization `json:"authorizationList"`
3852
}
3953

4054
func (txArgs TransactionArgs) Validate() error {
@@ -86,6 +100,141 @@ func (txArgs TransactionArgs) Validate() error {
86100
return nil
87101
}
88102

103+
// ToTransaction converts the arguments to a transaction.
104+
func (txArgs TransactionArgs) ToTransaction(
105+
defaultType int,
106+
defaultGas uint64,
107+
) *types.Transaction {
108+
nonce := uint64(0)
109+
if txArgs.Nonce != nil {
110+
nonce = uint64(*txArgs.Nonce)
111+
}
112+
113+
if txArgs.Gas == nil {
114+
gas := hexutil.Uint64(defaultGas)
115+
txArgs.Gas = &gas
116+
}
117+
118+
usedType := types.LegacyTxType
119+
switch {
120+
case txArgs.AuthorizationList != nil || defaultType == types.SetCodeTxType:
121+
usedType = types.SetCodeTxType
122+
case txArgs.BlobHashes != nil || defaultType == types.BlobTxType:
123+
usedType = types.BlobTxType
124+
case txArgs.MaxFeePerGas != nil || defaultType == types.DynamicFeeTxType:
125+
usedType = types.DynamicFeeTxType
126+
case txArgs.AccessList != nil || defaultType == types.AccessListTxType:
127+
usedType = types.AccessListTxType
128+
}
129+
// Make it possible to default to newer tx, but use legacy if gasprice is provided
130+
if txArgs.GasPrice != nil {
131+
usedType = types.LegacyTxType
132+
}
133+
var data types.TxData
134+
switch usedType {
135+
case types.SetCodeTxType:
136+
al := types.AccessList{}
137+
if txArgs.AccessList != nil {
138+
al = *txArgs.AccessList
139+
}
140+
authList := []types.SetCodeAuthorization{}
141+
if txArgs.AuthorizationList != nil {
142+
authList = txArgs.AuthorizationList
143+
}
144+
data = &types.SetCodeTx{
145+
To: *txArgs.To,
146+
ChainID: uint256.MustFromBig(txArgs.ChainID.ToInt()),
147+
Nonce: nonce,
148+
Gas: uint64(*txArgs.Gas),
149+
GasFeeCap: uint256.MustFromBig((*big.Int)(txArgs.MaxFeePerGas)),
150+
GasTipCap: uint256.MustFromBig((*big.Int)(txArgs.MaxPriorityFeePerGas)),
151+
Value: uint256.MustFromBig((*big.Int)(txArgs.Value)),
152+
Data: txArgs.data(),
153+
AccessList: al,
154+
AuthList: authList,
155+
}
156+
157+
case types.BlobTxType:
158+
al := types.AccessList{}
159+
if txArgs.AccessList != nil {
160+
al = *txArgs.AccessList
161+
}
162+
data = &types.BlobTx{
163+
To: *txArgs.To,
164+
ChainID: uint256.MustFromBig((*big.Int)(txArgs.ChainID)),
165+
Nonce: nonce,
166+
Gas: uint64(*txArgs.Gas),
167+
GasFeeCap: uint256.MustFromBig((*big.Int)(txArgs.MaxFeePerGas)),
168+
GasTipCap: uint256.MustFromBig((*big.Int)(txArgs.MaxPriorityFeePerGas)),
169+
Value: uint256.MustFromBig((*big.Int)(txArgs.Value)),
170+
Data: txArgs.data(),
171+
AccessList: al,
172+
BlobHashes: txArgs.BlobHashes,
173+
BlobFeeCap: uint256.MustFromBig((*big.Int)(txArgs.BlobFeeCap)),
174+
}
175+
if txArgs.Blobs != nil {
176+
data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{
177+
Blobs: txArgs.Blobs,
178+
Commitments: txArgs.Commitments,
179+
Proofs: txArgs.Proofs,
180+
}
181+
}
182+
183+
case types.DynamicFeeTxType:
184+
al := types.AccessList{}
185+
if txArgs.AccessList != nil {
186+
al = *txArgs.AccessList
187+
}
188+
data = &types.DynamicFeeTx{
189+
To: txArgs.To,
190+
ChainID: (*big.Int)(txArgs.ChainID),
191+
Nonce: nonce,
192+
Gas: uint64(*txArgs.Gas),
193+
GasFeeCap: (*big.Int)(txArgs.MaxFeePerGas),
194+
GasTipCap: (*big.Int)(txArgs.MaxPriorityFeePerGas),
195+
Value: (*big.Int)(txArgs.Value),
196+
Data: txArgs.data(),
197+
AccessList: al,
198+
}
199+
200+
case types.AccessListTxType:
201+
data = &types.AccessListTx{
202+
To: txArgs.To,
203+
ChainID: (*big.Int)(txArgs.ChainID),
204+
Nonce: nonce,
205+
Gas: uint64(*txArgs.Gas),
206+
GasPrice: (*big.Int)(txArgs.GasPrice),
207+
Value: (*big.Int)(txArgs.Value),
208+
Data: txArgs.data(),
209+
AccessList: *txArgs.AccessList,
210+
}
211+
212+
default:
213+
data = &types.LegacyTx{
214+
To: txArgs.To,
215+
Nonce: nonce,
216+
Gas: uint64(*txArgs.Gas),
217+
GasPrice: (*big.Int)(txArgs.GasPrice),
218+
Value: (*big.Int)(txArgs.Value),
219+
Data: txArgs.data(),
220+
}
221+
}
222+
223+
return types.NewTx(data)
224+
}
225+
226+
// data retrieves the transaction calldata. Input field is preferred.
227+
func (txArgs *TransactionArgs) data() []byte {
228+
if txArgs.Input != nil {
229+
return *txArgs.Input
230+
}
231+
if txArgs.Data != nil {
232+
return *txArgs.Data
233+
}
234+
235+
return nil
236+
}
237+
89238
// AccessListResult returns an optional accesslist
90239
// It's the result of the `debug_createAccessList` RPC call.
91240
// It contains an error if the transaction itself failed.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ require (
66
github.com/cockroachdb/pebble v1.1.2
77
github.com/goccy/go-json v0.10.4
88
github.com/hashicorp/go-multierror v1.1.1
9+
github.com/holiman/uint256 v1.3.2
910
github.com/onflow/atree v0.9.0
1011
github.com/onflow/cadence v1.3.3
1112
github.com/onflow/flow-go v0.39.3-unsafe-cdp.0.0.20250410112831-d5fdbe30ff6d
@@ -93,7 +94,6 @@ require (
9394
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
9495
github.com/hashicorp/hcl v1.0.0 // indirect
9596
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
96-
github.com/holiman/uint256 v1.3.2 // indirect
9797
github.com/huandu/go-clone v1.6.0 // indirect
9898
github.com/huandu/go-clone/generic v1.7.2 // indirect
9999
github.com/huin/goupnp v1.3.0 // indirect

0 commit comments

Comments
 (0)