github.com/theQRL/go-zond@v0.1.1/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 "errors" 22 "fmt" 23 "math/big" 24 "os" 25 "path" 26 "strings" 27 28 "github.com/theQRL/go-qrllib/dilithium" 29 "github.com/theQRL/go-zond/common" 30 "github.com/theQRL/go-zond/common/hexutil" 31 "github.com/theQRL/go-zond/consensus/misc" 32 "github.com/theQRL/go-zond/core" 33 "github.com/theQRL/go-zond/core/state" 34 "github.com/theQRL/go-zond/core/types" 35 "github.com/theQRL/go-zond/core/vm" 36 "github.com/theQRL/go-zond/log" 37 "github.com/theQRL/go-zond/params" 38 "github.com/theQRL/go-zond/pqcrypto" 39 "github.com/theQRL/go-zond/rlp" 40 "github.com/theQRL/go-zond/tests" 41 "github.com/theQRL/go-zond/zond/tracers/logger" 42 "github.com/urfave/cli/v2" 43 ) 44 45 const ( 46 ErrorEVM = 2 47 ErrorConfig = 3 48 ErrorMissingBlockhash = 4 49 50 ErrorJson = 10 51 ErrorIO = 11 52 ErrorRlp = 12 53 54 stdinSelector = "stdin" 55 ) 56 57 type NumberedError struct { 58 errorCode int 59 err error 60 } 61 62 func NewError(errorCode int, err error) *NumberedError { 63 return &NumberedError{errorCode, err} 64 } 65 66 func (n *NumberedError) Error() string { 67 return fmt.Sprintf("ERROR(%d): %v", n.errorCode, n.err.Error()) 68 } 69 70 func (n *NumberedError) ExitCode() int { 71 return n.errorCode 72 } 73 74 // compile-time conformance test 75 var ( 76 _ cli.ExitCoder = (*NumberedError)(nil) 77 ) 78 79 type input struct { 80 Alloc core.GenesisAlloc `json:"alloc,omitempty"` 81 Env *stEnv `json:"env,omitempty"` 82 Txs []*txWithKey `json:"txs,omitempty"` 83 TxRlp string `json:"txsRlp,omitempty"` 84 } 85 86 func Transition(ctx *cli.Context) error { 87 // Configure the go-ethereum logger 88 glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) 89 glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) 90 log.Root().SetHandler(glogger) 91 92 var ( 93 err error 94 tracer vm.EVMLogger 95 ) 96 var getTracer func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) 97 98 baseDir, err := createBasedir(ctx) 99 if err != nil { 100 return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) 101 } 102 if ctx.Bool(TraceFlag.Name) { 103 if ctx.IsSet(TraceDisableMemoryFlag.Name) && ctx.IsSet(TraceEnableMemoryFlag.Name) { 104 return NewError(ErrorConfig, fmt.Errorf("can't use both flags --%s and --%s", TraceDisableMemoryFlag.Name, TraceEnableMemoryFlag.Name)) 105 } 106 if ctx.IsSet(TraceDisableReturnDataFlag.Name) && ctx.IsSet(TraceEnableReturnDataFlag.Name) { 107 return NewError(ErrorConfig, fmt.Errorf("can't use both flags --%s and --%s", TraceDisableReturnDataFlag.Name, TraceEnableReturnDataFlag.Name)) 108 } 109 if ctx.IsSet(TraceDisableMemoryFlag.Name) { 110 log.Warn(fmt.Sprintf("--%s has been deprecated in favour of --%s", TraceDisableMemoryFlag.Name, TraceEnableMemoryFlag.Name)) 111 } 112 if ctx.IsSet(TraceDisableReturnDataFlag.Name) { 113 log.Warn(fmt.Sprintf("--%s has been deprecated in favour of --%s", TraceDisableReturnDataFlag.Name, TraceEnableReturnDataFlag.Name)) 114 } 115 // Configure the EVM logger 116 logConfig := &logger.Config{ 117 DisableStack: ctx.Bool(TraceDisableStackFlag.Name), 118 EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name) || ctx.Bool(TraceEnableMemoryFlag.Name), 119 EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name) || ctx.Bool(TraceEnableReturnDataFlag.Name), 120 Debug: true, 121 } 122 var prevFile *os.File 123 // This one closes the last file 124 defer func() { 125 if prevFile != nil { 126 prevFile.Close() 127 } 128 }() 129 getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { 130 if prevFile != nil { 131 prevFile.Close() 132 } 133 traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) 134 if err != nil { 135 return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) 136 } 137 prevFile = traceFile 138 return logger.NewJSONLogger(logConfig, traceFile), nil 139 } 140 } else { 141 getTracer = func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error) { 142 return nil, nil 143 } 144 } 145 // We need to load three things: alloc, env and transactions. May be either in 146 // stdin input or in files. 147 // Check if anything needs to be read from stdin 148 var ( 149 prestate Prestate 150 txs types.Transactions // txs to apply 151 allocStr = ctx.String(InputAllocFlag.Name) 152 153 envStr = ctx.String(InputEnvFlag.Name) 154 txStr = ctx.String(InputTxsFlag.Name) 155 inputData = &input{} 156 ) 157 // Figure out the prestate alloc 158 if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector { 159 decoder := json.NewDecoder(os.Stdin) 160 if err := decoder.Decode(inputData); err != nil { 161 return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err)) 162 } 163 } 164 if allocStr != stdinSelector { 165 if err := readFile(allocStr, "alloc", &inputData.Alloc); err != nil { 166 return err 167 } 168 } 169 prestate.Pre = inputData.Alloc 170 171 // Set the block environment 172 if envStr != stdinSelector { 173 var env stEnv 174 if err := readFile(envStr, "env", &env); err != nil { 175 return err 176 } 177 inputData.Env = &env 178 } 179 prestate.Env = *inputData.Env 180 181 vmConfig := vm.Config{ 182 Tracer: tracer, 183 } 184 // Construct the chainconfig 185 var chainConfig *params.ChainConfig 186 if cConf, extraEips, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil { 187 return NewError(ErrorConfig, fmt.Errorf("failed constructing chain configuration: %v", err)) 188 } else { 189 chainConfig = cConf 190 vmConfig.ExtraEips = extraEips 191 } 192 // Set the chain id 193 chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) 194 195 if txs, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil { 196 return err 197 } 198 if err := applyLondonChecks(&prestate.Env, chainConfig); err != nil { 199 return err 200 } 201 if err := applyShanghaiChecks(&prestate.Env, chainConfig); err != nil { 202 return err 203 } 204 if err := applyMergeChecks(&prestate.Env, chainConfig); err != nil { 205 return err 206 } 207 if err := applyCancunChecks(&prestate.Env, chainConfig); err != nil { 208 return err 209 } 210 // Run the test and aggregate the result 211 s, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer) 212 if err != nil { 213 return err 214 } 215 body, _ := rlp.EncodeToBytes(txs) 216 // Dump the excution result 217 collector := make(Alloc) 218 s.DumpToCollector(collector, nil) 219 return dispatchOutput(ctx, baseDir, result, collector, body) 220 } 221 222 // txWithKey is a helper-struct, to allow us to use the types.Transaction along with 223 // a `secretKey`-field, for input 224 type txWithKey struct { 225 key *dilithium.Dilithium 226 tx *types.Transaction 227 protected bool 228 } 229 230 func (t *txWithKey) UnmarshalJSON(input []byte) error { 231 // Read the metadata, if present 232 type txMetadata struct { 233 Key *common.Hash `json:"secretKey"` 234 Protected *bool `json:"protected"` 235 } 236 var data txMetadata 237 if err := json.Unmarshal(input, &data); err != nil { 238 return err 239 } 240 if data.Key != nil { 241 k := data.Key.Hex()[2:] 242 if dilithiumKey, err := pqcrypto.HexToDilithium(k); err != nil { 243 return err 244 } else { 245 t.key = dilithiumKey 246 } 247 } 248 if data.Protected != nil { 249 t.protected = *data.Protected 250 } else { 251 t.protected = true 252 } 253 // Now, read the transaction itself 254 var tx types.Transaction 255 if err := json.Unmarshal(input, &tx); err != nil { 256 return err 257 } 258 t.tx = &tx 259 return nil 260 } 261 262 // signUnsignedTransactions converts the input txs to canonical transactions. 263 // 264 // The transactions can have two forms, either 265 // 1. unsigned or 266 // 2. signed 267 // 268 // For (1), r, s, v, need so be zero, and the `secretKey` needs to be set. 269 // If so, we sign it here and now, with the given `secretKey` 270 // If the condition above is not met, then it's considered a signed transaction. 271 // 272 // To manage this, we read the transactions twice, first trying to read the secretKeys, 273 // and secondly to read them with the standard tx json format 274 func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Transactions, error) { 275 var signedTxs []*types.Transaction 276 for i, tx := range txs { 277 var ( 278 signature = tx.tx.RawSignatureValues() 279 signed *types.Transaction 280 err error 281 ) 282 if tx.key == nil || signature != nil { 283 // Already signed 284 signedTxs = append(signedTxs, tx.tx) 285 continue 286 } 287 // This transaction needs to be signed 288 if tx.protected { 289 signed, err = types.SignTx(tx.tx, signer, tx.key) 290 } else { 291 signed, err = types.SignTx(tx.tx, types.FrontierSigner{}, tx.key) 292 } 293 if err != nil { 294 return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err)) 295 } 296 signedTxs = append(signedTxs, signed) 297 } 298 return signedTxs, nil 299 } 300 301 func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *params.ChainConfig) (types.Transactions, error) { 302 var txsWithKeys []*txWithKey 303 var signed types.Transactions 304 if txStr != stdinSelector { 305 data, err := os.ReadFile(txStr) 306 if err != nil { 307 return nil, NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) 308 } 309 if strings.HasSuffix(txStr, ".rlp") { // A file containing an rlp list 310 var body hexutil.Bytes 311 if err := json.Unmarshal(data, &body); err != nil { 312 return nil, err 313 } 314 // Already signed transactions 315 if err := rlp.DecodeBytes(body, &signed); err != nil { 316 return nil, err 317 } 318 return signed, nil 319 } 320 if err := json.Unmarshal(data, &txsWithKeys); err != nil { 321 return nil, NewError(ErrorJson, fmt.Errorf("failed unmarshaling txs-file: %v", err)) 322 } 323 } else { 324 if len(inputData.TxRlp) > 0 { 325 // Decode the body of already signed transactions 326 body := common.FromHex(inputData.TxRlp) 327 // Already signed transactions 328 if err := rlp.DecodeBytes(body, &signed); err != nil { 329 return nil, err 330 } 331 return signed, nil 332 } 333 // JSON encoded transactions 334 txsWithKeys = inputData.Txs 335 } 336 // We may have to sign the transactions. 337 signer := types.MakeSigner(chainConfig, big.NewInt(int64(env.Number)), env.Timestamp) 338 return signUnsignedTransactions(txsWithKeys, signer) 339 } 340 341 func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error { 342 if !chainConfig.IsLondon(big.NewInt(int64(env.Number))) { 343 return nil 344 } 345 // Sanity check, to not `panic` in state_transition 346 if env.BaseFee != nil { 347 // Already set, base fee has precedent over parent base fee. 348 return nil 349 } 350 if env.ParentBaseFee == nil || env.Number == 0 { 351 return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section")) 352 } 353 env.BaseFee = eip1559.CalcBaseFee(chainConfig, &types.Header{ 354 Number: new(big.Int).SetUint64(env.Number - 1), 355 BaseFee: env.ParentBaseFee, 356 GasUsed: env.ParentGasUsed, 357 GasLimit: env.ParentGasLimit, 358 }) 359 return nil 360 } 361 362 func applyShanghaiChecks(env *stEnv, chainConfig *params.ChainConfig) error { 363 if !chainConfig.IsShanghai(big.NewInt(int64(env.Number)), env.Timestamp) { 364 return nil 365 } 366 if env.Withdrawals == nil { 367 return NewError(ErrorConfig, errors.New("Shanghai config but missing 'withdrawals' in env section")) 368 } 369 return nil 370 } 371 372 func applyMergeChecks(env *stEnv, chainConfig *params.ChainConfig) error { 373 isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0 374 if !isMerged { 375 // pre-merge: If difficulty was not provided by caller, we need to calculate it. 376 if env.Difficulty != nil { 377 // already set 378 return nil 379 } 380 switch { 381 case env.ParentDifficulty == nil: 382 return NewError(ErrorConfig, errors.New("currentDifficulty was not provided, and cannot be calculated due to missing parentDifficulty")) 383 case env.Number == 0: 384 return NewError(ErrorConfig, errors.New("currentDifficulty needs to be provided for block number 0")) 385 case env.Timestamp <= env.ParentTimestamp: 386 return NewError(ErrorConfig, fmt.Errorf("currentDifficulty cannot be calculated -- currentTime (%d) needs to be after parent time (%d)", 387 env.Timestamp, env.ParentTimestamp)) 388 } 389 env.Difficulty = calcDifficulty(chainConfig, env.Number, env.Timestamp, 390 env.ParentTimestamp, env.ParentDifficulty, env.ParentUncleHash) 391 return nil 392 } 393 // post-merge: 394 // - random must be supplied 395 // - difficulty must be zero 396 switch { 397 case env.Random == nil: 398 return NewError(ErrorConfig, errors.New("post-merge requires currentRandom to be defined in env")) 399 case env.Difficulty != nil && env.Difficulty.BitLen() != 0: 400 return NewError(ErrorConfig, errors.New("post-merge difficulty must be zero (or omitted) in env")) 401 } 402 env.Difficulty = nil 403 return nil 404 } 405 406 func applyCancunChecks(env *stEnv, chainConfig *params.ChainConfig) error { 407 if !chainConfig.IsCancun(big.NewInt(int64(env.Number)), env.Timestamp) { 408 env.ParentBeaconBlockRoot = nil // un-set it if it has been set too early 409 return nil 410 } 411 // Post-cancun 412 // We require EIP-4788 beacon root to be set in the env 413 if env.ParentBeaconBlockRoot == nil { 414 return NewError(ErrorConfig, errors.New("post-cancun env requires parentBeaconBlockRoot to be set")) 415 } 416 return nil 417 } 418 419 type Alloc map[common.Address]core.GenesisAccount 420 421 func (g Alloc) OnRoot(common.Hash) {} 422 423 func (g Alloc) OnAccount(addr *common.Address, dumpAccount state.DumpAccount) { 424 if addr == nil { 425 return 426 } 427 balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10) 428 var storage map[common.Hash]common.Hash 429 if dumpAccount.Storage != nil { 430 storage = make(map[common.Hash]common.Hash) 431 for k, v := range dumpAccount.Storage { 432 storage[k] = common.HexToHash(v) 433 } 434 } 435 genesisAccount := core.GenesisAccount{ 436 Code: dumpAccount.Code, 437 Storage: storage, 438 Balance: balance, 439 Nonce: dumpAccount.Nonce, 440 } 441 g[*addr] = genesisAccount 442 } 443 444 // saveFile marshals the object to the given file 445 func saveFile(baseDir, filename string, data interface{}) error { 446 b, err := json.MarshalIndent(data, "", " ") 447 if err != nil { 448 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 449 } 450 location := path.Join(baseDir, filename) 451 if err = os.WriteFile(location, b, 0644); err != nil { 452 return NewError(ErrorIO, fmt.Errorf("failed writing output: %v", err)) 453 } 454 log.Info("Wrote file", "file", location) 455 return nil 456 } 457 458 // dispatchOutput writes the output data to either stderr or stdout, or to the specified 459 // files 460 func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes) error { 461 stdOutObject := make(map[string]interface{}) 462 stdErrObject := make(map[string]interface{}) 463 dispatch := func(baseDir, fName, name string, obj interface{}) error { 464 switch fName { 465 case "stdout": 466 stdOutObject[name] = obj 467 case "stderr": 468 stdErrObject[name] = obj 469 case "": 470 // don't save 471 default: // save to file 472 if err := saveFile(baseDir, fName, obj); err != nil { 473 return err 474 } 475 } 476 return nil 477 } 478 if err := dispatch(baseDir, ctx.String(OutputAllocFlag.Name), "alloc", alloc); err != nil { 479 return err 480 } 481 if err := dispatch(baseDir, ctx.String(OutputResultFlag.Name), "result", result); err != nil { 482 return err 483 } 484 if err := dispatch(baseDir, ctx.String(OutputBodyFlag.Name), "body", body); err != nil { 485 return err 486 } 487 if len(stdOutObject) > 0 { 488 b, err := json.MarshalIndent(stdOutObject, "", " ") 489 if err != nil { 490 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 491 } 492 os.Stdout.Write(b) 493 os.Stdout.WriteString("\n") 494 } 495 if len(stdErrObject) > 0 { 496 b, err := json.MarshalIndent(stdErrObject, "", " ") 497 if err != nil { 498 return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) 499 } 500 os.Stderr.Write(b) 501 os.Stderr.WriteString("\n") 502 } 503 return nil 504 }