github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/cmd/evm/internal/t8ntool/tx_iterator.go (about) 1 // Copyright 2023 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package t8ntool 18 19 import ( 20 "bytes" 21 "crypto/ecdsa" 22 "encoding/json" 23 "fmt" 24 "io" 25 "os" 26 "strings" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/common/hexutil" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/params" 33 "github.com/ethereum/go-ethereum/rlp" 34 ) 35 36 // txWithKey is a helper-struct, to allow us to use the types.Transaction along with 37 // a `secretKey`-field, for input 38 type txWithKey struct { 39 key *ecdsa.PrivateKey 40 tx *types.Transaction 41 protected bool 42 } 43 44 func (t *txWithKey) UnmarshalJSON(input []byte) error { 45 // Read the metadata, if present 46 type txMetadata struct { 47 Key *common.Hash `json:"secretKey"` 48 Protected *bool `json:"protected"` 49 } 50 var data txMetadata 51 if err := json.Unmarshal(input, &data); err != nil { 52 return err 53 } 54 if data.Key != nil { 55 k := data.Key.Hex()[2:] 56 if ecdsaKey, err := crypto.HexToECDSA(k); err != nil { 57 return err 58 } else { 59 t.key = ecdsaKey 60 } 61 } 62 if data.Protected != nil { 63 t.protected = *data.Protected 64 } else { 65 t.protected = true 66 } 67 // Now, read the transaction itself 68 var tx types.Transaction 69 if err := json.Unmarshal(input, &tx); err != nil { 70 return err 71 } 72 t.tx = &tx 73 return nil 74 } 75 76 // signUnsignedTransactions converts the input txs to canonical transactions. 77 // 78 // The transactions can have two forms, either 79 // 1. unsigned or 80 // 2. signed 81 // 82 // For (1), r, s, v, need so be zero, and the `secretKey` needs to be set. 83 // If so, we sign it here and now, with the given `secretKey` 84 // If the condition above is not met, then it's considered a signed transaction. 85 // 86 // To manage this, we read the transactions twice, first trying to read the secretKeys, 87 // and secondly to read them with the standard tx json format 88 func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Transactions, error) { 89 var signedTxs []*types.Transaction 90 for i, tx := range txs { 91 var ( 92 v, r, s = tx.tx.RawSignatureValues() 93 signed *types.Transaction 94 err error 95 ) 96 if tx.key == nil || v.BitLen()+r.BitLen()+s.BitLen() != 0 { 97 // Already signed 98 signedTxs = append(signedTxs, tx.tx) 99 continue 100 } 101 // This transaction needs to be signed 102 if tx.protected { 103 signed, err = types.SignTx(tx.tx, signer, tx.key) 104 } else { 105 signed, err = types.SignTx(tx.tx, types.FrontierSigner{}, tx.key) 106 } 107 if err != nil { 108 return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err)) 109 } 110 signedTxs = append(signedTxs, signed) 111 } 112 return signedTxs, nil 113 } 114 115 func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *params.ChainConfig) (txIterator, error) { 116 var txsWithKeys []*txWithKey 117 if txStr != stdinSelector { 118 data, err := os.ReadFile(txStr) 119 if err != nil { 120 return nil, NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) 121 } 122 if strings.HasSuffix(txStr, ".rlp") { // A file containing an rlp list 123 var body hexutil.Bytes 124 if err := json.Unmarshal(data, &body); err != nil { 125 return nil, err 126 } 127 return newRlpTxIterator(body), nil 128 } 129 if err := json.Unmarshal(data, &txsWithKeys); err != nil { 130 return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshalling txs-file: %v", err)) 131 } 132 } else { 133 if len(inputData.TxRlp) > 0 { 134 // Decode the body of already signed transactions 135 return newRlpTxIterator(common.FromHex(inputData.TxRlp)), nil 136 } 137 // JSON encoded transactions 138 txsWithKeys = inputData.Txs 139 } 140 // We may have to sign the transactions. 141 signer := types.LatestSignerForChainID(chainConfig.ChainID) 142 txs, err := signUnsignedTransactions(txsWithKeys, signer) 143 return newSliceTxIterator(txs), err 144 } 145 146 type txIterator interface { 147 // Next returns true until EOF 148 Next() bool 149 // Tx returns the next transaction, OR an error. 150 Tx() (*types.Transaction, error) 151 } 152 153 type sliceTxIterator struct { 154 idx int 155 txs []*types.Transaction 156 } 157 158 func newSliceTxIterator(transactions types.Transactions) txIterator { 159 return &sliceTxIterator{0, transactions} 160 } 161 162 func (ait *sliceTxIterator) Next() bool { 163 return ait.idx < len(ait.txs) 164 } 165 166 func (ait *sliceTxIterator) Tx() (*types.Transaction, error) { 167 if ait.idx < len(ait.txs) { 168 ait.idx++ 169 return ait.txs[ait.idx-1], nil 170 } 171 return nil, io.EOF 172 } 173 174 type rlpTxIterator struct { 175 in *rlp.Stream 176 } 177 178 func newRlpTxIterator(rlpData []byte) txIterator { 179 in := rlp.NewStream(bytes.NewBuffer(rlpData), 1024*1024) 180 in.List() 181 return &rlpTxIterator{in} 182 } 183 184 func (it *rlpTxIterator) Next() bool { 185 return it.in.MoreDataInList() 186 } 187 188 func (it *rlpTxIterator) Tx() (*types.Transaction, error) { 189 var a types.Transaction 190 if err := it.in.Decode(&a); err != nil { 191 return nil, err 192 } 193 return &a, nil 194 }