github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/cmd/evm/internal/t8ntool/transaction.go (about) 1 // Copyright 2021 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 "encoding/json" 21 "errors" 22 "fmt" 23 "math/big" 24 "os" 25 "strings" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/hexutil" 29 "github.com/ethereum/go-ethereum/core" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/params" 32 "github.com/ethereum/go-ethereum/rlp" 33 "github.com/ethereum/go-ethereum/tests" 34 "github.com/urfave/cli/v2" 35 ) 36 37 type result struct { 38 Error error 39 Address common.Address 40 Hash common.Hash 41 IntrinsicGas uint64 42 } 43 44 // MarshalJSON marshals as JSON with a hash. 45 func (r *result) MarshalJSON() ([]byte, error) { 46 type xx struct { 47 Error string `json:"error,omitempty"` 48 Address *common.Address `json:"address,omitempty"` 49 Hash *common.Hash `json:"hash,omitempty"` 50 IntrinsicGas hexutil.Uint64 `json:"intrinsicGas,omitempty"` 51 } 52 var out xx 53 if r.Error != nil { 54 out.Error = r.Error.Error() 55 } 56 if r.Address != (common.Address{}) { 57 out.Address = &r.Address 58 } 59 if r.Hash != (common.Hash{}) { 60 out.Hash = &r.Hash 61 } 62 out.IntrinsicGas = hexutil.Uint64(r.IntrinsicGas) 63 return json.Marshal(out) 64 } 65 66 func Transaction(ctx *cli.Context) error { 67 var ( 68 err error 69 ) 70 // We need to load the transactions. May be either in stdin input or in files. 71 // Check if anything needs to be read from stdin 72 var ( 73 txStr = ctx.String(InputTxsFlag.Name) 74 inputData = &input{} 75 chainConfig *params.ChainConfig 76 ) 77 // Construct the chainconfig 78 if cConf, _, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil { 79 return NewError(ErrorConfig, fmt.Errorf("failed constructing chain configuration: %v", err)) 80 } else { 81 chainConfig = cConf 82 } 83 // Set the chain id 84 chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) 85 var body hexutil.Bytes 86 if txStr == stdinSelector { 87 decoder := json.NewDecoder(os.Stdin) 88 if err := decoder.Decode(inputData); err != nil { 89 return NewError(ErrorJson, fmt.Errorf("failed unmarshalling stdin: %v", err)) 90 } 91 // Decode the body of already signed transactions 92 body = common.FromHex(inputData.TxRlp) 93 } else { 94 // Read input from file 95 inFile, err := os.Open(txStr) 96 if err != nil { 97 return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) 98 } 99 defer inFile.Close() 100 decoder := json.NewDecoder(inFile) 101 if strings.HasSuffix(txStr, ".rlp") { 102 if err := decoder.Decode(&body); err != nil { 103 return err 104 } 105 } else { 106 return NewError(ErrorIO, errors.New("only rlp supported")) 107 } 108 } 109 signer := types.MakeSigner(chainConfig, new(big.Int), 0) 110 // We now have the transactions in 'body', which is supposed to be an 111 // rlp list of transactions 112 it, err := rlp.NewListIterator([]byte(body)) 113 if err != nil { 114 return err 115 } 116 var results []result 117 for it.Next() { 118 if err := it.Err(); err != nil { 119 return NewError(ErrorIO, err) 120 } 121 var tx types.Transaction 122 err := rlp.DecodeBytes(it.Value(), &tx) 123 if err != nil { 124 results = append(results, result{Error: err}) 125 continue 126 } 127 r := result{Hash: tx.Hash()} 128 if sender, err := types.Sender(signer, &tx); err != nil { 129 r.Error = err 130 results = append(results, r) 131 continue 132 } else { 133 r.Address = sender 134 } 135 // Check intrinsic gas 136 if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil, 137 chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int), 0)); err != nil { 138 r.Error = err 139 results = append(results, r) 140 continue 141 } else { 142 r.IntrinsicGas = gas 143 if tx.Gas() < gas { 144 r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrIntrinsicGas, tx.Gas(), gas) 145 results = append(results, r) 146 continue 147 } 148 } 149 // Validate <256bit fields 150 switch { 151 case tx.Nonce()+1 < tx.Nonce(): 152 r.Error = errors.New("nonce exceeds 2^64-1") 153 case tx.Value().BitLen() > 256: 154 r.Error = errors.New("value exceeds 256 bits") 155 case tx.GasPrice().BitLen() > 256: 156 r.Error = errors.New("gasPrice exceeds 256 bits") 157 case tx.GasTipCap().BitLen() > 256: 158 r.Error = errors.New("maxPriorityFeePerGas exceeds 256 bits") 159 case tx.GasFeeCap().BitLen() > 256: 160 r.Error = errors.New("maxFeePerGas exceeds 256 bits") 161 case tx.GasFeeCap().Cmp(tx.GasTipCap()) < 0: 162 r.Error = errors.New("maxFeePerGas < maxPriorityFeePerGas") 163 case new(big.Int).Mul(tx.GasPrice(), new(big.Int).SetUint64(tx.Gas())).BitLen() > 256: 164 r.Error = errors.New("gas * gasPrice exceeds 256 bits") 165 case new(big.Int).Mul(tx.GasFeeCap(), new(big.Int).SetUint64(tx.Gas())).BitLen() > 256: 166 r.Error = errors.New("gas * maxFeePerGas exceeds 256 bits") 167 } 168 // Check whether the init code size has been exceeded. 169 if chainConfig.IsShanghai(new(big.Int), 0) && tx.To() == nil && len(tx.Data()) > params.MaxInitCodeSize { 170 r.Error = errors.New("max initcode size exceeded") 171 } 172 results = append(results, r) 173 } 174 out, err := json.MarshalIndent(results, "", " ") 175 fmt.Println(string(out)) 176 return err 177 }