core/vm, internal/ethapi: tracer no full storage, nicer json output (#15499)
* core/vm, internal/ethapi: tracer no full storage, nicer json output * core/vm, internal/ethapi: omit disabled trace fields
This commit is contained in:
		| @@ -45,7 +45,6 @@ type LogConfig struct { | ||||
| 	DisableMemory  bool // disable memory capture | ||||
| 	DisableStack   bool // disable stack capture | ||||
| 	DisableStorage bool // disable storage capture | ||||
| 	FullStorage    bool // show full storage (slow) | ||||
| 	Limit          int  // maximum length of output, but zero means unlimited | ||||
| } | ||||
|  | ||||
| @@ -136,14 +135,13 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui | ||||
| 		) | ||||
| 		l.changedValues[contract.Address()][address] = value | ||||
| 	} | ||||
| 	// copy a snapstot of the current memory state to a new buffer | ||||
| 	// Copy a snapstot of the current memory state to a new buffer | ||||
| 	var mem []byte | ||||
| 	if !l.cfg.DisableMemory { | ||||
| 		mem = make([]byte, len(memory.Data())) | ||||
| 		copy(mem, memory.Data()) | ||||
| 	} | ||||
|  | ||||
| 	// copy a snapshot of the current stack state to a new buffer | ||||
| 	// Copy a snapshot of the current stack state to a new buffer | ||||
| 	var stck []*big.Int | ||||
| 	if !l.cfg.DisableStack { | ||||
| 		stck = make([]*big.Int, len(stack.Data())) | ||||
| @@ -151,26 +149,10 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui | ||||
| 			stck[i] = new(big.Int).Set(item) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Copy the storage based on the settings specified in the log config. If full storage | ||||
| 	// is disabled (default) we can use the simple Storage.Copy method, otherwise we use | ||||
| 	// the state object to query for all values (slow process). | ||||
| 	// Copy a snapshot of the current storage to a new container | ||||
| 	var storage Storage | ||||
| 	if !l.cfg.DisableStorage { | ||||
| 		if l.cfg.FullStorage { | ||||
| 			storage = make(Storage) | ||||
| 			// Get the contract account and loop over each storage entry. This may involve looping over | ||||
| 			// the trie and is a very expensive process. | ||||
|  | ||||
| 			env.StateDB.ForEachStorage(contract.Address(), func(key, value common.Hash) bool { | ||||
| 				storage[key] = value | ||||
| 				// Return true, indicating we'd like to continue. | ||||
| 				return true | ||||
| 			}) | ||||
| 		} else { | ||||
| 			// copy a snapshot of the current storage to a new container. | ||||
| 			storage = l.changedValues[contract.Address()].Copy() | ||||
| 		} | ||||
| 		storage = l.changedValues[contract.Address()].Copy() | ||||
| 	} | ||||
| 	// create a new snaptshot of the EVM. | ||||
| 	log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, err} | ||||
|   | ||||
| @@ -63,32 +63,8 @@ func TestStoreCapture(t *testing.T) { | ||||
| 	if len(logger.changedValues[contract.Address()]) == 0 { | ||||
| 		t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.changedValues[contract.Address()])) | ||||
| 	} | ||||
|  | ||||
| 	exp := common.BigToHash(big.NewInt(1)) | ||||
| 	if logger.changedValues[contract.Address()][index] != exp { | ||||
| 		t.Errorf("expected %x, got %x", exp, logger.changedValues[contract.Address()][index]) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestStorageCapture(t *testing.T) { | ||||
| 	t.Skip("implementing this function is difficult. it requires all sort of interfaces to be implemented which isn't trivial. The value (the actual test) isn't worth it") | ||||
| 	var ( | ||||
| 		ref      = &dummyContractRef{} | ||||
| 		contract = NewContract(ref, ref, new(big.Int), 0) | ||||
| 		env      = NewEVM(Context{}, dummyStateDB{ref: ref}, params.TestChainConfig, Config{EnableJit: false, ForceJit: false}) | ||||
| 		logger   = NewStructLogger(nil) | ||||
| 		mem      = NewMemory() | ||||
| 		stack    = newstack() | ||||
| 	) | ||||
|  | ||||
| 	logger.CaptureState(env, 0, STOP, 0, 0, mem, stack, contract, 0, nil) | ||||
| 	if ref.calledForEach { | ||||
| 		t.Error("didn't expect for each to be called") | ||||
| 	} | ||||
|  | ||||
| 	logger = NewStructLogger(&LogConfig{FullStorage: true}) | ||||
| 	logger.CaptureState(env, 0, STOP, 0, 0, mem, stack, contract, 0, nil) | ||||
| 	if !ref.calledForEach { | ||||
| 		t.Error("expected for each to be called") | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -710,45 +710,52 @@ type ExecutionResult struct { | ||||
| // StructLogRes stores a structured log emitted by the EVM while replaying a | ||||
| // transaction in debug mode | ||||
| type StructLogRes struct { | ||||
| 	Pc      uint64            `json:"pc"` | ||||
| 	Op      string            `json:"op"` | ||||
| 	Gas     uint64            `json:"gas"` | ||||
| 	GasCost uint64            `json:"gasCost"` | ||||
| 	Depth   int               `json:"depth"` | ||||
| 	Error   error             `json:"error"` | ||||
| 	Stack   []string          `json:"stack"` | ||||
| 	Memory  []string          `json:"memory"` | ||||
| 	Storage map[string]string `json:"storage"` | ||||
| 	Pc      uint64             `json:"pc"` | ||||
| 	Op      string             `json:"op"` | ||||
| 	Gas     uint64             `json:"gas"` | ||||
| 	GasCost uint64             `json:"gasCost"` | ||||
| 	Depth   int                `json:"depth"` | ||||
| 	Error   error              `json:"error,omitempty"` | ||||
| 	Stack   *[]string          `json:"stack,omitempty"` | ||||
| 	Memory  *[]string          `json:"memory,omitempty"` | ||||
| 	Storage *map[string]string `json:"storage,omitempty"` | ||||
| } | ||||
|  | ||||
| // formatLogs formats EVM returned structured logs for json output | ||||
| func FormatLogs(structLogs []vm.StructLog) []StructLogRes { | ||||
| 	formattedStructLogs := make([]StructLogRes, len(structLogs)) | ||||
| 	for index, trace := range structLogs { | ||||
| 		formattedStructLogs[index] = StructLogRes{ | ||||
| func FormatLogs(logs []vm.StructLog) []StructLogRes { | ||||
| 	formatted := make([]StructLogRes, len(logs)) | ||||
| 	for index, trace := range logs { | ||||
| 		formatted[index] = StructLogRes{ | ||||
| 			Pc:      trace.Pc, | ||||
| 			Op:      trace.Op.String(), | ||||
| 			Gas:     trace.Gas, | ||||
| 			GasCost: trace.GasCost, | ||||
| 			Depth:   trace.Depth, | ||||
| 			Error:   trace.Err, | ||||
| 			Stack:   make([]string, len(trace.Stack)), | ||||
| 			Storage: make(map[string]string), | ||||
| 		} | ||||
|  | ||||
| 		for i, stackValue := range trace.Stack { | ||||
| 			formattedStructLogs[index].Stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) | ||||
| 		if trace.Stack != nil { | ||||
| 			stack := make([]string, len(trace.Stack)) | ||||
| 			for i, stackValue := range trace.Stack { | ||||
| 				stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) | ||||
| 			} | ||||
| 			formatted[index].Stack = &stack | ||||
| 		} | ||||
|  | ||||
| 		for i := 0; i+32 <= len(trace.Memory); i += 32 { | ||||
| 			formattedStructLogs[index].Memory = append(formattedStructLogs[index].Memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) | ||||
| 		if trace.Memory != nil { | ||||
| 			memory := make([]string, 0, (len(trace.Memory)+31)/32) | ||||
| 			for i := 0; i+32 <= len(trace.Memory); i += 32 { | ||||
| 				memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) | ||||
| 			} | ||||
| 			formatted[index].Memory = &memory | ||||
| 		} | ||||
|  | ||||
| 		for i, storageValue := range trace.Storage { | ||||
| 			formattedStructLogs[index].Storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) | ||||
| 		if trace.Storage != nil { | ||||
| 			storage := make(map[string]string) | ||||
| 			for i, storageValue := range trace.Storage { | ||||
| 				storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) | ||||
| 			} | ||||
| 			formatted[index].Storage = &storage | ||||
| 		} | ||||
| 	} | ||||
| 	return formattedStructLogs | ||||
| 	return formatted | ||||
| } | ||||
|  | ||||
| // rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are | ||||
|   | ||||
		Reference in New Issue
	
	Block a user