Skip to content

Commit 0be9d76

Browse files
lightclientbobpkr
andauthored
internal/ethapi: rework setDefaults for tx args so fee logic is separate (#25197)
Co-authored-by: bobpkr <[email protected]>
1 parent 366d216 commit 0be9d76

File tree

2 files changed

+410
-50
lines changed

2 files changed

+410
-50
lines changed

internal/ethapi/transaction_args.go

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -75,56 +75,8 @@ func (args *TransactionArgs) data() []byte {
7575

7676
// setDefaults fills in default values for unspecified tx fields.
7777
func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
78-
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
79-
return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
80-
}
81-
// After london, default to 1559 unless gasPrice is set
82-
head := b.CurrentHeader()
83-
// If user specifies both maxPriorityfee and maxFee, then we do not
84-
// need to consult the chain for defaults. It's definitely a London tx.
85-
if args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil {
86-
// In this clause, user left some fields unspecified.
87-
if b.ChainConfig().IsLondon(head.Number) && args.GasPrice == nil {
88-
if args.MaxPriorityFeePerGas == nil {
89-
tip, err := b.SuggestGasTipCap(ctx)
90-
if err != nil {
91-
return err
92-
}
93-
args.MaxPriorityFeePerGas = (*hexutil.Big)(tip)
94-
}
95-
if args.MaxFeePerGas == nil {
96-
gasFeeCap := new(big.Int).Add(
97-
(*big.Int)(args.MaxPriorityFeePerGas),
98-
new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
99-
)
100-
args.MaxFeePerGas = (*hexutil.Big)(gasFeeCap)
101-
}
102-
if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
103-
return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
104-
}
105-
} else {
106-
if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil {
107-
return errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet")
108-
}
109-
if args.GasPrice == nil {
110-
price, err := b.SuggestGasTipCap(ctx)
111-
if err != nil {
112-
return err
113-
}
114-
if b.ChainConfig().IsLondon(head.Number) {
115-
// The legacy tx gas price suggestion should not add 2x base fee
116-
// because all fees are consumed, so it would result in a spiral
117-
// upwards.
118-
price.Add(price, head.BaseFee)
119-
}
120-
args.GasPrice = (*hexutil.Big)(price)
121-
}
122-
}
123-
} else {
124-
// Both maxPriorityfee and maxFee set by caller. Sanity-check their internal relation
125-
if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
126-
return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
127-
}
78+
if err := args.setFeeDefaults(ctx, b); err != nil {
79+
return err
12880
}
12981
if args.Value == nil {
13082
args.Value = new(hexutil.Big)
@@ -178,6 +130,72 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
178130
return nil
179131
}
180132

133+
// setFeeDefaults fills in default fee values for unspecified tx fields.
134+
func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) error {
135+
// If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error.
136+
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
137+
return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
138+
}
139+
// If the tx has completely specified a fee mechanism, no default is needed. This allows users
140+
// who are not yet synced past London to get defaults for other tx values. See
141+
// https://github.com/ethereum/go-ethereum/pull/23274 for more information.
142+
eip1559ParamsSet := args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil
143+
if (args.GasPrice != nil && !eip1559ParamsSet) || (args.GasPrice == nil && eip1559ParamsSet) {
144+
// Sanity check the EIP-1559 fee parameters if present.
145+
if args.GasPrice == nil && args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
146+
return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
147+
}
148+
return nil
149+
}
150+
// Now attempt to fill in default value depending on whether London is active or not.
151+
head := b.CurrentHeader()
152+
if b.ChainConfig().IsLondon(head.Number) {
153+
// London is active, set maxPriorityFeePerGas and maxFeePerGas.
154+
if err := args.setLondonFeeDefaults(ctx, head, b); err != nil {
155+
return err
156+
}
157+
} else {
158+
if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil {
159+
return fmt.Errorf("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active")
160+
}
161+
// London not active, set gas price.
162+
price, err := b.SuggestGasTipCap(ctx)
163+
if err != nil {
164+
return err
165+
}
166+
args.GasPrice = (*hexutil.Big)(price)
167+
}
168+
return nil
169+
}
170+
171+
// setLondonFeeDefaults fills in reasonable default fee values for unspecified fields.
172+
func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *types.Header, b Backend) error {
173+
// Set maxPriorityFeePerGas if it is missing.
174+
if args.MaxPriorityFeePerGas == nil {
175+
tip, err := b.SuggestGasTipCap(ctx)
176+
if err != nil {
177+
return err
178+
}
179+
args.MaxPriorityFeePerGas = (*hexutil.Big)(tip)
180+
}
181+
// Set maxFeePerGas if it is missing.
182+
if args.MaxFeePerGas == nil {
183+
// Set the max fee to be 2 times larger than the previous block's base fee.
184+
// The additional slack allows the tx to not become invalidated if the base
185+
// fee is rising.
186+
val := new(big.Int).Add(
187+
args.MaxPriorityFeePerGas.ToInt(),
188+
new(big.Int).Mul(head.BaseFee, big.NewInt(2)),
189+
)
190+
args.MaxFeePerGas = (*hexutil.Big)(val)
191+
}
192+
// Both EIP-1559 fee parameters are now set; sanity check them.
193+
if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
194+
return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
195+
}
196+
return nil
197+
}
198+
181199
// ToMessage converts the transaction arguments to the Message type used by the
182200
// core evm. This method is used in calls and traces that do not require a real
183201
// live transaction.

0 commit comments

Comments
 (0)