gitee.com/liu-zhao234568/cntest@v1.0.0/cmd/evm/internal/t8ntool/transition.go (about) 1 // Copyright 2020 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 "crypto/ecdsa" 21 "encoding/json" 22 "errors" 23 "fmt" 24 "io/ioutil" 25 "math/big" 26 "os" 27 "path" 28 29 "gitee.com/liu-zhao234568/cntest/common" 30 "gitee.com/liu-zhao234568/cntest/common/hexutil" 31 "gitee.com/liu-zhao234568/cntest/core" 32 "gitee.com/liu-zhao234568/cntest/core/state" 33 "gitee.com/liu-zhao234568/cntest/core/types" 34 "gitee.com/liu-zhao234568/cntest/core/vm" 35 "gitee.com/liu-zhao234568/cntest/crypto" 36 "gitee.com/liu-zhao234568/cntest/log" 37 "gitee.com/liu-zhao234568/cntest/params" 38 "gitee.com/liu-zhao234568/cntest/rlp" 39 "gitee.com/liu-zhao234568/cntest/tests" 40 "gopkg.in/urfave/cli.v1" 41 ) 42 43 const ( 44 ErrorEVM = 2 45 ErrorVMConfig = 3 46 ErrorMissingBlockhash = 4 47 48 ErrorJson = 10 49 ErrorIO = 11 50 51 stdinSelector = "stdin" 52 ) 53 54 type NumberedError struct { 55 errorCode int 56 err error 57 } 58 59 func NewError(errorCode int, err error) *NumberedError { 60 return &NumberedError{errorCode, err} 61 } 62 63 func (n *NumberedError) Error() string { 64 return fmt.Sprintf("ERROR(%d): %v", n.errorCode, n.err.Error()) 65 } 66 67 func (n *NumberedError) Code() int { 68 return n.errorCode 69 } 70 71 type input struct { 72 Alloc core.GenesisAlloc `json:"alloc,omitempty"` 73 Env *stEnv `json:"env,omitempty"` 74 Txs []*txWithKey `json:"txs,omitempty"` 75 } 76 77 func Main(ctx *cli.Context) error { 78 // Configure the go-ethereum logger 79 glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 80 glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) 81 log.Root().SetHandler(glogger) 82 83 var ( 84 err error 85 tracer vm.Tracer 86 baseDir = "" 87 ) 88 var getTracer func(txIndex int, txHash common.Hash) (vm.Tracer, error) 89 90 // If user specified a basedir, make sure it exists 91 if ctx.IsSet(OutputBasedir.Name) { 92 if base := ctx.String(OutputBasedir.Name); len(base) > 0 { 93 err := os.MkdirAll(base, 0755) // //rw-r--r-- 94 if err != nil { 95 return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) 96 } 97 baseDir = base 98 } 99 } 100 if ctx.Bool(TraceFlag.Name) { 101 // Configure the EVM logger 102 logConfig := &vm.LogConfig{ 103 DisableStack: ctx.Bool(TraceDisableStackFlag.Name), 104 DisableMemory: ctx.Bool(TraceDisableMemoryFlag.Name), 105 DisableReturnData: ctx.Bool(TraceDisableReturnDataFlag.Name), 106 Debug: true, 107 } 108 var prevFile *os.File 109 // This one closes the last file 110 defer func() { 111 if prevFile != nil { 112 prevFile.Close() 113 } 114 }() 115 getTracer = func(txIndex int, txHash common.Hash) (vm.Tracer, error) { 116 if prevFile != nil { 117 prevFile.Close() 118 } 119 traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) 120 if err != nil { 121 return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) 122 } 123 prevFile = traceFile 124 return vm.NewJSONLogger(logConfig, traceFile), nil 125 } 126 } else { 127 getTracer = func(txIndex int, txHash common.Hash) (tracer vm.Tracer, err error) { 128 return nil, nil 129 } 130 } 131 // We need to load three things: alloc, env and transactions. May be either in 132 // stdin input or in files. 133 // Check if anything needs to be read from stdin 134 var ( 135 prestate Prestate 136 txs types.Transactions // txs to apply 137 allocStr = ctx.String(InputAllocFlag.Name) 138 139 envStr = ctx.String(InputEnvFlag.Name) 140 txStr = ctx.String(InputTxsFlag.Name) 141 inputData = &input{} 142 ) 143 // Figure out the prestate alloc 144 if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector { 145 decoder := json.NewDecoder(os.Stdin) 146 if err := decoder.Decode(inputData); err != nil { 147 return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err)) 148 } 149 } 150 if allocStr != stdinSelector { 151 inFile, err := os.Open(allocStr) 152 if err != nil { 153 return NewError(ErrorIO, fmt.Errorf("failed reading alloc file: %v", err)) 154 } 155 defer inFile.Close() 156 decoder := json.NewDecoder(inFile) 157 if err := decoder.Decode(&inputData.Alloc); err != nil { 158 return NewError(ErrorJson, fmt.Errorf("failed unmarshaling alloc-file: %v", err)) 159 } 160 } 161 prestate.Pre = inputData.Alloc 162 163 // Set the block environment 164 if envStr != stdinSelector { 165 inFile, err := os.Open(envStr) 166 if err != nil { 167 return NewError(ErrorIO, fmt.Errorf("failed reading env file: %v", err)) 168 } 169 defer inFile.Close() 170 decoder := json.NewDecoder(inFile) 171 var env stEnv 172 if err := decoder.Decode(&env); err != nil { 173 return NewError(ErrorJson, fmt.Errorf("failed unmarshaling env-file: %v", err)) 174 } 175 inputData.Env = &env 176 } 177 prestate.Env = *inputData.Env 178 179 vmConfig := vm.Config{ 180 Tracer: tracer, 181 Debug: (tracer != nil), 182 } 183 // Construct the chainconfig 184 var chainConfig *params.ChainConfig 185 if cConf, extraEips, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil { 186 return NewError(ErrorVMConfig, fmt.Errorf("failed constructing chain configuration: %v", err)) 187 } else { 188 chainConfig = cConf 189 vmConfig.ExtraEips = extraEips 190 } 191 // Set the chain id 192 chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) 193 194 var txsWithKeys []*txWithKey 195 if txStr != stdinSelector { 196 inFile, err := os.Open(txStr) 197 if err != nil { 198 return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) 199 } 200 defer inFile.Close() 201 decoder := json.NewDecoder(inFile) 202 if err := decoder.Decode(&txsWithKeys); err != nil { 203 return NewError(ErrorJson, fmt.Errorf("failed unmarshaling txs-file: %v", err)) 204 } 205 } else { 206 txsWithKeys = inputData.Txs 207 } 208 // We may have to sign the transactions. 209 signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number))) 210 211 if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil { 212 return NewError(ErrorJson, fmt.Errorf("failed signing transactions: %v", err)) 213 } 214 // Sanity check, to not `panic` in state_transition 215 if chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) { 216 if prestate.Env.BaseFee == nil { 217 return NewError(ErrorVMConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) 218 } 219 } 220 // Run the test and aggregate the result 221 s, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer) 222 if err != nil { 223 return err 224 } 225 body, _ := rlp.EncodeToBytes(txs) 226 // Dump the excution result 227 collector := make(Alloc) 228 s.DumpToCollector(collector, nil) 229 return dispatchOutput(ctx, baseDir, result, collector, body) 230 } 231 232 // txWithKey is a helper-struct, to allow us to use the types.Transaction along with 233 // a `secretKey`-field, for input 234 type txWithKey struct { 235 key *ecdsa.PrivateKey 236 tx *types.Transaction 237 } 238 239 func (t *txWithKey) UnmarshalJSON(input []byte) error { 240 // Read the secretKey, if present 241 type sKey struct { 242 Key *common.Hash `json:"secretKey"` 243 } 244 var key sKey 245 if err := json.Unmarshal(input, &key); err != nil { 246 return err 247 } 248 if key.Key != nil { 249 k := key.Key.Hex()[2:] 250 if ecdsaKey, err := crypto.HexToECDSA(k); err != nil { 251 return err 252 } else { 253 t.key = ecdsaKey 254 } 255 } 256 // Now, read the transaction itself 257 var tx types.Transaction 258 if err := json.Unmarshal(input, &tx); err != nil { 259 return err 260 } 261 t.tx = &tx 262 return nil 263 } 264 265 // signUnsignedTransactions converts the input txs to canonical transactions. 266 // 267 // The transactions can have two forms, either 268 // 1. unsigned or 269 // 2. signed 270 // For (1), r, s, v, need so be zero, and the `secretKey` needs to be set. 271 // If so, we sign it here and now, with the given `secretKey` 272 // If the condition above is not met, then it's considered a signed transaction. 273 // 274 // To manage this, we read the transactions twice, first trying to read the secretKeys, 275 // and secondly to read them with the standard tx json format 276 func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Transactions, error) { 277 var signedTxs []*types.Transaction 278 for i, txWithKey := range txs { 279 tx := txWithKey.tx 280 key := txWithKey.key 281 v, r, s := tx.RawSignatureValues() 282 if key != nil && v.BitLen()+r.BitLen()+s.BitLen() == 0 { 283 // This transaction needs to be signed 284 signed, err := types.SignTx(tx, signer, key) 285 if err != nil { 286 return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err)) 287 } 288 signedTxs = append(signedTxs, signed) 289 } else { 290 // Already signed 291 signedTxs = append(signedTxs, tx) 292 } 293 } 294 return signedTxs, nil 295 } 296 297 type Alloc map[common.Address]core.GenesisAccount 298 299 func (g Alloc) OnRoot(common.Hash) {} 300 301 func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) { 302 balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10) 303 var storage map[common.Hash]common.Hash 304 if dumpAccount.Storage != nil { 305 storage = make(map[common.Hash]common.Hash) 306 for k, v := range dumpAccount.Storage { 307 storage[k] = common.HexToHash(v) 308 } 309 } 310 genesisAccount := core.GenesisAccount{ 311 Code: dumpAccount.Code, 312 Storage: storage, 313 Balance: balance, 314 Nonce: dumpAccount.Nonce, 315 } 316 g[addr] = genesisAccount 317 } 318 319 // saveFile marshalls the object to the given file 320 func saveFile(baseDir, filename string, data interface{}) error { 321 b, err := json.MarshalIndent(data, "", " ") 322 if err != nil { 323 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 324 } 325 location := path.Join(baseDir, filename) 326 if err = ioutil.WriteFile(location, b, 0644); err != nil { 327 return NewError(ErrorIO, fmt.Errorf("failed writing output: %v", err)) 328 } 329 log.Info("Wrote file", "file", location) 330 return nil 331 } 332 333 // dispatchOutput writes the output data to either stderr or stdout, or to the specified 334 // files 335 func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes) error { 336 stdOutObject := make(map[string]interface{}) 337 stdErrObject := make(map[string]interface{}) 338 dispatch := func(baseDir, fName, name string, obj interface{}) error { 339 switch fName { 340 case "stdout": 341 stdOutObject[name] = obj 342 case "stderr": 343 stdErrObject[name] = obj 344 case "": 345 // don't save 346 default: // save to file 347 if err := saveFile(baseDir, fName, obj); err != nil { 348 return err 349 } 350 } 351 return nil 352 } 353 if err := dispatch(baseDir, ctx.String(OutputAllocFlag.Name), "alloc", alloc); err != nil { 354 return err 355 } 356 if err := dispatch(baseDir, ctx.String(OutputResultFlag.Name), "result", result); err != nil { 357 return err 358 } 359 if err := dispatch(baseDir, ctx.String(OutputBodyFlag.Name), "body", body); err != nil { 360 return err 361 } 362 if len(stdOutObject) > 0 { 363 b, err := json.MarshalIndent(stdOutObject, "", " ") 364 if err != nil { 365 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 366 } 367 os.Stdout.Write(b) 368 } 369 if len(stdErrObject) > 0 { 370 b, err := json.MarshalIndent(stdErrObject, "", " ") 371 if err != nil { 372 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 373 } 374 os.Stderr.Write(b) 375 } 376 return nil 377 }