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