github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/internal/ethapi/transaction_args.go (about) 1 // Copyright 2021 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package ethapi 18 19 import ( 20 "bytes" 21 "context" 22 "crypto/sha256" 23 "errors" 24 "fmt" 25 "math/big" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/hexutil" 29 "github.com/ethereum/go-ethereum/common/math" 30 "github.com/ethereum/go-ethereum/consensus/misc/eip4844" 31 "github.com/ethereum/go-ethereum/core" 32 "github.com/ethereum/go-ethereum/core/types" 33 "github.com/ethereum/go-ethereum/crypto/kzg4844" 34 "github.com/ethereum/go-ethereum/log" 35 "github.com/ethereum/go-ethereum/params" 36 "github.com/ethereum/go-ethereum/rpc" 37 "github.com/holiman/uint256" 38 ) 39 40 var ( 41 maxBlobsPerTransaction = params.MaxBlobGasPerBlock / params.BlobTxBlobGasPerBlob 42 ) 43 44 // TransactionArgs represents the arguments to construct a new transaction 45 // or a message call. 46 type TransactionArgs struct { 47 From *common.Address `json:"from"` 48 To *common.Address `json:"to"` 49 Gas *hexutil.Uint64 `json:"gas"` 50 GasPrice *hexutil.Big `json:"gasPrice"` 51 MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` 52 MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` 53 Value *hexutil.Big `json:"value"` 54 Nonce *hexutil.Uint64 `json:"nonce"` 55 56 // We accept "data" and "input" for backwards-compatibility reasons. 57 // "input" is the newer name and should be preferred by clients. 58 // Issue detail: https://github.com/ethereum/go-ethereum/issues/15628 59 Data *hexutil.Bytes `json:"data"` 60 Input *hexutil.Bytes `json:"input"` 61 62 // Introduced by AccessListTxType transaction. 63 AccessList *types.AccessList `json:"accessList,omitempty"` 64 ChainID *hexutil.Big `json:"chainId,omitempty"` 65 66 // For BlobTxType 67 BlobFeeCap *hexutil.Big `json:"maxFeePerBlobGas"` 68 BlobHashes []common.Hash `json:"blobVersionedHashes,omitempty"` 69 70 // For BlobTxType transactions with blob sidecar 71 Blobs []kzg4844.Blob `json:"blobs"` 72 Commitments []kzg4844.Commitment `json:"commitments"` 73 Proofs []kzg4844.Proof `json:"proofs"` 74 75 // This configures whether blobs are allowed to be passed. 76 blobSidecarAllowed bool 77 } 78 79 // from retrieves the transaction sender address. 80 func (args *TransactionArgs) from() common.Address { 81 if args.From == nil { 82 return common.Address{} 83 } 84 return *args.From 85 } 86 87 // data retrieves the transaction calldata. Input field is preferred. 88 func (args *TransactionArgs) data() []byte { 89 if args.Input != nil { 90 return *args.Input 91 } 92 if args.Data != nil { 93 return *args.Data 94 } 95 return nil 96 } 97 98 // setDefaults fills in default values for unspecified tx fields. 99 func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend, skipGasEstimation bool) error { 100 if err := args.setBlobTxSidecar(ctx); err != nil { 101 return err 102 } 103 if err := args.setFeeDefaults(ctx, b); err != nil { 104 return err 105 } 106 107 if args.Value == nil { 108 args.Value = new(hexutil.Big) 109 } 110 if args.Nonce == nil { 111 nonce, err := b.GetPoolNonce(ctx, args.from()) 112 if err != nil { 113 return err 114 } 115 args.Nonce = (*hexutil.Uint64)(&nonce) 116 } 117 if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { 118 return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`) 119 } 120 121 // BlobTx fields 122 if args.BlobHashes != nil && len(args.BlobHashes) == 0 { 123 return errors.New(`need at least 1 blob for a blob transaction`) 124 } 125 if args.BlobHashes != nil && len(args.BlobHashes) > maxBlobsPerTransaction { 126 return fmt.Errorf(`too many blobs in transaction (have=%d, max=%d)`, len(args.BlobHashes), maxBlobsPerTransaction) 127 } 128 129 // create check 130 if args.To == nil { 131 if args.BlobHashes != nil { 132 return errors.New(`missing "to" in blob transaction`) 133 } 134 if len(args.data()) == 0 { 135 return errors.New(`contract creation without any data provided`) 136 } 137 } 138 139 if args.Gas == nil { 140 if skipGasEstimation { // Skip gas usage estimation if a precise gas limit is not critical, e.g., in non-transaction calls. 141 gas := hexutil.Uint64(b.RPCGasCap()) 142 if gas == 0 { 143 gas = hexutil.Uint64(math.MaxUint64 / 2) 144 } 145 args.Gas = &gas 146 } else { // Estimate the gas usage otherwise. 147 // These fields are immutable during the estimation, safe to 148 // pass the pointer directly. 149 data := args.data() 150 callArgs := TransactionArgs{ 151 From: args.From, 152 To: args.To, 153 GasPrice: args.GasPrice, 154 MaxFeePerGas: args.MaxFeePerGas, 155 MaxPriorityFeePerGas: args.MaxPriorityFeePerGas, 156 Value: args.Value, 157 Data: (*hexutil.Bytes)(&data), 158 AccessList: args.AccessList, 159 BlobFeeCap: args.BlobFeeCap, 160 BlobHashes: args.BlobHashes, 161 } 162 latestBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber) 163 estimated, err := DoEstimateGas(ctx, b, callArgs, latestBlockNr, nil, b.RPCGasCap()) 164 if err != nil { 165 return err 166 } 167 args.Gas = &estimated 168 log.Trace("Estimate gas usage automatically", "gas", args.Gas) 169 } 170 } 171 172 // If chain id is provided, ensure it matches the local chain id. Otherwise, set the local 173 // chain id as the default. 174 want := b.ChainConfig().ChainID 175 if args.ChainID != nil { 176 if have := (*big.Int)(args.ChainID); have.Cmp(want) != 0 { 177 return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, want) 178 } 179 } else { 180 args.ChainID = (*hexutil.Big)(want) 181 } 182 return nil 183 } 184 185 // setFeeDefaults fills in default fee values for unspecified tx fields. 186 func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) error { 187 head := b.CurrentHeader() 188 // Sanity check the EIP-4844 fee parameters. 189 if args.BlobFeeCap != nil && args.BlobFeeCap.ToInt().Sign() == 0 { 190 return errors.New("maxFeePerBlobGas, if specified, must be non-zero") 191 } 192 if err := args.setCancunFeeDefaults(ctx, head, b); err != nil { 193 return err 194 } 195 // If both gasPrice and at least one of the EIP-1559 fee parameters are specified, error. 196 if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { 197 return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") 198 } 199 // If the tx has completely specified a fee mechanism, no default is needed. 200 // This allows users who are not yet synced past London to get defaults for 201 // other tx values. See https://github.com/ethereum/go-ethereum/pull/23274 202 // for more information. 203 eip1559ParamsSet := args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil 204 // Sanity check the EIP-1559 fee parameters if present. 205 if args.GasPrice == nil && eip1559ParamsSet { 206 if args.MaxFeePerGas.ToInt().Sign() == 0 { 207 return errors.New("maxFeePerGas must be non-zero") 208 } 209 if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 210 return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 211 } 212 return nil // No need to set anything, user already set MaxFeePerGas and MaxPriorityFeePerGas 213 } 214 215 // Sanity check the non-EIP-1559 fee parameters. 216 isLondon := b.ChainConfig().IsLondon(head.Number) 217 if args.GasPrice != nil && !eip1559ParamsSet { 218 // Zero gas-price is not allowed after London fork 219 if args.GasPrice.ToInt().Sign() == 0 && isLondon { 220 return errors.New("gasPrice must be non-zero after london fork") 221 } 222 return nil // No need to set anything, user already set GasPrice 223 } 224 225 // Now attempt to fill in default value depending on whether London is active or not. 226 if isLondon { 227 // London is active, set maxPriorityFeePerGas and maxFeePerGas. 228 if err := args.setLondonFeeDefaults(ctx, head, b); err != nil { 229 return err 230 } 231 } else { 232 if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil { 233 return errors.New("maxFeePerGas and maxPriorityFeePerGas are not valid before London is active") 234 } 235 // London not active, set gas price. 236 price, err := b.SuggestGasTipCap(ctx) 237 if err != nil { 238 return err 239 } 240 args.GasPrice = (*hexutil.Big)(price) 241 } 242 return nil 243 } 244 245 // setCancunFeeDefaults fills in reasonable default fee values for unspecified fields. 246 func (args *TransactionArgs) setCancunFeeDefaults(ctx context.Context, head *types.Header, b Backend) error { 247 // Set maxFeePerBlobGas if it is missing. 248 if args.BlobHashes != nil && args.BlobFeeCap == nil { 249 var excessBlobGas uint64 250 if head.ExcessBlobGas != nil { 251 excessBlobGas = *head.ExcessBlobGas 252 } 253 // ExcessBlobGas must be set for a Cancun block. 254 blobBaseFee := eip4844.CalcBlobFee(excessBlobGas) 255 // Set the max fee to be 2 times larger than the previous block's blob base fee. 256 // The additional slack allows the tx to not become invalidated if the base 257 // fee is rising. 258 val := new(big.Int).Mul(blobBaseFee, big.NewInt(2)) 259 args.BlobFeeCap = (*hexutil.Big)(val) 260 } 261 return nil 262 } 263 264 // setLondonFeeDefaults fills in reasonable default fee values for unspecified fields. 265 func (args *TransactionArgs) setLondonFeeDefaults(ctx context.Context, head *types.Header, b Backend) error { 266 // Set maxPriorityFeePerGas if it is missing. 267 if args.MaxPriorityFeePerGas == nil { 268 tip, err := b.SuggestGasTipCap(ctx) 269 if err != nil { 270 return err 271 } 272 args.MaxPriorityFeePerGas = (*hexutil.Big)(tip) 273 } 274 // Set maxFeePerGas if it is missing. 275 if args.MaxFeePerGas == nil { 276 // Set the max fee to be 2 times larger than the previous block's base fee. 277 // The additional slack allows the tx to not become invalidated if the base 278 // fee is rising. 279 val := new(big.Int).Add( 280 args.MaxPriorityFeePerGas.ToInt(), 281 new(big.Int).Mul(head.BaseFee, big.NewInt(2)), 282 ) 283 args.MaxFeePerGas = (*hexutil.Big)(val) 284 } 285 // Both EIP-1559 fee parameters are now set; sanity check them. 286 if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 287 return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 288 } 289 return nil 290 } 291 292 // setBlobTxSidecar adds the blob tx 293 func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context) error { 294 // No blobs, we're done. 295 if args.Blobs == nil { 296 return nil 297 } 298 299 // Passing blobs is not allowed in all contexts, only in specific methods. 300 if !args.blobSidecarAllowed { 301 return errors.New(`"blobs" is not supported for this RPC method`) 302 } 303 304 n := len(args.Blobs) 305 // Assume user provides either only blobs (w/o hashes), or 306 // blobs together with commitments and proofs. 307 if args.Commitments == nil && args.Proofs != nil { 308 return errors.New(`blob proofs provided while commitments were not`) 309 } else if args.Commitments != nil && args.Proofs == nil { 310 return errors.New(`blob commitments provided while proofs were not`) 311 } 312 313 // len(blobs) == len(commitments) == len(proofs) == len(hashes) 314 if args.Commitments != nil && len(args.Commitments) != n { 315 return fmt.Errorf("number of blobs and commitments mismatch (have=%d, want=%d)", len(args.Commitments), n) 316 } 317 if args.Proofs != nil && len(args.Proofs) != n { 318 return fmt.Errorf("number of blobs and proofs mismatch (have=%d, want=%d)", len(args.Proofs), n) 319 } 320 if args.BlobHashes != nil && len(args.BlobHashes) != n { 321 return fmt.Errorf("number of blobs and hashes mismatch (have=%d, want=%d)", len(args.BlobHashes), n) 322 } 323 324 if args.Commitments == nil { 325 // Generate commitment and proof. 326 commitments := make([]kzg4844.Commitment, n) 327 proofs := make([]kzg4844.Proof, n) 328 for i, b := range args.Blobs { 329 c, err := kzg4844.BlobToCommitment(&b) 330 if err != nil { 331 return fmt.Errorf("blobs[%d]: error computing commitment: %v", i, err) 332 } 333 commitments[i] = c 334 p, err := kzg4844.ComputeBlobProof(&b, c) 335 if err != nil { 336 return fmt.Errorf("blobs[%d]: error computing proof: %v", i, err) 337 } 338 proofs[i] = p 339 } 340 args.Commitments = commitments 341 args.Proofs = proofs 342 } else { 343 for i, b := range args.Blobs { 344 if err := kzg4844.VerifyBlobProof(&b, args.Commitments[i], args.Proofs[i]); err != nil { 345 return fmt.Errorf("failed to verify blob proof: %v", err) 346 } 347 } 348 } 349 350 hashes := make([]common.Hash, n) 351 hasher := sha256.New() 352 for i, c := range args.Commitments { 353 hashes[i] = kzg4844.CalcBlobHashV1(hasher, &c) 354 } 355 if args.BlobHashes != nil { 356 for i, h := range hashes { 357 if h != args.BlobHashes[i] { 358 return fmt.Errorf("blob hash verification failed (have=%s, want=%s)", args.BlobHashes[i], h) 359 } 360 } 361 } else { 362 args.BlobHashes = hashes 363 } 364 return nil 365 } 366 367 // CallDefaults sanitizes the transaction arguments, often filling in zero values, 368 // for the purpose of eth_call class of RPC methods. 369 func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, chainID *big.Int) error { 370 // Reject invalid combinations of pre- and post-1559 fee styles 371 if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { 372 return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") 373 } 374 if args.ChainID == nil { 375 args.ChainID = (*hexutil.Big)(chainID) 376 } else { 377 if have := (*big.Int)(args.ChainID); have.Cmp(chainID) != 0 { 378 return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, chainID) 379 } 380 } 381 if args.Gas == nil { 382 gas := globalGasCap 383 if gas == 0 { 384 gas = uint64(math.MaxUint64 / 2) 385 } 386 args.Gas = (*hexutil.Uint64)(&gas) 387 } else { 388 if globalGasCap > 0 && globalGasCap < uint64(*args.Gas) { 389 log.Warn("Caller gas above allowance, capping", "requested", args.Gas, "cap", globalGasCap) 390 args.Gas = (*hexutil.Uint64)(&globalGasCap) 391 } 392 } 393 if args.Nonce == nil { 394 args.Nonce = new(hexutil.Uint64) 395 } 396 if args.Value == nil { 397 args.Value = new(hexutil.Big) 398 } 399 if baseFee == nil { 400 // If there's no basefee, then it must be a non-1559 execution 401 if args.GasPrice == nil { 402 args.GasPrice = new(hexutil.Big) 403 } 404 } else { 405 // A basefee is provided, necessitating 1559-type execution 406 if args.MaxFeePerGas == nil { 407 args.MaxFeePerGas = new(hexutil.Big) 408 } 409 if args.MaxPriorityFeePerGas == nil { 410 args.MaxPriorityFeePerGas = new(hexutil.Big) 411 } 412 } 413 if args.BlobFeeCap == nil && args.BlobHashes != nil { 414 args.BlobFeeCap = new(hexutil.Big) 415 } 416 417 return nil 418 } 419 420 // ToMessage converts the transaction arguments to the Message type used by the 421 // core evm. This method is used in calls and traces that do not require a real 422 // live transaction. 423 // Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called. 424 func (args *TransactionArgs) ToMessage(baseFee *big.Int) *core.Message { 425 var ( 426 gasPrice *big.Int 427 gasFeeCap *big.Int 428 gasTipCap *big.Int 429 ) 430 if baseFee == nil { 431 gasPrice = args.GasPrice.ToInt() 432 gasFeeCap, gasTipCap = gasPrice, gasPrice 433 } else { 434 // A basefee is provided, necessitating 1559-type execution 435 if args.GasPrice != nil { 436 // User specified the legacy gas field, convert to 1559 gas typing 437 gasPrice = args.GasPrice.ToInt() 438 gasFeeCap, gasTipCap = gasPrice, gasPrice 439 } else { 440 // User specified 1559 gas fields (or none), use those 441 gasFeeCap = args.MaxFeePerGas.ToInt() 442 gasTipCap = args.MaxPriorityFeePerGas.ToInt() 443 // Backfill the legacy gasPrice for EVM execution, unless we're all zeroes 444 gasPrice = new(big.Int) 445 if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 { 446 gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap) 447 } 448 } 449 } 450 var accessList types.AccessList 451 if args.AccessList != nil { 452 accessList = *args.AccessList 453 } 454 return &core.Message{ 455 From: args.from(), 456 To: args.To, 457 Value: (*big.Int)(args.Value), 458 GasLimit: uint64(*args.Gas), 459 GasPrice: gasPrice, 460 GasFeeCap: gasFeeCap, 461 GasTipCap: gasTipCap, 462 Data: args.data(), 463 AccessList: accessList, 464 BlobGasFeeCap: (*big.Int)(args.BlobFeeCap), 465 BlobHashes: args.BlobHashes, 466 SkipAccountChecks: true, 467 } 468 } 469 470 // ToTransaction converts the arguments to a transaction. 471 // This assumes that setDefaults has been called. 472 func (args *TransactionArgs) ToTransaction() *types.Transaction { 473 var data types.TxData 474 switch { 475 case args.BlobHashes != nil: 476 al := types.AccessList{} 477 if args.AccessList != nil { 478 al = *args.AccessList 479 } 480 data = &types.BlobTx{ 481 To: *args.To, 482 ChainID: uint256.MustFromBig((*big.Int)(args.ChainID)), 483 Nonce: uint64(*args.Nonce), 484 Gas: uint64(*args.Gas), 485 GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)), 486 GasTipCap: uint256.MustFromBig((*big.Int)(args.MaxPriorityFeePerGas)), 487 Value: uint256.MustFromBig((*big.Int)(args.Value)), 488 Data: args.data(), 489 AccessList: al, 490 BlobHashes: args.BlobHashes, 491 BlobFeeCap: uint256.MustFromBig((*big.Int)(args.BlobFeeCap)), 492 } 493 if args.Blobs != nil { 494 data.(*types.BlobTx).Sidecar = &types.BlobTxSidecar{ 495 Blobs: args.Blobs, 496 Commitments: args.Commitments, 497 Proofs: args.Proofs, 498 } 499 } 500 501 case args.MaxFeePerGas != nil: 502 al := types.AccessList{} 503 if args.AccessList != nil { 504 al = *args.AccessList 505 } 506 data = &types.DynamicFeeTx{ 507 To: args.To, 508 ChainID: (*big.Int)(args.ChainID), 509 Nonce: uint64(*args.Nonce), 510 Gas: uint64(*args.Gas), 511 GasFeeCap: (*big.Int)(args.MaxFeePerGas), 512 GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas), 513 Value: (*big.Int)(args.Value), 514 Data: args.data(), 515 AccessList: al, 516 } 517 518 case args.AccessList != nil: 519 data = &types.AccessListTx{ 520 To: args.To, 521 ChainID: (*big.Int)(args.ChainID), 522 Nonce: uint64(*args.Nonce), 523 Gas: uint64(*args.Gas), 524 GasPrice: (*big.Int)(args.GasPrice), 525 Value: (*big.Int)(args.Value), 526 Data: args.data(), 527 AccessList: *args.AccessList, 528 } 529 530 default: 531 data = &types.LegacyTx{ 532 To: args.To, 533 Nonce: uint64(*args.Nonce), 534 Gas: uint64(*args.Gas), 535 GasPrice: (*big.Int)(args.GasPrice), 536 Value: (*big.Int)(args.Value), 537 Data: args.data(), 538 } 539 } 540 return types.NewTx(data) 541 } 542 543 // IsEIP4844 returns an indicator if the args contains EIP4844 fields. 544 func (args *TransactionArgs) IsEIP4844() bool { 545 return args.BlobHashes != nil || args.BlobFeeCap != nil 546 }