| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | // Copyright 2020 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of go-ethereum. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // go-ethereum is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package t8ntool | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	"crypto/ecdsa" | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							|  |  |  | 	"math/big" | 
					
						
							|  |  |  | 	"os" | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common/hexutil" | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/core" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/state" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/types" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/core/vm" | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/params" | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/tests" | 
					
						
							|  |  |  | 	"gopkg.in/urfave/cli.v1" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	ErrorEVM              = 2 | 
					
						
							|  |  |  | 	ErrorVMConfig         = 3 | 
					
						
							|  |  |  | 	ErrorMissingBlockhash = 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ErrorJson = 10 | 
					
						
							|  |  |  | 	ErrorIO   = 11 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	stdinSelector = "stdin" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type NumberedError struct { | 
					
						
							|  |  |  | 	errorCode int | 
					
						
							|  |  |  | 	err       error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewError(errorCode int, err error) *NumberedError { | 
					
						
							|  |  |  | 	return &NumberedError{errorCode, err} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (n *NumberedError) Error() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("ERROR(%d): %v", n.errorCode, n.err.Error()) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (n *NumberedError) Code() int { | 
					
						
							|  |  |  | 	return n.errorCode | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type input struct { | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	Alloc core.GenesisAlloc `json:"alloc,omitempty"` | 
					
						
							|  |  |  | 	Env   *stEnv            `json:"env,omitempty"` | 
					
						
							|  |  |  | 	Txs   []*txWithKey      `json:"txs,omitempty"` | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func Main(ctx *cli.Context) error { | 
					
						
							|  |  |  | 	// Configure the go-ethereum logger | 
					
						
							|  |  |  | 	glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) | 
					
						
							|  |  |  | 	glogger.Verbosity(log.Lvl(ctx.Int(VerbosityFlag.Name))) | 
					
						
							|  |  |  | 	log.Root().SetHandler(glogger) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 		err     error | 
					
						
							|  |  |  | 		tracer  vm.Tracer | 
					
						
							|  |  |  | 		baseDir = "" | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	) | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 	var getTracer func(txIndex int, txHash common.Hash) (vm.Tracer, error) | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 	// If user specified a basedir, make sure it exists | 
					
						
							|  |  |  | 	if ctx.IsSet(OutputBasedir.Name) { | 
					
						
							|  |  |  | 		if base := ctx.String(OutputBasedir.Name); len(base) > 0 { | 
					
						
							|  |  |  | 			err := os.MkdirAll(base, 0755) // //rw-r--r-- | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			baseDir = base | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	if ctx.Bool(TraceFlag.Name) { | 
					
						
							|  |  |  | 		// Configure the EVM logger | 
					
						
							|  |  |  | 		logConfig := &vm.LogConfig{ | 
					
						
							| 
									
										
										
										
											2020-07-16 14:06:19 +02:00
										 |  |  | 			DisableStack:      ctx.Bool(TraceDisableStackFlag.Name), | 
					
						
							|  |  |  | 			DisableMemory:     ctx.Bool(TraceDisableMemoryFlag.Name), | 
					
						
							|  |  |  | 			DisableReturnData: ctx.Bool(TraceDisableReturnDataFlag.Name), | 
					
						
							|  |  |  | 			Debug:             true, | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		var prevFile *os.File | 
					
						
							|  |  |  | 		// This one closes the last file | 
					
						
							|  |  |  | 		defer func() { | 
					
						
							|  |  |  | 			if prevFile != nil { | 
					
						
							|  |  |  | 				prevFile.Close() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}() | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 		getTracer = func(txIndex int, txHash common.Hash) (vm.Tracer, error) { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 			if prevFile != nil { | 
					
						
							|  |  |  | 				prevFile.Close() | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 			traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			prevFile = traceFile | 
					
						
							|  |  |  | 			return vm.NewJSONLogger(logConfig, traceFile), nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 		getTracer = func(txIndex int, txHash common.Hash) (tracer vm.Tracer, err error) { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 			return nil, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// We need to load three things: alloc, env and transactions. May be either in | 
					
						
							|  |  |  | 	// stdin input or in files. | 
					
						
							|  |  |  | 	// Check if anything needs to be read from stdin | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		prestate Prestate | 
					
						
							|  |  |  | 		txs      types.Transactions // txs to apply | 
					
						
							|  |  |  | 		allocStr = ctx.String(InputAllocFlag.Name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		envStr    = ctx.String(InputEnvFlag.Name) | 
					
						
							|  |  |  | 		txStr     = ctx.String(InputTxsFlag.Name) | 
					
						
							|  |  |  | 		inputData = &input{} | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	// Figure out the prestate alloc | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	if allocStr == stdinSelector || envStr == stdinSelector || txStr == stdinSelector { | 
					
						
							|  |  |  | 		decoder := json.NewDecoder(os.Stdin) | 
					
						
							|  |  |  | 		decoder.Decode(inputData) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if allocStr != stdinSelector { | 
					
						
							|  |  |  | 		inFile, err := os.Open(allocStr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorIO, fmt.Errorf("failed reading alloc file: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		defer inFile.Close() | 
					
						
							|  |  |  | 		decoder := json.NewDecoder(inFile) | 
					
						
							|  |  |  | 		if err := decoder.Decode(&inputData.Alloc); err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling alloc-file: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	prestate.Pre = inputData.Alloc | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	// Set the block environment | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	if envStr != stdinSelector { | 
					
						
							|  |  |  | 		inFile, err := os.Open(envStr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorIO, fmt.Errorf("failed reading env file: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		defer inFile.Close() | 
					
						
							|  |  |  | 		decoder := json.NewDecoder(inFile) | 
					
						
							|  |  |  | 		var env stEnv | 
					
						
							|  |  |  | 		if err := decoder.Decode(&env); err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling env-file: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		inputData.Env = &env | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	prestate.Env = *inputData.Env | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	vmConfig := vm.Config{ | 
					
						
							|  |  |  | 		Tracer: tracer, | 
					
						
							|  |  |  | 		Debug:  (tracer != nil), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Construct the chainconfig | 
					
						
							|  |  |  | 	var chainConfig *params.ChainConfig | 
					
						
							|  |  |  | 	if cConf, extraEips, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil { | 
					
						
							|  |  |  | 		return NewError(ErrorVMConfig, fmt.Errorf("Failed constructing chain configuration: %v", err)) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		chainConfig = cConf | 
					
						
							|  |  |  | 		vmConfig.ExtraEips = extraEips | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Set the chain id | 
					
						
							|  |  |  | 	chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	var txsWithKeys []*txWithKey | 
					
						
							|  |  |  | 	if txStr != stdinSelector { | 
					
						
							|  |  |  | 		inFile, err := os.Open(txStr) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		defer inFile.Close() | 
					
						
							|  |  |  | 		decoder := json.NewDecoder(inFile) | 
					
						
							|  |  |  | 		if err := decoder.Decode(&txsWithKeys); err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorJson, fmt.Errorf("Failed unmarshaling txs-file: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		txsWithKeys = inputData.Txs | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// We may have to sign the transactions. | 
					
						
							|  |  |  | 	signer := types.MakeSigner(chainConfig, big.NewInt(int64(prestate.Env.Number))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if txs, err = signUnsignedTransactions(txsWithKeys, signer); err != nil { | 
					
						
							|  |  |  | 		return NewError(ErrorJson, fmt.Errorf("Failed signing transactions: %v", err)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Iterate over all the tests, run them and aggregate the results | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	// Run the test and aggregate the result | 
					
						
							|  |  |  | 	state, result, err := prestate.Apply(vmConfig, chainConfig, txs, ctx.Int64(RewardFlag.Name), getTracer) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	body, _ := rlp.EncodeToBytes(txs) | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	// Dump the excution result | 
					
						
							|  |  |  | 	collector := make(Alloc) | 
					
						
							|  |  |  | 	state.DumpToCollector(collector, false, false, false, nil, -1) | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	return dispatchOutput(ctx, baseDir, result, collector, body) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | // txWithKey is a helper-struct, to allow us to use the types.Transaction along with | 
					
						
							|  |  |  | // a `secretKey`-field, for input | 
					
						
							|  |  |  | type txWithKey struct { | 
					
						
							|  |  |  | 	key *ecdsa.PrivateKey | 
					
						
							|  |  |  | 	tx  *types.Transaction | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t *txWithKey) UnmarshalJSON(input []byte) error { | 
					
						
							|  |  |  | 	// Read the secretKey, if present | 
					
						
							|  |  |  | 	type sKey struct { | 
					
						
							|  |  |  | 		Key *common.Hash `json:"secretKey"` | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var key sKey | 
					
						
							|  |  |  | 	if err := json.Unmarshal(input, &key); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if key.Key != nil { | 
					
						
							|  |  |  | 		k := key.Key.Hex()[2:] | 
					
						
							|  |  |  | 		if ecdsaKey, err := crypto.HexToECDSA(k); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			t.key = ecdsaKey | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Now, read the transaction itself | 
					
						
							|  |  |  | 	var tx types.Transaction | 
					
						
							|  |  |  | 	if err := json.Unmarshal(input, &tx); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	t.tx = &tx | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // signUnsignedTransactions converts the input txs to canonical transactions. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The transactions can have two forms, either | 
					
						
							|  |  |  | //   1. unsigned or | 
					
						
							|  |  |  | //   2. signed | 
					
						
							|  |  |  | // For (1), r, s, v, need so be zero, and the `secretKey` needs to be set. | 
					
						
							|  |  |  | // If so, we sign it here and now, with the given `secretKey` | 
					
						
							|  |  |  | // If the condition above is not met, then it's considered a signed transaction. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // To manage this, we read the transactions twice, first trying to read the secretKeys, | 
					
						
							|  |  |  | // and secondly to read them with the standard tx json format | 
					
						
							|  |  |  | func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Transactions, error) { | 
					
						
							|  |  |  | 	var signedTxs []*types.Transaction | 
					
						
							|  |  |  | 	for i, txWithKey := range txs { | 
					
						
							|  |  |  | 		tx := txWithKey.tx | 
					
						
							|  |  |  | 		key := txWithKey.key | 
					
						
							|  |  |  | 		v, r, s := tx.RawSignatureValues() | 
					
						
							|  |  |  | 		if key != nil && v.BitLen()+r.BitLen()+s.BitLen() == 0 { | 
					
						
							|  |  |  | 			// This transaction needs to be signed | 
					
						
							|  |  |  | 			signed, err := types.SignTx(tx, signer, key) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, NewError(ErrorJson, fmt.Errorf("Tx %d: failed to sign tx: %v", i, err)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			signedTxs = append(signedTxs, signed) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// Already signed | 
					
						
							|  |  |  | 			signedTxs = append(signedTxs, tx) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return signedTxs, nil | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type Alloc map[common.Address]core.GenesisAccount | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (g Alloc) OnRoot(common.Hash) {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) { | 
					
						
							|  |  |  | 	balance, _ := new(big.Int).SetString(dumpAccount.Balance, 10) | 
					
						
							|  |  |  | 	var storage map[common.Hash]common.Hash | 
					
						
							|  |  |  | 	if dumpAccount.Storage != nil { | 
					
						
							|  |  |  | 		storage = make(map[common.Hash]common.Hash) | 
					
						
							|  |  |  | 		for k, v := range dumpAccount.Storage { | 
					
						
							|  |  |  | 			storage[k] = common.HexToHash(v) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	genesisAccount := core.GenesisAccount{ | 
					
						
							|  |  |  | 		Code:    common.FromHex(dumpAccount.Code), | 
					
						
							|  |  |  | 		Storage: storage, | 
					
						
							|  |  |  | 		Balance: balance, | 
					
						
							|  |  |  | 		Nonce:   dumpAccount.Nonce, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	g[addr] = genesisAccount | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // saveFile marshalls the object to the given file | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | func saveFile(baseDir, filename string, data interface{}) error { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	b, err := json.MarshalIndent(data, "", " ") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	location := path.Join(baseDir, filename) | 
					
						
							|  |  |  | 	if err = ioutil.WriteFile(location, b, 0644); err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 		return NewError(ErrorIO, fmt.Errorf("failed writing output: %v", err)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	log.Info("Wrote file", "file", location) | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // dispatchOutput writes the output data to either stderr or stdout, or to the specified | 
					
						
							|  |  |  | // files | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc, body hexutil.Bytes) error { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	stdOutObject := make(map[string]interface{}) | 
					
						
							|  |  |  | 	stdErrObject := make(map[string]interface{}) | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 	dispatch := func(baseDir, fName, name string, obj interface{}) error { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 		switch fName { | 
					
						
							|  |  |  | 		case "stdout": | 
					
						
							|  |  |  | 			stdOutObject[name] = obj | 
					
						
							|  |  |  | 		case "stderr": | 
					
						
							|  |  |  | 			stdErrObject[name] = obj | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 		case "": | 
					
						
							|  |  |  | 			// don't save | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 		default: // save to file | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 			if err := saveFile(baseDir, fName, obj); err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 				return err | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 	if err := dispatch(baseDir, ctx.String(OutputAllocFlag.Name), "alloc", alloc); err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-08-19 11:31:13 +02:00
										 |  |  | 	if err := dispatch(baseDir, ctx.String(OutputResultFlag.Name), "result", result); err != nil { | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-02-25 07:26:57 -07:00
										 |  |  | 	if err := dispatch(baseDir, ctx.String(OutputBodyFlag.Name), "body", body); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-06-30 10:12:51 +02:00
										 |  |  | 	if len(stdOutObject) > 0 { | 
					
						
							|  |  |  | 		b, err := json.MarshalIndent(stdOutObject, "", " ") | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		os.Stdout.Write(b) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if len(stdErrObject) > 0 { | 
					
						
							|  |  |  | 		b, err := json.MarshalIndent(stdErrObject, "", " ") | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		os.Stderr.Write(b) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |