gitlab.com/lightnet1/go-ethereum@v1.9.30/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 "encoding/json" 21 "fmt" 22 "io/ioutil" 23 "math/big" 24 "os" 25 "path" 26 27 "gitlab.com/lightnet1/go-ethereum/common" 28 "gitlab.com/lightnet1/go-ethereum/core" 29 "gitlab.com/lightnet1/go-ethereum/core/state" 30 "gitlab.com/lightnet1/go-ethereum/core/types" 31 "gitlab.com/lightnet1/go-ethereum/core/vm" 32 "gitlab.com/lightnet1/go-ethereum/log" 33 "gitlab.com/lightnet1/go-ethereum/params" 34 "gitlab.com/lightnet1/go-ethereum/tests" 35 "gopkg.in/urfave/cli.v1" 36 ) 37 38 const ( 39 ErrorEVM = 2 40 ErrorVMConfig = 3 41 ErrorMissingBlockhash = 4 42 43 ErrorJson = 10 44 ErrorIO = 11 45 46 stdinSelector = "stdin" 47 ) 48 49 type NumberedError struct { 50 errorCode int 51 err error 52 } 53 54 func NewError(errorCode int, err error) *NumberedError { 55 return &NumberedError{errorCode, err} 56 } 57 58 func (n *NumberedError) Error() string { 59 return fmt.Sprintf("ERROR(%d): %v", n.errorCode, n.err.Error()) 60 } 61 62 func (n *NumberedError) Code() int { 63 return n.errorCode 64 } 65 66 type input struct { 67 Alloc core.GenesisAlloc `json:"alloc,omitempty"` 68 Env *stEnv `json:"env,omitempty"` 69 Txs types.Transactions `json:"txs,omitempty"` 70 } 71 72 func Main(ctx *cli.Context) error { 73 // Configure the go-ethereum logger 74 glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 75 glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) 76 log.Root().SetHandler(glogger) 77 78 var ( 79 err error 80 tracer vm.Tracer 81 baseDir = "" 82 ) 83 var getTracer func(txIndex int, txHash common.Hash) (vm.Tracer, error) 84 85 // If user specified a basedir, make sure it exists 86 if ctx.IsSet(OutputBasedir.Name) { 87 if base := ctx.String(OutputBasedir.Name); len(base) > 0 { 88 err := os.MkdirAll(base, 0755) // //rw-r--r-- 89 if err != nil { 90 return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) 91 } 92 baseDir = base 93 } 94 } 95 if ctx.Bool(TraceFlag.Name) { 96 // Configure the EVM logger 97 logConfig := &vm.LogConfig{ 98 DisableStack: ctx.Bool(TraceDisableStackFlag.Name), 99 DisableMemory: ctx.Bool(TraceDisableMemoryFlag.Name), 100 DisableReturnData: ctx.Bool(TraceDisableReturnDataFlag.Name), 101 Debug: true, 102 } 103 var prevFile *os.File 104 // This one closes the last file 105 defer func() { 106 if prevFile != nil { 107 prevFile.Close() 108 } 109 }() 110 getTracer = func(txIndex int, txHash common.Hash) (vm.Tracer, error) { 111 if prevFile != nil { 112 prevFile.Close() 113 } 114 traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) 115 if err != nil { 116 return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) 117 } 118 prevFile = traceFile 119 return vm.NewJSONLogger(logConfig, traceFile), nil 120 } 121 } else { 122 getTracer = func(txIndex int, txHash common.Hash) (tracer vm.Tracer, err error) { 123 return nil, nil 124 } 125 } 126 // We need to load three things: alloc, env and transactions. May be either in 127 // stdin input or in files. 128 // Check if anything needs to be read from stdin 129 var ( 130 prestate Prestate 131 txs types.Transactions // txs to apply 132 allocStr = ctx.String(InputAllocFlag.Name) 133 134 envStr = ctx.String(InputEnvFlag.Name) 135 txStr = ctx.String(InputTxsFlag.Name) 136 inputData = &input{} 137 ) 138 139 if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector { 140 decoder := json.NewDecoder(os.Stdin) 141 decoder.Decode(inputData) 142 } 143 if allocStr != stdinSelector { 144 inFile, err := os.Open(allocStr) 145 if err != nil { 146 return NewError(ErrorIO, fmt.Errorf("failed reading alloc file: %v", err)) 147 } 148 defer inFile.Close() 149 decoder := json.NewDecoder(inFile) 150 if err := decoder.Decode(&inputData.Alloc); err != nil { 151 return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling alloc-file: %v", err)) 152 } 153 } 154 155 if envStr != stdinSelector { 156 inFile, err := os.Open(envStr) 157 if err != nil { 158 return NewError(ErrorIO, fmt.Errorf("failed reading env file: %v", err)) 159 } 160 defer inFile.Close() 161 decoder := json.NewDecoder(inFile) 162 var env stEnv 163 if err := decoder.Decode(&env); err != nil { 164 return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling env-file: %v", err)) 165 } 166 inputData.Env = &env 167 } 168 169 if txStr != stdinSelector { 170 inFile, err := os.Open(txStr) 171 if err != nil { 172 return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) 173 } 174 defer inFile.Close() 175 decoder := json.NewDecoder(inFile) 176 var txs types.Transactions 177 if err := decoder.Decode(&txs); err != nil { 178 return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling txs-file: %v", err)) 179 } 180 inputData.Txs = txs 181 } 182 183 prestate.Pre = inputData.Alloc 184 prestate.Env = *inputData.Env 185 txs = inputData.Txs 186 187 // Iterate over all the tests, run them and aggregate the results 188 vmConfig := vm.Config{ 189 Tracer: tracer, 190 Debug: (tracer != nil), 191 } 192 // Construct the chainconfig 193 var chainConfig *params.ChainConfig 194 if cConf, extraEips, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil { 195 return NewError(ErrorVMConfig, fmt.Errorf("Failed constructing chain configuration: %v", err)) 196 } else { 197 chainConfig = cConf 198 vmConfig.ExtraEips = extraEips 199 } 200 // Set the chain id 201 chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) 202 203 // Run the test and aggregate the result 204 state, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer) 205 if err != nil { 206 return err 207 } 208 // Dump the excution result 209 //postAlloc := state.DumpGenesisFormat(false, false, false) 210 collector := make(Alloc) 211 state.DumpToCollector(collector, false, false, false, nil, -1) 212 return dispatchOutput(ctx, baseDir, result, collector) 213 214 } 215 216 type Alloc map[common.Address]core.GenesisAccount 217 218 func (g Alloc) OnRoot(common.Hash) {} 219 220 func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) { 221 balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10) 222 var storage map[common.Hash]common.Hash 223 if dumpAccount.Storage != nil { 224 storage = make(map[common.Hash]common.Hash) 225 for k, v := range dumpAccount.Storage { 226 storage[k] = common.HexToHash(v) 227 } 228 } 229 genesisAccount := core.GenesisAccount{ 230 Code: common.FromHex(dumpAccount.Code), 231 Storage: storage, 232 Balance: balance, 233 Nonce: dumpAccount.Nonce, 234 } 235 g[addr] = genesisAccount 236 } 237 238 // saveFile marshalls the object to the given file 239 func saveFile(baseDir, filename string, data interface{}) error { 240 b, err := json.MarshalIndent(data, "", " ") 241 if err != nil { 242 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 243 } 244 if err = ioutil.WriteFile(path.Join(baseDir, filename), b, 0644); err != nil { 245 return NewError(ErrorIO, fmt.Errorf("failed writing output: %v", err)) 246 } 247 return nil 248 } 249 250 // dispatchOutput writes the output data to either stderr or stdout, or to the specified 251 // files 252 func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc) error { 253 stdOutObject := make(map[string]interface{}) 254 stdErrObject := make(map[string]interface{}) 255 dispatch := func(baseDir, fName, name string, obj interface{}) error { 256 switch fName { 257 case "stdout": 258 stdOutObject[name] = obj 259 case "stderr": 260 stdErrObject[name] = obj 261 default: // save to file 262 if err := saveFile(baseDir, fName, obj); err != nil { 263 return err 264 } 265 } 266 return nil 267 } 268 if err := dispatch(baseDir, ctx.String(OutputAllocFlag.Name), "alloc", alloc); err != nil { 269 return err 270 } 271 if err := dispatch(baseDir, ctx.String(OutputResultFlag.Name), "result", result); err != nil { 272 return err 273 } 274 if len(stdOutObject) > 0 { 275 b, err := json.MarshalIndent(stdOutObject, "", " ") 276 if err != nil { 277 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 278 } 279 os.Stdout.Write(b) 280 } 281 if len(stdErrObject) > 0 { 282 b, err := json.MarshalIndent(stdErrObject, "", " ") 283 if err != nil { 284 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 285 } 286 os.Stderr.Write(b) 287 } 288 return nil 289 }