github.com/klaytn/klaytn@v1.12.1/api/tx_args.go (about) 1 // Modifications Copyright 2019 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from internal/ethapi/api.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package api 22 23 import ( 24 "bytes" 25 "context" 26 "errors" 27 "fmt" 28 "math/big" 29 "reflect" 30 31 "github.com/klaytn/klaytn/blockchain/types" 32 "github.com/klaytn/klaytn/blockchain/types/accountkey" 33 "github.com/klaytn/klaytn/common" 34 "github.com/klaytn/klaytn/common/hexutil" 35 "github.com/klaytn/klaytn/common/math" 36 "github.com/klaytn/klaytn/networks/rpc" 37 "github.com/klaytn/klaytn/params" 38 "github.com/klaytn/klaytn/rlp" 39 ) 40 41 var ( 42 errTxArgInvalidInputData = errors.New(`Both "data" and "input" are set and not equal. Please use "input" to pass transaction call data.`) 43 errTxArgInvalidFeePayer = errors.New("invalid fee payer is set") 44 errTxArgNilTxType = errors.New("tx should have a type value") 45 errTxArgNilContractData = errors.New(`contract creation without any data provided`) 46 errTxArgNilSenderSig = errors.New("sender signature is not set") 47 errTxArgNilNonce = errors.New("nonce of the sender is not set") 48 errTxArgNilGas = errors.New("gas limit is not set") 49 errTxArgNilGasPrice = errors.New("gas price is not set") 50 errNotForFeeDelegationTx = errors.New("fee-delegation type transactions are not allowed to use this API") 51 ) 52 53 // isTxField checks whether the string is a field name of the specific txType. 54 // isTxField[txType][txFieldName] has true/false. 55 var isTxField = func() map[types.TxType]map[string]bool { 56 mapOfFieldMap := map[types.TxType]map[string]bool{} 57 internalDataTypes := map[types.TxType]interface{}{ 58 // since legacy tx has optional fields, some fields can be omitted 59 // types.TxTypeLegacyTransaction: types.TxInternalDataLegacy{}, 60 types.TxTypeValueTransfer: types.TxInternalDataValueTransfer{}, 61 types.TxTypeFeeDelegatedValueTransfer: types.TxInternalDataFeeDelegatedValueTransfer{}, 62 types.TxTypeFeeDelegatedValueTransferWithRatio: types.TxInternalDataFeeDelegatedValueTransferWithRatio{}, 63 types.TxTypeValueTransferMemo: types.TxInternalDataValueTransferMemo{}, 64 types.TxTypeFeeDelegatedValueTransferMemo: types.TxInternalDataFeeDelegatedValueTransferMemo{}, 65 types.TxTypeFeeDelegatedValueTransferMemoWithRatio: types.TxInternalDataFeeDelegatedValueTransferMemoWithRatio{}, 66 types.TxTypeAccountUpdate: types.TxInternalDataAccountUpdate{}, 67 types.TxTypeFeeDelegatedAccountUpdate: types.TxInternalDataFeeDelegatedAccountUpdate{}, 68 types.TxTypeFeeDelegatedAccountUpdateWithRatio: types.TxInternalDataFeeDelegatedAccountUpdateWithRatio{}, 69 types.TxTypeSmartContractDeploy: types.TxInternalDataSmartContractDeploy{}, 70 types.TxTypeFeeDelegatedSmartContractDeploy: types.TxInternalDataFeeDelegatedSmartContractDeploy{}, 71 types.TxTypeFeeDelegatedSmartContractDeployWithRatio: types.TxInternalDataFeeDelegatedSmartContractDeployWithRatio{}, 72 types.TxTypeSmartContractExecution: types.TxInternalDataSmartContractExecution{}, 73 types.TxTypeFeeDelegatedSmartContractExecution: types.TxInternalDataFeeDelegatedSmartContractExecution{}, 74 types.TxTypeFeeDelegatedSmartContractExecutionWithRatio: types.TxInternalDataFeeDelegatedSmartContractExecutionWithRatio{}, 75 types.TxTypeCancel: types.TxInternalDataCancel{}, 76 types.TxTypeFeeDelegatedCancel: types.TxInternalDataFeeDelegatedCancel{}, 77 types.TxTypeFeeDelegatedCancelWithRatio: types.TxInternalDataFeeDelegatedCancelWithRatio{}, 78 types.TxTypeChainDataAnchoring: types.TxInternalDataChainDataAnchoring{}, 79 types.TxTypeFeeDelegatedChainDataAnchoring: types.TxInternalDataFeeDelegatedChainDataAnchoring{}, 80 types.TxTypeFeeDelegatedChainDataAnchoringWithRatio: types.TxInternalDataFeeDelegatedChainDataAnchoringWithRatio{}, 81 } 82 83 // generate field maps for each tx type 84 for txType, internalData := range internalDataTypes { 85 fieldMap := map[string]bool{} 86 internalDataType := reflect.TypeOf(internalData) 87 88 // key of filedMap is tx field name and value of fieldMap means the existence of field name 89 for i := 0; i < internalDataType.NumField(); i++ { 90 fieldMap[internalDataType.Field(i).Name] = true 91 } 92 93 // additional field of SendTxArgs to support various tx types 94 fieldMap["TypeInt"] = true 95 // additional field of SendTxArgs to support a legacy tx field (skip checking) 96 fieldMap["Data"] = false 97 98 mapOfFieldMap[txType] = fieldMap 99 } 100 return mapOfFieldMap 101 }() 102 103 type NewTxArgs interface { 104 setDefaults(context.Context, Backend) error 105 toTransaction() (*types.Transaction, error) 106 from() common.Address 107 gas() *hexutil.Uint64 108 gasPrice() *hexutil.Big 109 nonce() *hexutil.Uint64 110 setGas(*hexutil.Uint64) 111 setGasPrice(*hexutil.Big) 112 } 113 114 // SendTxArgs represents the arguments to submit a new transaction into the transaction pool. 115 type SendTxArgs struct { 116 TypeInt *types.TxType `json:"typeInt"` 117 From common.Address `json:"from"` 118 Recipient *common.Address `json:"to"` 119 GasLimit *hexutil.Uint64 `json:"gas"` 120 Price *hexutil.Big `json:"gasPrice"` 121 MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` 122 MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` 123 Amount *hexutil.Big `json:"value"` 124 AccountNonce *hexutil.Uint64 `json:"nonce"` 125 // We accept "data" and "input" for backwards-compatibility reasons. "input" is the 126 // newer name and should be preferred by clients. 127 Data *hexutil.Bytes `json:"data"` 128 Payload *hexutil.Bytes `json:"input"` 129 130 CodeFormat *params.CodeFormat `json:"codeFormat"` 131 HumanReadable *bool `json:"humanReadable"` 132 133 Key *hexutil.Bytes `json:"key"` 134 135 AccessList *types.AccessList `json:"accessList,omitempty"` 136 ChainID *hexutil.Big `json:"chainId,omitempty"` 137 138 FeePayer *common.Address `json:"feePayer"` 139 FeeRatio *types.FeeRatio `json:"feeRatio"` 140 141 TxSignatures types.TxSignaturesJSON `json:"signatures"` 142 } 143 144 // setDefaults is a helper function that fills in default values for unspecified common tx fields. 145 func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { 146 isMagma := b.ChainConfig().IsMagmaForkEnabled(new(big.Int).Add(b.CurrentBlock().Number(), big.NewInt(1))) 147 148 if args.TypeInt == nil { 149 args.TypeInt = new(types.TxType) 150 *args.TypeInt = types.TxTypeLegacyTransaction 151 } 152 if args.GasLimit == nil { 153 args.GasLimit = new(hexutil.Uint64) 154 *args.GasLimit = hexutil.Uint64(90000) 155 } 156 // Eth typed transactions requires chainId. 157 if args.TypeInt.IsEthTypedTransaction() { 158 if args.ChainID == nil { 159 args.ChainID = (*hexutil.Big)(b.ChainConfig().ChainID) 160 } 161 } 162 // For the transaction that do not use the gasPrice field, the default value of gasPrice is not set. 163 if args.Price == nil && *args.TypeInt != types.TxTypeEthereumDynamicFee { 164 // b.SuggestPrice = unitPrice, for before Magma 165 // = baseFee * 2, for after Magma 166 price, err := b.SuggestPrice(ctx) 167 if err != nil { 168 return err 169 } 170 args.Price = (*hexutil.Big)(price) 171 } 172 173 if *args.TypeInt == types.TxTypeEthereumDynamicFee { 174 gasPrice, err := b.SuggestPrice(ctx) 175 if err != nil { 176 return err 177 } 178 if args.MaxPriorityFeePerGas == nil { 179 args.MaxPriorityFeePerGas = (*hexutil.Big)(gasPrice) 180 } 181 if args.MaxFeePerGas == nil { 182 // Before Magma hard fork, `gasFeeCap` was set to `baseFee*2 + maxPriorityFeePerGas` by default. 183 gasFeeCap := new(big.Int).Add( 184 (*big.Int)(args.MaxPriorityFeePerGas), 185 new(big.Int).Mul(new(big.Int).SetUint64(params.ZeroBaseFee), big.NewInt(2)), 186 ) 187 if isMagma { 188 // After Magma hard fork, `gasFeeCap` was set to `baseFee*2` by default. 189 gasFeeCap = gasPrice 190 } 191 args.MaxFeePerGas = (*hexutil.Big)(gasFeeCap) 192 } 193 if isMagma { 194 if args.MaxFeePerGas.ToInt().Cmp(new(big.Int).Div(gasPrice, common.Big2)) < 0 { 195 return fmt.Errorf("maxFeePerGas (%v) < BaseFee (%v)", args.MaxFeePerGas, gasPrice) 196 } 197 } else if args.MaxPriorityFeePerGas.ToInt().Cmp(gasPrice) != 0 || args.MaxFeePerGas.ToInt().Cmp(gasPrice) != 0 { 198 return fmt.Errorf("only %s is allowed to be used as maxFeePerGas and maxPriorityPerGas", gasPrice.Text(16)) 199 } 200 if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 201 return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 202 } 203 } 204 if args.AccountNonce == nil { 205 nonce := b.GetPoolNonce(ctx, args.From) 206 args.AccountNonce = (*hexutil.Uint64)(&nonce) 207 } 208 209 return nil 210 } 211 212 // checkArgs checks the validity of SendTxArgs values. 213 // The each tx types has its own validation logic to give detailed errors to users. 214 func (args *SendTxArgs) checkArgs() error { 215 if args.TypeInt == nil { 216 return errTxArgNilTxType 217 } 218 // Skip ethereum transaction type since it has optional fields 219 if args.TypeInt.IsEthereumTransaction() { 220 return nil 221 } 222 223 argsType := reflect.TypeOf(*args) 224 argsValue := reflect.ValueOf(*args) 225 226 for i := 0; i < argsType.NumField(); i++ { 227 // Skip From since it is an essential field and a non-pointer value 228 // Skip TxSignatures since the value is not considered by all APIs 229 if argsType.Field(i).Name == "From" || argsType.Field(i).Name == "TxSignatures" { 230 continue 231 } 232 233 // An args field doesn't have a value but the field name exist on the tx type 234 if argsValue.Field(i).IsNil() && isTxField[*args.TypeInt][argsType.Field(i).Name] { 235 // Allow only contract deploying txs to set the recipient as nil 236 if (*args.TypeInt).IsContractDeploy() && argsType.Field(i).Name == "Recipient" { 237 continue 238 } 239 return errors.New((string)(argsType.Field(i).Tag) + " is required for " + (*args.TypeInt).String()) 240 } 241 242 // An args field has a value but the field name doesn't exist on the tx type 243 if !argsValue.Field(i).IsNil() && !isTxField[*args.TypeInt][argsType.Field(i).Name] { 244 return errors.New((string)(argsType.Field(i).Tag) + " is not a field of " + (*args.TypeInt).String()) 245 } 246 } 247 248 return nil 249 } 250 251 // genTxValuesMap generates a value map used used in "NewTransactionWithMap" function. 252 // This function assigned all non-nil values regardless of the tx type. 253 // Invalid values in the map will be validated in "NewTransactionWithMap" function. 254 func (args *SendTxArgs) genTxValuesMap() map[types.TxValueKeyType]interface{} { 255 values := make(map[types.TxValueKeyType]interface{}) 256 257 // common tx fields. They should have values after executing "setDefaults" function. 258 if args.TypeInt == nil || args.AccountNonce == nil || args.GasLimit == nil { 259 return values 260 } 261 // GasPrice can be an optional tx filed for TxTypeEthereumDynamicFee 262 if args.Price == nil && *args.TypeInt != types.TxTypeEthereumDynamicFee { 263 return values 264 } 265 266 if !args.TypeInt.IsEthereumTransaction() { 267 values[types.TxValueKeyFrom] = args.From 268 } 269 values[types.TxValueKeyNonce] = uint64(*args.AccountNonce) 270 values[types.TxValueKeyGasLimit] = uint64(*args.GasLimit) 271 272 // optional tx fields 273 if args.Price != nil { 274 values[types.TxValueKeyGasPrice] = (*big.Int)(args.Price) 275 } 276 if args.TypeInt.IsContractDeploy() || args.TypeInt.IsEthereumTransaction() { 277 // contract deploy type and ethereum tx types allow nil as TxValueKeyTo value 278 values[types.TxValueKeyTo] = (*common.Address)(args.Recipient) 279 } else if args.Recipient != nil { 280 values[types.TxValueKeyTo] = *args.Recipient 281 } 282 if args.FeePayer != nil { 283 values[types.TxValueKeyFeePayer] = *args.FeePayer 284 } 285 if args.FeeRatio != nil { 286 values[types.TxValueKeyFeeRatioOfFeePayer] = *args.FeeRatio 287 } 288 if args.Amount != nil { 289 values[types.TxValueKeyAmount] = (*big.Int)(args.Amount) 290 } else if args.TypeInt.IsEthereumTransaction() { 291 values[types.TxValueKeyAmount] = common.Big0 292 } 293 if args.Payload != nil { 294 // chain data anchoring type uses the TxValueKeyAnchoredData field 295 if args.TypeInt.IsChainDataAnchoring() { 296 values[types.TxValueKeyAnchoredData] = ([]byte)(*args.Payload) 297 } else { 298 values[types.TxValueKeyData] = ([]byte)(*args.Payload) 299 } 300 } else if args.TypeInt.IsEthereumTransaction() { 301 // For Ethereum transactions, Payload is an optional field. 302 values[types.TxValueKeyData] = []byte{} 303 } 304 if args.CodeFormat != nil { 305 values[types.TxValueKeyCodeFormat] = *args.CodeFormat 306 } 307 if args.HumanReadable != nil { 308 values[types.TxValueKeyHumanReadable] = *args.HumanReadable 309 } 310 if args.Key != nil { 311 serializer := accountkey.NewAccountKeySerializer() 312 if err := rlp.DecodeBytes(*args.Key, &serializer); err == nil { 313 values[types.TxValueKeyAccountKey] = serializer.GetKey() 314 } 315 } 316 if args.ChainID != nil { 317 values[types.TxValueKeyChainID] = (*big.Int)(args.ChainID) 318 } 319 if args.AccessList != nil { 320 values[types.TxValueKeyAccessList] = *args.AccessList 321 } 322 if args.MaxPriorityFeePerGas != nil { 323 values[types.TxValueKeyGasTipCap] = (*big.Int)(args.MaxPriorityFeePerGas) 324 } 325 if args.MaxFeePerGas != nil { 326 values[types.TxValueKeyGasFeeCap] = (*big.Int)(args.MaxFeePerGas) 327 } 328 329 return values 330 } 331 332 // toTransaction returns an unsigned transaction filled with values in SendTxArgs. 333 func (args *SendTxArgs) toTransaction() (*types.Transaction, error) { 334 var input []byte 335 336 // provide detailed error messages to users (optional) 337 if err := args.checkArgs(); err != nil { 338 return nil, err 339 } 340 341 // for TxTypeLegacyTransaction 342 if *args.TypeInt == types.TxTypeLegacyTransaction { 343 if args.Data != nil && args.Payload != nil && !bytes.Equal(*args.Data, *args.Payload) { 344 return nil, errTxArgInvalidInputData 345 } 346 347 if args.Data != nil { 348 input = *args.Data 349 } else if args.Payload != nil { 350 input = *args.Payload 351 } 352 353 if args.Recipient == nil { 354 if len(input) == 0 { 355 return nil, errTxArgNilContractData 356 } 357 return types.NewContractCreation(uint64(*args.AccountNonce), (*big.Int)(args.Amount), uint64(*args.GasLimit), (*big.Int)(args.Price), input), nil 358 } 359 return types.NewTransaction(uint64(*args.AccountNonce), *args.Recipient, (*big.Int)(args.Amount), uint64(*args.GasLimit), (*big.Int)(args.Price), input), nil 360 } 361 362 // for other tx types except TxTypeLegacyTransaction 363 values := args.genTxValuesMap() 364 return types.NewTransactionWithMap(*args.TypeInt, values) 365 } 366 367 func (args *SendTxArgs) from() common.Address { 368 return args.From 369 } 370 371 func (args *SendTxArgs) gas() *hexutil.Uint64 { 372 return args.GasLimit 373 } 374 375 func (args *SendTxArgs) gasPrice() *hexutil.Big { 376 return args.Price 377 } 378 379 func (args *SendTxArgs) nonce() *hexutil.Uint64 { 380 return args.AccountNonce 381 } 382 383 func (args *SendTxArgs) setGas(gas *hexutil.Uint64) { 384 args.GasLimit = gas 385 } 386 387 func (args *SendTxArgs) setGasPrice(gasPrice *hexutil.Big) { 388 args.Price = gasPrice 389 } 390 391 type ValueTransferTxArgs struct { 392 From common.Address `json:"from"` 393 Gas *hexutil.Uint64 `json:"gas"` 394 GasPrice *hexutil.Big `json:"gasPrice"` 395 Nonce *hexutil.Uint64 `json:"nonce"` 396 To common.Address `json:"to"` 397 Value *hexutil.Big `json:"value"` 398 } 399 400 func (args *ValueTransferTxArgs) from() common.Address { 401 return args.From 402 } 403 404 func (args *ValueTransferTxArgs) gas() *hexutil.Uint64 { 405 return args.Gas 406 } 407 408 func (args *ValueTransferTxArgs) gasPrice() *hexutil.Big { 409 return args.GasPrice 410 } 411 412 func (args *ValueTransferTxArgs) nonce() *hexutil.Uint64 { 413 return args.Nonce 414 } 415 416 func (args *ValueTransferTxArgs) setGas(gas *hexutil.Uint64) { 417 args.Gas = gas 418 } 419 420 func (args *ValueTransferTxArgs) setGasPrice(gasPrice *hexutil.Big) { 421 args.GasPrice = gasPrice 422 } 423 424 // setDefaults is a helper function that fills in default values for unspecified tx fields. 425 func (args *ValueTransferTxArgs) setDefaults(ctx context.Context, b Backend) error { 426 if args.Gas == nil { 427 args.Gas = new(hexutil.Uint64) 428 *(*uint64)(args.Gas) = 90000 429 } 430 if args.GasPrice == nil { 431 price, err := b.SuggestPrice(ctx) 432 if err != nil { 433 return err 434 } 435 args.GasPrice = (*hexutil.Big)(price) 436 } 437 if args.Nonce == nil { 438 nonce := b.GetPoolNonce(ctx, args.From) 439 args.Nonce = (*hexutil.Uint64)(&nonce) 440 } 441 return nil 442 } 443 444 func (args *ValueTransferTxArgs) toTransaction() (*types.Transaction, error) { 445 tx, err := types.NewTransactionWithMap(types.TxTypeValueTransfer, map[types.TxValueKeyType]interface{}{ 446 types.TxValueKeyNonce: (uint64)(*args.Nonce), 447 types.TxValueKeyGasLimit: (uint64)(*args.Gas), 448 types.TxValueKeyGasPrice: (*big.Int)(args.GasPrice), 449 types.TxValueKeyFrom: args.From, 450 types.TxValueKeyTo: args.To, 451 types.TxValueKeyAmount: (*big.Int)(args.Value), 452 }) 453 if err != nil { 454 return nil, err 455 } 456 457 return tx, nil 458 } 459 460 type AccountUpdateTxArgs struct { 461 From common.Address `json:"from"` 462 Gas *hexutil.Uint64 `json:"gas"` 463 GasPrice *hexutil.Big `json:"gasPrice"` 464 Nonce *hexutil.Uint64 `json:"nonce"` 465 Key *hexutil.Bytes `json:"key"` 466 } 467 468 func (args *AccountUpdateTxArgs) from() common.Address { 469 return args.From 470 } 471 472 func (args *AccountUpdateTxArgs) gas() *hexutil.Uint64 { 473 return args.Gas 474 } 475 476 func (args *AccountUpdateTxArgs) gasPrice() *hexutil.Big { 477 return args.GasPrice 478 } 479 480 func (args *AccountUpdateTxArgs) nonce() *hexutil.Uint64 { 481 return args.Nonce 482 } 483 484 func (args *AccountUpdateTxArgs) setGas(gas *hexutil.Uint64) { 485 args.Gas = gas 486 } 487 488 func (args *AccountUpdateTxArgs) setGasPrice(gasPrice *hexutil.Big) { 489 args.GasPrice = gasPrice 490 } 491 492 // setDefaults is a helper function that fills in default values for unspecified tx fields. 493 func (args *AccountUpdateTxArgs) setDefaults(ctx context.Context, b Backend) error { 494 if args.Gas == nil { 495 args.Gas = new(hexutil.Uint64) 496 *(*uint64)(args.Gas) = 90000 497 } 498 if args.GasPrice == nil { 499 price, err := b.SuggestPrice(ctx) 500 if err != nil { 501 return err 502 } 503 args.GasPrice = (*hexutil.Big)(price) 504 } 505 if args.Nonce == nil { 506 nonce := b.GetPoolNonce(ctx, args.From) 507 args.Nonce = (*hexutil.Uint64)(&nonce) 508 } 509 return nil 510 } 511 512 func (args *AccountUpdateTxArgs) toTransaction() (*types.Transaction, error) { 513 serializer := accountkey.NewAccountKeySerializer() 514 515 if err := rlp.DecodeBytes(*args.Key, &serializer); err != nil { 516 return nil, err 517 } 518 tx, err := types.NewTransactionWithMap(types.TxTypeAccountUpdate, map[types.TxValueKeyType]interface{}{ 519 types.TxValueKeyNonce: (uint64)(*args.Nonce), 520 types.TxValueKeyGasLimit: (uint64)(*args.Gas), 521 types.TxValueKeyGasPrice: (*big.Int)(args.GasPrice), 522 types.TxValueKeyFrom: args.From, 523 types.TxValueKeyAccountKey: serializer.GetKey(), 524 }) 525 if err != nil { 526 return nil, err 527 } 528 529 return tx, nil 530 } 531 532 // EthTransactionArgs represents the arguments to construct a new transaction 533 // or a message call. 534 // TransactionArgs in go-ethereum has been renamed to EthTransactionArgs. 535 // TransactionArgs is defined in go-ethereum's internal package, so TransactionArgs is redefined here as EthTransactionArgs. 536 type EthTransactionArgs struct { 537 From *common.Address `json:"from"` 538 To *common.Address `json:"to"` 539 Gas *hexutil.Uint64 `json:"gas"` 540 GasPrice *hexutil.Big `json:"gasPrice"` 541 MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` 542 MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` 543 Value *hexutil.Big `json:"value"` 544 Nonce *hexutil.Uint64 `json:"nonce"` 545 546 // We accept "data" and "input" for backwards-compatibility reasons. 547 // "input" is the newer name and should be preferred by clients. 548 // Issue detail: https://github.com/ethereum/go-ethereum/issues/15628 549 Data *hexutil.Bytes `json:"data"` 550 Input *hexutil.Bytes `json:"input"` 551 552 // Introduced by AccessListTxType transaction. 553 AccessList *types.AccessList `json:"accessList,omitempty"` 554 ChainID *hexutil.Big `json:"chainId,omitempty"` 555 } 556 557 // from retrieves the transaction sender address. 558 func (args *EthTransactionArgs) from() common.Address { 559 if args.From == nil { 560 return common.Address{} 561 } 562 return *args.From 563 } 564 565 func (args *EthTransactionArgs) gas() *hexutil.Uint64 { 566 return args.Gas 567 } 568 569 func (args *EthTransactionArgs) gasPrice() *hexutil.Big { 570 return args.GasPrice 571 } 572 573 func (args *EthTransactionArgs) nonce() *hexutil.Uint64 { 574 return args.Nonce 575 } 576 577 // data retrieves the transaction calldata. Input field is preferred. 578 func (args *EthTransactionArgs) data() []byte { 579 if args.Input != nil { 580 return *args.Input 581 } 582 if args.Data != nil { 583 return *args.Data 584 } 585 return nil 586 } 587 588 func (args *EthTransactionArgs) setGas(gas *hexutil.Uint64) { 589 args.Gas = gas 590 } 591 592 func (args *EthTransactionArgs) setGasPrice(gasPrice *hexutil.Big) { 593 args.GasPrice = gasPrice 594 } 595 596 // setDefaults fills in default values for unspecified tx fields. 597 func (args *EthTransactionArgs) setDefaults(ctx context.Context, b Backend) error { 598 if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { 599 return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") 600 } 601 // After london, default to 1559 uncles gasPrice is set 602 head := b.CurrentBlock().Header() 603 isMagma := head.BaseFee != nil 604 605 fixedBaseFee := new(big.Int).SetUint64(params.ZeroBaseFee) 606 607 // b.SuggestPrice = unitPrice, for before Magma 608 // = baseFee, for after Magma 609 gasPrice, err := b.SuggestPrice(ctx) 610 if err != nil { 611 return err 612 } 613 614 // If user specifies both maxPriorityFee and maxFee, then we do not 615 // need to consult the chain for defaults. It's definitely a London tx. 616 if args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil { 617 if b.ChainConfig().IsEthTxTypeForkEnabled(head.Number) && args.GasPrice == nil { 618 if args.MaxPriorityFeePerGas == nil { 619 args.MaxPriorityFeePerGas = (*hexutil.Big)(gasPrice) 620 } 621 if args.MaxFeePerGas == nil { 622 // Before Magma hard fork, `gasFeeCap` was set to `baseFee*2 + maxPriorityFeePerGas` by default. 623 gasFeeCap := new(big.Int).Add( 624 (*big.Int)(args.MaxPriorityFeePerGas), 625 new(big.Int).Mul(fixedBaseFee, big.NewInt(2)), 626 ) 627 if isMagma { 628 // After Magma hard fork, `gasFeeCap` was set to `baseFee*2` by default. 629 gasFeeCap = gasPrice 630 } 631 args.MaxFeePerGas = (*hexutil.Big)(gasFeeCap) 632 } 633 if isMagma { 634 if args.MaxFeePerGas.ToInt().Cmp(new(big.Int).Div(gasPrice, common.Big2)) < 0 { 635 return fmt.Errorf("maxFeePerGas (%v) < BaseFee (%v)", args.MaxFeePerGas, gasPrice) 636 } 637 } else if args.MaxPriorityFeePerGas.ToInt().Cmp(gasPrice) != 0 || args.MaxFeePerGas.ToInt().Cmp(gasPrice) != 0 { 638 return fmt.Errorf("only %s is allowed to be used as maxFeePerGas and maxPriorityPerGas", gasPrice.Text(16)) 639 } 640 if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 641 return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 642 } 643 } else { 644 if args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil { 645 return errors.New("maxFeePerGas or maxPriorityFeePerGas specified but london is not active yet") 646 } 647 if args.GasPrice == nil { 648 // TODO-Klaytn: Original logic of Ethereum uses b.SuggestTipCap which suggests TipCap, not a GasPrice. 649 // But Klaytn currently uses fixed unit price determined by Governance, so using b.SuggestPrice 650 // is fine as now. 651 if b.ChainConfig().IsEthTxTypeForkEnabled(head.Number) { 652 // TODO-Klaytn: Klaytn is using fixed BaseFee(0) as now but 653 // if we apply dynamic BaseFee, we should add calculated BaseFee instead of params.ZeroBaseFee. 654 gasPrice.Add(gasPrice, new(big.Int).SetUint64(params.ZeroBaseFee)) 655 } 656 args.GasPrice = (*hexutil.Big)(gasPrice) 657 } 658 } 659 } else { 660 // Both maxPriorityFee and maxFee set by caller. Sanity-check their internal relation 661 if isMagma { 662 if args.MaxFeePerGas.ToInt().Cmp(new(big.Int).Div(gasPrice, common.Big2)) < 0 { 663 return fmt.Errorf("maxFeePerGas (%v) < BaseFee (%v)", args.MaxFeePerGas, gasPrice) 664 } 665 } else { 666 if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 667 return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 668 } 669 } 670 } 671 if args.Value == nil { 672 args.Value = new(hexutil.Big) 673 } 674 if args.Nonce == nil { 675 nonce := b.GetPoolNonce(ctx, args.from()) 676 args.Nonce = (*hexutil.Uint64)(&nonce) 677 } 678 if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { 679 return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`) 680 } 681 if args.To == nil && len(args.data()) == 0 { 682 return errors.New(`contract creation without any data provided`) 683 } 684 // Estimate the gas usage if necessary. 685 if args.Gas == nil { 686 // These fields are immutable during the estimation, safe to 687 // pass the pointer directly. 688 data := args.data() 689 callArgs := EthTransactionArgs{ 690 From: args.From, 691 To: args.To, 692 GasPrice: args.GasPrice, 693 MaxFeePerGas: args.MaxFeePerGas, 694 MaxPriorityFeePerGas: args.MaxPriorityFeePerGas, 695 Value: args.Value, 696 Data: (*hexutil.Bytes)(&data), 697 AccessList: args.AccessList, 698 } 699 pendingBlockNr := rpc.NewBlockNumberOrHashWithNumber(rpc.PendingBlockNumber) 700 gasCap := uint64(0) 701 if rpcGasCap := b.RPCGasCap(); rpcGasCap != nil { 702 gasCap = rpcGasCap.Uint64() 703 } 704 estimated, err := EthDoEstimateGas(ctx, b, callArgs, pendingBlockNr, gasCap) 705 if err != nil { 706 return err 707 } 708 args.Gas = &estimated 709 logger.Trace("Estimate gas usage automatically", "gas", args.Gas) 710 } 711 if args.ChainID == nil { 712 id := (*hexutil.Big)(b.ChainConfig().ChainID) 713 args.ChainID = id 714 } 715 return nil 716 } 717 718 // ToMessage change EthTransactionArgs to types.Transaction in Klaytn. 719 func (args *EthTransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int, intrinsicGas uint64) (*types.Transaction, error) { 720 // Reject invalid combinations of pre- and post-1559 fee styles 721 if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { 722 return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") 723 } else if args.MaxFeePerGas != nil && args.MaxPriorityFeePerGas != nil { 724 if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { 725 return nil, errors.New("MaxPriorityFeePerGas is greater than MaxFeePerGas") 726 } 727 } 728 // Set sender address or use zero address if none specified. 729 addr := args.from() 730 731 // Set default gas & gas price if none were set 732 gas := globalGasCap 733 if gas == 0 { 734 gas = uint64(math.MaxUint64 / 2) 735 } 736 if args.Gas != nil { 737 gas = uint64(*args.Gas) 738 } 739 if globalGasCap != 0 && globalGasCap < gas { 740 logger.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap) 741 gas = globalGasCap 742 } 743 744 // Do not update gasPrice unless any of args.GasPrice and args.MaxFeePerGas is specified. 745 gasPrice := new(big.Int) 746 if baseFee.Cmp(new(big.Int).SetUint64(params.ZeroBaseFee)) == 0 { 747 // If there's no basefee, then it must be a non-1559 execution 748 if args.GasPrice != nil { 749 gasPrice = args.GasPrice.ToInt() 750 } else if args.MaxFeePerGas != nil { 751 gasPrice = args.MaxFeePerGas.ToInt() 752 } 753 } else { 754 if args.GasPrice != nil { 755 gasPrice = args.GasPrice.ToInt() 756 } else if args.MaxFeePerGas != nil { 757 // User specified 1559 gas fields (or none), use those 758 gasPrice = args.MaxFeePerGas.ToInt() 759 } else { 760 // User specified neither GasPrice nor MaxFeePerGas, use baseFee 761 gasPrice = new(big.Int).Mul(baseFee, common.Big2) 762 } 763 } 764 765 value := new(big.Int) 766 if args.Value != nil { 767 value = args.Value.ToInt() 768 } 769 data := args.data() 770 771 var accessList types.AccessList 772 if args.AccessList != nil { 773 accessList = *args.AccessList 774 } 775 return types.NewMessage(addr, args.To, 0, value, gas, gasPrice, data, false, intrinsicGas, accessList), nil 776 } 777 778 // toTransaction converts the arguments to a transaction. 779 // This assumes that setDefaults has been called. 780 func (args *EthTransactionArgs) toTransaction() (*types.Transaction, error) { 781 var tx *types.Transaction 782 switch { 783 case args.MaxFeePerGas != nil: 784 al := types.AccessList{} 785 if args.AccessList != nil { 786 al = *args.AccessList 787 } 788 tx = types.NewTx(&types.TxInternalDataEthereumDynamicFee{ 789 ChainID: (*big.Int)(args.ChainID), 790 AccountNonce: uint64(*args.Nonce), 791 GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas), 792 GasFeeCap: (*big.Int)(args.MaxFeePerGas), 793 GasLimit: uint64(*args.Gas), 794 Recipient: args.To, 795 Amount: (*big.Int)(args.Value), 796 Payload: args.data(), 797 AccessList: al, 798 }) 799 case args.AccessList != nil: 800 tx = types.NewTx(&types.TxInternalDataEthereumAccessList{ 801 ChainID: (*big.Int)(args.ChainID), 802 AccountNonce: uint64(*args.Nonce), 803 Recipient: args.To, 804 GasLimit: uint64(*args.Gas), 805 Price: (*big.Int)(args.GasPrice), 806 Amount: (*big.Int)(args.Value), 807 Payload: args.data(), 808 AccessList: *args.AccessList, 809 }) 810 default: 811 tx = types.NewTx(&types.TxInternalDataLegacy{ 812 AccountNonce: uint64(*args.Nonce), 813 Price: (*big.Int)(args.GasPrice), 814 GasLimit: uint64(*args.Gas), 815 Recipient: args.To, 816 Amount: (*big.Int)(args.Value), 817 Payload: args.data(), 818 }) 819 } 820 return tx, nil 821 }