github.com/core-coin/go-core/v2@v2.1.9/cmd/cvm/internal/t8ntool/transition.go (about) 1 // Copyright 2020 by the Authors 2 // This file is part of go-core. 3 // 4 // go-core 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-core 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-core. 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 "gopkg.in/urfave/cli.v1" 28 29 "github.com/core-coin/go-core/v2/common" 30 "github.com/core-coin/go-core/v2/core" 31 "github.com/core-coin/go-core/v2/core/state" 32 "github.com/core-coin/go-core/v2/core/types" 33 "github.com/core-coin/go-core/v2/core/vm" 34 "github.com/core-coin/go-core/v2/log" 35 "github.com/core-coin/go-core/v2/params" 36 "github.com/core-coin/go-core/v2/tests" 37 ) 38 39 const ( 40 ErrorCVM = 2 41 ErrorVMConfig = 3 42 ErrorMissingBlockhash = 4 43 44 ErrorJson = 10 45 ErrorIO = 11 46 47 stdinSelector = "stdin" 48 ) 49 50 type NumberedError struct { 51 errorCode int 52 err error 53 } 54 55 func NewError(errorCode int, err error) *NumberedError { 56 return &NumberedError{errorCode, err} 57 } 58 59 func (n *NumberedError) Error() string { 60 return fmt.Sprintf("ERROR(%d): %v", n.errorCode, n.err.Error()) 61 } 62 63 func (n *NumberedError) Code() int { 64 return n.errorCode 65 } 66 67 type input struct { 68 Alloc core.GenesisAlloc `json:"alloc,omitempty"` 69 Env *stEnv `json:"env,omitempty"` 70 Txs types.Transactions `json:"txs,omitempty"` 71 } 72 73 func Main(ctx *cli.Context) error { 74 // Configure the go-core logger 75 glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 76 glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) 77 log.Root().SetHandler(glogger) 78 79 var ( 80 err error 81 tracer vm.Tracer 82 baseDir = "" 83 ) 84 var getTracer func(txIndex int, txHash common.Hash) (vm.Tracer, error) 85 86 // If user specified a basedir, make sure it exists 87 if ctx.IsSet(OutputBasedir.Name) { 88 if base := ctx.String(OutputBasedir.Name); len(base) > 0 { 89 err := os.MkdirAll(base, 0755) // //rw-r--r-- 90 if err != nil { 91 return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) 92 } 93 baseDir = base 94 } 95 } 96 if ctx.Bool(TraceFlag.Name) { 97 // Configure the CVM logger 98 logConfig := &vm.LogConfig{ 99 DisableStack: ctx.Bool(TraceDisableStackFlag.Name), 100 DisableMemory: ctx.Bool(TraceDisableMemoryFlag.Name), 101 DisableReturnData: ctx.Bool(TraceDisableReturnDataFlag.Name), 102 Debug: true, 103 } 104 var prevFile *os.File 105 // This one closes the last file 106 defer func() { 107 if prevFile != nil { 108 prevFile.Close() 109 } 110 }() 111 getTracer = func(txIndex int, txHash common.Hash) (vm.Tracer, error) { 112 if prevFile != nil { 113 prevFile.Close() 114 } 115 traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) 116 if err != nil { 117 return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) 118 } 119 prevFile = traceFile 120 return vm.NewJSONLogger(logConfig, traceFile), nil 121 } 122 } else { 123 getTracer = func(txIndex int, txHash common.Hash) (tracer vm.Tracer, err error) { 124 return nil, nil 125 } 126 } 127 // We need to load three things: alloc, env and transactions. May be either in 128 // stdin input or in files. 129 // Check if anything needs to be read from stdin 130 var ( 131 prestate Prestate 132 txs types.Transactions // txs to apply 133 allocStr = ctx.String(InputAllocFlag.Name) 134 135 envStr = ctx.String(InputEnvFlag.Name) 136 txStr = ctx.String(InputTxsFlag.Name) 137 inputData = &input{} 138 ) 139 140 if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector { 141 decoder := json.NewDecoder(os.Stdin) 142 decoder.Decode(inputData) 143 } 144 if allocStr != stdinSelector { 145 inFile, err := os.Open(allocStr) 146 if err != nil { 147 return NewError(ErrorIO, fmt.Errorf("failed reading alloc file: %v", err)) 148 } 149 defer inFile.Close() 150 decoder := json.NewDecoder(inFile) 151 if err := decoder.Decode(&inputData.Alloc); err != nil { 152 return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling alloc-file: %v", err)) 153 } 154 } 155 156 if envStr != stdinSelector { 157 inFile, err := os.Open(envStr) 158 if err != nil { 159 return NewError(ErrorIO, fmt.Errorf("failed reading env file: %v", err)) 160 } 161 defer inFile.Close() 162 decoder := json.NewDecoder(inFile) 163 var env stEnv 164 if err := decoder.Decode(&env); err != nil { 165 return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling env-file: %v", err)) 166 } 167 inputData.Env = &env 168 } 169 170 if txStr != stdinSelector { 171 inFile, err := os.Open(txStr) 172 if err != nil { 173 return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) 174 } 175 defer inFile.Close() 176 decoder := json.NewDecoder(inFile) 177 var txs types.Transactions 178 if err := decoder.Decode(&txs); err != nil { 179 return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling txs-file: %v", err)) 180 } 181 inputData.Txs = txs 182 } 183 184 prestate.Pre = inputData.Alloc 185 prestate.Env = *inputData.Env 186 txs = inputData.Txs 187 188 // Iterate over all the tests, run them and aggregate the results 189 vmConfig := vm.Config{ 190 Tracer: tracer, 191 Debug: (tracer != nil), 192 } 193 // Construct the chainconfig 194 var chainConfig *params.ChainConfig 195 if cConf, _, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil { 196 return NewError(ErrorVMConfig, fmt.Errorf("Failed constructing chain configuration: %v", err)) 197 } else { 198 chainConfig = cConf 199 } 200 // Set the chain id 201 chainConfig.NetworkID = big.NewInt(ctx.Int64(NetworkIDFlag.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 }