github.com/klaytn/klaytn@v1.12.1/api/api_public_transaction_pool.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 "context" 25 "encoding/json" 26 "errors" 27 "fmt" 28 "math/big" 29 30 "github.com/klaytn/klaytn/accounts" 31 "github.com/klaytn/klaytn/blockchain/types" 32 "github.com/klaytn/klaytn/common" 33 "github.com/klaytn/klaytn/common/hexutil" 34 "github.com/klaytn/klaytn/crypto" 35 "github.com/klaytn/klaytn/networks/rpc" 36 "github.com/klaytn/klaytn/rlp" 37 ) 38 39 // PublicTransactionPoolAPI exposes methods for the RPC interface 40 type PublicTransactionPoolAPI struct { 41 b Backend 42 nonceLock *AddrLocker 43 } 44 45 // NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. 46 func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI { 47 return &PublicTransactionPoolAPI{b, nonceLock} 48 } 49 50 // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. 51 func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*hexutil.Uint, error) { 52 block, err := s.b.BlockByNumber(ctx, blockNr) 53 if block != nil && err == nil { 54 n := hexutil.Uint(len(block.Transactions())) 55 return &n, err 56 } 57 return nil, err 58 } 59 60 // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. 61 func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) (*hexutil.Uint, error) { 62 block, err := s.b.BlockByHash(ctx, blockHash) 63 if block != nil && err == nil { 64 n := hexutil.Uint(len(block.Transactions())) 65 return &n, err 66 } 67 return nil, err 68 } 69 70 // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. 71 func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { 72 block, err := s.b.BlockByNumber(ctx, blockNr) 73 if block != nil && err == nil { 74 return newRPCTransactionFromBlockIndex(block, uint64(index)), nil 75 } 76 return nil, err 77 } 78 79 // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. 80 func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { 81 block, err := s.b.BlockByHash(ctx, blockHash) 82 if block != nil && err == nil { 83 return newRPCTransactionFromBlockIndex(block, uint64(index)), nil 84 } 85 return nil, err 86 } 87 88 // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. 89 func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (hexutil.Bytes, error) { 90 block, err := s.b.BlockByNumber(ctx, blockNr) 91 if block != nil && err == nil { 92 return newRPCRawTransactionFromBlockIndex(block, uint64(index)), nil 93 } 94 return nil, err 95 } 96 97 // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. 98 func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (hexutil.Bytes, error) { 99 block, err := s.b.BlockByHash(ctx, blockHash) 100 if block != nil && err == nil { 101 return newRPCRawTransactionFromBlockIndex(block, uint64(index)), nil 102 } 103 return nil, err 104 } 105 106 // GetTransactionCount returns the number of transactions the given address has sent for the given block number or hash 107 func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { 108 // Ask transaction pool for the nonce which includes pending transactions 109 if blockNr, ok := blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber { 110 nonce := s.b.GetPoolNonce(ctx, address) 111 return (*hexutil.Uint64)(&nonce), nil 112 } 113 114 // Resolve block number and use its state to ask for the nonce 115 state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) 116 if err != nil { 117 return nil, err 118 } 119 nonce := state.GetNonce(address) 120 return (*hexutil.Uint64)(&nonce), state.Error() 121 } 122 123 func (s *PublicTransactionPoolAPI) GetTransactionBySenderTxHash(ctx context.Context, senderTxHash common.Hash) map[string]interface{} { 124 txhash := s.b.ChainDB().ReadTxHashFromSenderTxHash(senderTxHash) 125 if common.EmptyHash(txhash) { 126 txhash = senderTxHash 127 } 128 return s.GetTransactionByHash(ctx, txhash) 129 } 130 131 // GetTransactionByHash returns the transaction for the given hash 132 func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) map[string]interface{} { 133 // Try to return an already finalized transaction 134 if tx, blockHash, blockNumber, index := s.b.ChainDB().ReadTxAndLookupInfo(hash); tx != nil { 135 return newRPCTransaction(nil, tx, blockHash, blockNumber, index) 136 } 137 // No finalized transaction, try to retrieve it from the pool 138 if tx := s.b.GetPoolTransaction(hash); tx != nil { 139 return newRPCPendingTransaction(tx) 140 } 141 // Transaction unknown, return as such 142 return nil 143 } 144 145 // GetDecodedAnchoringTransactionByHash returns the decoded anchoring data of anchoring transaction for the given hash 146 func (s *PublicTransactionPoolAPI) GetDecodedAnchoringTransactionByHash(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { 147 var tx *types.Transaction 148 149 // Try to return an already finalized transaction 150 if tx, _, _, _ = s.b.ChainDB().ReadTxAndLookupInfo(hash); tx != nil { 151 goto decode 152 } 153 154 // No finalized transaction, try to retrieve it from the pool 155 if tx = s.b.GetPoolTransaction(hash); tx != nil { 156 goto decode 157 } 158 return nil, errors.New("can't find the transaction") 159 160 decode: 161 162 if !tx.Type().IsChainDataAnchoring() { 163 return nil, errors.New("invalid transaction type") 164 } 165 166 data, err := tx.AnchoredData() 167 if err != nil { 168 return nil, err 169 } 170 171 anchoringDataInternal, err := types.DecodeAnchoringData(data) 172 if err != nil { 173 return nil, err 174 } 175 176 str, err := json.Marshal(anchoringDataInternal) 177 if err != nil { 178 return nil, err 179 } 180 181 var result map[string]interface{} 182 json.Unmarshal(str, &result) 183 184 return result, nil 185 } 186 187 // GetRawTransactionByHash returns the bytes of the transaction for the given hash. 188 func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { 189 var tx *types.Transaction 190 191 // Retrieve a finalized transaction, or a pooled otherwise 192 if tx, _, _, _ = s.b.ChainDB().ReadTxAndLookupInfo(hash); tx == nil { 193 if tx = s.b.GetPoolTransaction(hash); tx == nil { 194 // Transaction not found anywhere, abort 195 return nil, nil 196 } 197 } 198 199 // Serialize to RLP and return 200 return rlp.EncodeToBytes(tx) 201 } 202 203 // RpcOutputReceipt converts a receipt to the RPC output with the associated information regarding to the 204 // block in which the receipt is included, the transaction that outputs the receipt, and the receipt itself. 205 func RpcOutputReceipt(header *types.Header, tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, receipt *types.Receipt) map[string]interface{} { 206 if tx == nil || receipt == nil { 207 return nil 208 } 209 210 fields := newRPCTransaction(nil, tx, blockHash, blockNumber, index) 211 212 if receipt.Status != types.ReceiptStatusSuccessful { 213 fields["status"] = hexutil.Uint(types.ReceiptStatusFailed) 214 fields["txError"] = hexutil.Uint(receipt.Status) 215 } else { 216 fields["status"] = hexutil.Uint(receipt.Status) 217 } 218 219 fields["logsBloom"] = receipt.Bloom 220 fields["gasUsed"] = hexutil.Uint64(receipt.GasUsed) 221 222 fields["effectiveGasPrice"] = hexutil.Uint64(tx.EffectiveGasPrice(header).Uint64()) 223 224 if receipt.Logs == nil { 225 fields["logs"] = [][]*types.Log{} 226 } else { 227 fields["logs"] = receipt.Logs 228 } 229 // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation 230 if receipt.ContractAddress != (common.Address{}) { 231 fields["contractAddress"] = receipt.ContractAddress 232 } else { 233 fields["contractAddress"] = nil 234 } 235 236 // Rename field name `hash` to `transactionHash` since this function returns a JSON object of a receipt. 237 fields["transactionHash"] = fields["hash"] 238 delete(fields, "hash") 239 240 return fields 241 } 242 243 func (s *PublicTransactionPoolAPI) GetTransactionReceiptBySenderTxHash(ctx context.Context, senderTxHash common.Hash) (map[string]interface{}, error) { 244 txhash := s.b.ChainDB().ReadTxHashFromSenderTxHash(senderTxHash) 245 if common.EmptyHash(txhash) { 246 txhash = senderTxHash 247 } 248 return s.GetTransactionReceipt(ctx, txhash) 249 } 250 251 // GetTransactionReceipt returns the transaction receipt for the given transaction hash. 252 func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { 253 tx, blockHash, blockNumber, index, receipt := s.b.GetTxLookupInfoAndReceipt(ctx, hash) 254 return s.getTransactionReceipt(ctx, tx, blockHash, blockNumber, index, receipt) 255 } 256 257 // GetTransactionReceiptInCache returns the transaction receipt for the given transaction hash. 258 func (s *PublicTransactionPoolAPI) GetTransactionReceiptInCache(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { 259 tx, blockHash, blockNumber, index, receipt := s.b.GetTxLookupInfoAndReceiptInCache(hash) 260 return s.getTransactionReceipt(ctx, tx, blockHash, blockNumber, index, receipt) 261 } 262 263 // getTransactionReceipt returns the transaction receipt for the given transaction hash. 264 func (s *PublicTransactionPoolAPI) getTransactionReceipt(ctx context.Context, tx *types.Transaction, blockHash common.Hash, 265 blockNumber uint64, index uint64, receipt *types.Receipt, 266 ) (map[string]interface{}, error) { 267 // No error handling is required here. 268 // Header is checked in the following RpcOutputReceipt function 269 header, _ := s.b.HeaderByHash(ctx, blockHash) 270 return RpcOutputReceipt(header, tx, blockHash, blockNumber, index, receipt), nil 271 } 272 273 // sign is a helper function that signs a transaction with the private key of the given address. 274 func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { 275 // Look up the wallet containing the requested signer 276 account := accounts.Account{Address: addr} 277 278 wallet, err := s.b.AccountManager().Find(account) 279 if err != nil { 280 return nil, err 281 } 282 // Request the wallet to sign the transaction 283 return wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) 284 } 285 286 // signAsFeePayer is a helper function that signs a transaction as a fee payer with the private key of the given address. 287 func (s *PublicTransactionPoolAPI) signAsFeePayer(addr common.Address, tx *types.Transaction) (*types.Transaction, error) { 288 // Look up the wallet containing the requested signer 289 account := accounts.Account{Address: addr} 290 291 wallet, err := s.b.AccountManager().Find(account) 292 if err != nil { 293 return nil, err 294 } 295 // Request the wallet to sign the transaction 296 return wallet.SignTxAsFeePayer(account, tx, s.b.ChainConfig().ChainID) 297 } 298 299 var submitTxCount = 0 300 301 // submitTransaction is a helper function that submits tx to txPool and logs a message. 302 func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) { 303 // submitTxCount++ 304 // log.Error("### submitTransaction","tx",submitTxCount) 305 306 if err := b.SendTx(ctx, tx); err != nil { 307 return common.Hash{}, err 308 } 309 // TODO-Klaytn only enable on logging 310 //if tx.To() == nil { 311 // signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number()) 312 // from, err := types.Sender(signer, tx) 313 // if err != nil { 314 // logger.Error("api.submitTransaction make from","err",err) 315 // return common.Hash{}, err 316 // } 317 // addr := crypto.CreateAddress(from, tx.Nonce()) 318 // logger.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex()) 319 //} else { 320 // logger.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To()) 321 //} 322 return tx.Hash(), nil 323 } 324 325 // SendTransaction creates a transaction for the given argument, sign it and submit it to the 326 // transaction pool. 327 func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) { 328 if args.AccountNonce == nil { 329 // Hold the addresse's mutex around signing to prevent concurrent assignment of 330 // the same nonce to multiple accounts. 331 s.nonceLock.LockAddr(args.From) 332 defer s.nonceLock.UnlockAddr(args.From) 333 } 334 335 signedTx, err := s.SignTransaction(ctx, args) 336 if err != nil { 337 return common.Hash{}, err 338 } 339 340 return submitTransaction(ctx, s.b, signedTx.Tx) 341 } 342 343 // SendTransactionAsFeePayer creates a transaction for the given argument, sign it as a fee payer 344 // and submit it to the transaction pool. 345 func (s *PublicTransactionPoolAPI) SendTransactionAsFeePayer(ctx context.Context, args SendTxArgs) (common.Hash, error) { 346 // Don't allow dynamic assign of values from the setDefaults function since the sender already signed on specific values. 347 if args.TypeInt == nil { 348 return common.Hash{}, errTxArgNilTxType 349 } 350 if args.AccountNonce == nil { 351 return common.Hash{}, errTxArgNilNonce 352 } 353 if args.GasLimit == nil { 354 return common.Hash{}, errTxArgNilGas 355 } 356 if args.Price == nil { 357 return common.Hash{}, errTxArgNilGasPrice 358 } 359 360 if args.TxSignatures == nil { 361 return common.Hash{}, errTxArgNilSenderSig 362 } 363 364 feePayerSignedTx, err := s.SignTransactionAsFeePayer(ctx, args) 365 if err != nil { 366 return common.Hash{}, err 367 } 368 369 return submitTransaction(ctx, s.b, feePayerSignedTx.Tx) 370 } 371 372 // SendRawTransaction will add the signed transaction to the transaction pool. 373 // The sender is responsible for signing the transaction and using the correct nonce. 374 func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) { 375 tx := new(types.Transaction) 376 if err := rlp.DecodeBytes(encodedTx, tx); err != nil { 377 return common.Hash{}, err 378 } 379 return submitTransaction(ctx, s.b, tx) 380 } 381 382 // Sign calculates an ECDSA signature for: 383 // keccack256("\x19Klaytn Signed Message:\n" + len(message) + message). 384 // 385 // Note, the produced signature conforms to the secp256k1 curve R, S and V values, 386 // where the V value will be 27 or 28 for legacy reasons. 387 // 388 // The account associated with addr must be unlocked. 389 // 390 // https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign 391 func (s *PublicTransactionPoolAPI) Sign(addr common.Address, data hexutil.Bytes) (hexutil.Bytes, error) { 392 // Look up the wallet containing the requested signer 393 account := accounts.Account{Address: addr} 394 395 wallet, err := s.b.AccountManager().Find(account) 396 if err != nil { 397 return nil, err 398 } 399 // Sign the requested hash with the wallet 400 signature, err := wallet.SignHash(account, signHash(data)) 401 if err == nil { 402 signature[crypto.RecoveryIDOffset] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper 403 } 404 return signature, err 405 } 406 407 // SignTransactionResult represents a RLP encoded signed transaction. 408 type SignTransactionResult struct { 409 Raw hexutil.Bytes `json:"raw"` 410 Tx *types.Transaction `json:"tx"` 411 } 412 413 // SignTransaction will sign the given transaction with the from account. 414 // The node needs to have the private key of the account corresponding with 415 // the given from address and it needs to be unlocked. 416 func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args SendTxArgs) (*SignTransactionResult, error) { 417 if args.TypeInt != nil && args.TypeInt.IsEthTypedTransaction() { 418 if args.Price == nil && (args.MaxPriorityFeePerGas == nil || args.MaxFeePerGas == nil) { 419 return nil, fmt.Errorf("missing gasPrice or maxFeePerGas/maxPriorityFeePerGas") 420 } 421 } 422 423 // No need to obtain the noncelock mutex, since we won't be sending this 424 // tx into the transaction pool, but right back to the user 425 if err := args.setDefaults(ctx, s.b); err != nil { 426 return nil, err 427 } 428 tx, err := args.toTransaction() 429 if err != nil { 430 return nil, err 431 } 432 signedTx, err := s.sign(args.From, tx) 433 if err != nil { 434 return nil, err 435 } 436 data, err := rlp.EncodeToBytes(signedTx) 437 if err != nil { 438 return nil, err 439 } 440 return &SignTransactionResult{data, signedTx}, nil 441 } 442 443 // SignTransactionAsFeePayer will sign the given transaction as a fee payer 444 // with the from account. The node needs to have the private key of the account 445 // corresponding with the given from address and it needs to be unlocked. 446 func (s *PublicTransactionPoolAPI) SignTransactionAsFeePayer(ctx context.Context, args SendTxArgs) (*SignTransactionResult, error) { 447 // Allows setting a default nonce value of the sender just for the case the fee payer tries to sign a tx earlier than the sender. 448 if err := args.setDefaults(ctx, s.b); err != nil { 449 return nil, err 450 } 451 tx, err := args.toTransaction() 452 if err != nil { 453 return nil, err 454 } 455 // Don't return errors for nil signature allowing the fee payer to sign a tx earlier than the sender. 456 if args.TxSignatures != nil { 457 tx.SetSignature(args.TxSignatures.ToTxSignatures()) 458 } 459 feePayer, err := tx.FeePayer() 460 if err != nil { 461 return nil, errTxArgInvalidFeePayer 462 } 463 feePayerSignedTx, err := s.signAsFeePayer(feePayer, tx) 464 if err != nil { 465 return nil, err 466 } 467 data, err := rlp.EncodeToBytes(feePayerSignedTx) 468 if err != nil { 469 return nil, err 470 } 471 return &SignTransactionResult{data, feePayerSignedTx}, nil 472 } 473 474 func getAccountsFromWallets(wallets []accounts.Wallet) map[common.Address]struct{} { 475 accounts := make(map[common.Address]struct{}) 476 for _, wallet := range wallets { 477 for _, account := range wallet.Accounts() { 478 accounts[account.Address] = struct{}{} 479 } 480 } 481 return accounts 482 } 483 484 // PendingTransactions returns the transactions that are in the transaction pool 485 // and have a from address that is one of the accounts this node manages. 486 func (s *PublicTransactionPoolAPI) PendingTransactions() ([]map[string]interface{}, error) { 487 pending, err := s.b.GetPoolTransactions() 488 if err != nil { 489 return nil, err 490 } 491 accounts := getAccountsFromWallets(s.b.AccountManager().Wallets()) 492 transactions := make([]map[string]interface{}, 0, len(pending)) 493 for _, tx := range pending { 494 from := getFrom(tx) 495 if _, exists := accounts[from]; exists { 496 transactions = append(transactions, newRPCPendingTransaction(tx)) 497 } 498 } 499 return transactions, nil 500 } 501 502 // Resend accepts an existing transaction and a new gas price and limit. It will remove 503 // the given transaction from the pool and reinsert it with the new gas price and limit. 504 func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { 505 return resend(s, ctx, &sendArgs, gasPrice, gasLimit) 506 } 507 508 // Resend accepts an existing transaction and a new gas price and limit. It will remove 509 // the given transaction from the pool and reinsert it with the new gas price and limit. 510 func resend(s *PublicTransactionPoolAPI, ctx context.Context, sendArgs NewTxArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { 511 if sendArgs.nonce() == nil { 512 return common.Hash{}, fmt.Errorf("missing transaction nonce in transaction spec") 513 } 514 if err := sendArgs.setDefaults(ctx, s.b); err != nil { 515 return common.Hash{}, err 516 } 517 matchTx, err := sendArgs.toTransaction() 518 if err != nil { 519 return common.Hash{}, err 520 } 521 pending, err := s.b.GetPoolTransactions() 522 if err != nil { 523 return common.Hash{}, err 524 } 525 526 for _, p := range pending { 527 signer := types.LatestSignerForChainID(p.ChainId()) 528 wantSigHash := signer.Hash(matchTx) 529 530 if pFrom, err := types.Sender(signer, p); err == nil && pFrom == sendArgs.from() && signer.Hash(p) == wantSigHash { 531 // Match. Re-sign and send the transaction. 532 if gasPrice != nil && (*big.Int)(gasPrice).Sign() != 0 { 533 sendArgs.setGasPrice(gasPrice) 534 } 535 if gasLimit != nil && *gasLimit != 0 { 536 sendArgs.setGas(gasLimit) 537 } 538 tx, err := sendArgs.toTransaction() 539 if err != nil { 540 return common.Hash{}, err 541 } 542 signedTx, err := s.sign(sendArgs.from(), tx) 543 if err != nil { 544 return common.Hash{}, err 545 } 546 if err = s.b.SendTx(ctx, signedTx); err != nil { 547 return common.Hash{}, err 548 } 549 return signedTx.Hash(), nil 550 } 551 } 552 553 return common.Hash{}, fmt.Errorf("Transaction %#x not found", matchTx.Hash()) 554 } 555 556 // RecoverFromTransaction recovers the sender address from a signed raw transaction. 557 // The signature is validated against the sender account's key configuration at the given block number. 558 func (s *PublicTransactionPoolAPI) RecoverFromTransaction(ctx context.Context, encodedTx hexutil.Bytes, blockNumber rpc.BlockNumber) (common.Address, error) { 559 if len(encodedTx) == 0 { 560 return common.Address{}, fmt.Errorf("Empty input") 561 } 562 if 0 < encodedTx[0] && encodedTx[0] < 0x8 { // TODO: Add helper to distinguish eth vs klay txtypes 563 ethEnvelope := []byte{byte(types.EthereumTxTypeEnvelope)} 564 encodedTx = append(ethEnvelope, encodedTx...) 565 } 566 567 tx := new(types.Transaction) 568 if err := rlp.DecodeBytes(encodedTx, tx); err != nil { 569 return common.Address{}, err 570 } 571 572 var bn uint64 573 if blockNumber == rpc.LatestBlockNumber || blockNumber == rpc.PendingBlockNumber { 574 bn = s.b.CurrentBlock().NumberU64() 575 } else { 576 bn = blockNumber.Uint64() 577 } 578 579 signer := types.MakeSigner(s.b.ChainConfig(), new(big.Int).SetUint64(bn)) 580 state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNumber) 581 if err != nil { 582 return common.Address{}, err 583 } 584 _, err = tx.ValidateSender(signer, state, bn) 585 if err != nil { 586 return common.Address{}, err 587 } 588 return tx.From() 589 } 590 591 // RecoverFromMessage validates that the message is signed by one of the keys in the given account. 592 // Returns the recovered signer address, which may be different from the account address. 593 func (s *PublicTransactionPoolAPI) RecoverFromMessage( 594 ctx context.Context, address common.Address, data, sig hexutil.Bytes, blockNumber rpc.BlockNumber, 595 ) (common.Address, error) { 596 if len(sig) != crypto.SignatureLength { 597 return common.Address{}, fmt.Errorf("signature must be 65 bytes long") 598 } 599 if sig[crypto.RecoveryIDOffset] != 27 && sig[crypto.RecoveryIDOffset] != 28 { 600 return common.Address{}, fmt.Errorf("invalid Klaytn signature (V is not 27 or 28)") 601 } 602 603 // Transform yellow paper V from 27/28 to 0/1 604 sig[crypto.RecoveryIDOffset] -= 27 605 606 state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNumber) 607 if err != nil { 608 return common.Address{}, err 609 } 610 key := state.GetKey(address) 611 612 // We cannot identify if the signature has signed with klay or eth prefix without the signer's address. 613 // Even though a user signed message with eth prefix, it will return invalid something in klayEcRecover. 614 // We should call each rcrecover function separately and the actual result will be checked in ValidateMember. 615 var recoverErr error 616 if pubkey, err := klayEcRecover(data, sig); err == nil { 617 if key.ValidateMember(pubkey, address) { 618 return crypto.PubkeyToAddress(*pubkey), nil 619 } 620 } else { 621 recoverErr = err 622 } 623 if pubkey, err := ethEcRecover(data, sig); err == nil { 624 if key.ValidateMember(pubkey, address) { 625 return crypto.PubkeyToAddress(*pubkey), nil 626 } 627 } else { 628 recoverErr = err 629 } 630 if recoverErr != nil { 631 return common.Address{}, recoverErr 632 } else { 633 return common.Address{}, errors.New("Invalid signature") 634 } 635 }