func (l *StructLogger) Error() error {
	return l.err
}
Error returns the VM error captured by the trace
package vm
import (
	"encoding/hex"
	"fmt"
	"io"
	"math/big"
	"time"
	"github.com/Dipper-Labs/Dipper-Protocol/app/v0/vm/common/math"
	"github.com/Dipper-Labs/Dipper-Protocol/app/v0/vm/types"
	sdk "github.com/Dipper-Labs/Dipper-Protocol/types"
)
type Storage map[sdk.Hash]sdk.Hash
func (s Storage) Copy() Storage {
	cpy := make(Storage)
	for key, value := range s {
		cpy[key] = value
	}
	return cpy
}
type LogConfig struct {
	DisableMemory  bool  
	DisableStack   bool  
	DisableStorage bool  
	Debug          bool  
	Limit          int   
}
type StructLog struct {
	Pc            uint64                `json:"pc"`
	Op            OpCode                `json:"op"`
	Gas           uint64                `json:"gas"`
	GasCost       uint64                `json:"gasCost"`
	Memory        []byte                `json:"memory"`
	MemorySize    int                   `json:"memSize"`
	Stack         []*big.Int            `json:"stack"`
	Storage       map[sdk.Hash]sdk.Hash `json:"-"`
	Depth         uint64                `json:"depth"`
	RefundCounter uint64                `json:"refund"`
	Err           error                 `json:"-"`
}
func (s *StructLog) OpName() string {
	return s.Op.String()
}
func (s *StructLog) ErrorString() string {
	if s.Err != nil {
		return s.Err.Error()
	}
	return ""
}
type Tracer interface {
	CaptureStart(from sdk.AccAddress, to sdk.AccAddress, call bool, input []byte, gas uint64, value *big.Int) error
	CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth uint64, err error) error
	CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth uint64, err error) error
	CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
}
type StructLogger struct {
	cfg LogConfig
	logs          []StructLog
	changedValues map[string]Storage
	output        []byte
	err           error
}
func NewStructLogger(cfg *LogConfig) *StructLogger {
	logger := &StructLogger{
		changedValues: make(map[string]Storage),
	}
	if cfg != nil {
		logger.cfg = *cfg
	}
	return logger
}
func (l *StructLogger) CaptureStart(from sdk.AccAddress, to sdk.AccAddress, create bool, input []byte, gas uint64, value *big.Int) error {
	return nil
}
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth uint64, err error) error {
	if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
		return ErrTraceLimitReached
	}
	fmt.Println(contract.Address().String())
	if l.changedValues[contract.Address().String()] == nil {
		l.changedValues[contract.Address().String()] = make(Storage)
	}
	if op == SSTORE && stack.len() >= 2 {
		var (
			value   = sdk.BigToHash(stack.data[stack.len()-2])
			address = sdk.BigToHash(stack.data[stack.len()-1])
		)
		l.changedValues[contract.Address().String()][address] = value
	}
	var mem []byte
	if !l.cfg.DisableMemory {
		mem = make([]byte, len(memory.Data()))
		copy(mem, memory.Data())
	}
	var stck []*big.Int
	if !l.cfg.DisableStack {
		stck = make([]*big.Int, len(stack.Data()))
		for i, item := range stack.Data() {
			stck[i] = new(big.Int).Set(item)
		}
	}
	var storage Storage
	if !l.cfg.DisableStorage {
		storage = l.changedValues[contract.Address().String()].Copy()
	}
	log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, env.StateDB.GetRefund(), err}
	l.logs = append(l.logs, log)
	return nil
}
func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth uint64, err error) error {
	return nil
}
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
	l.output = output
	l.err = err
	if l.cfg.Debug {
		fmt.Printf("0x%x\n", output)
		if err != nil {
			fmt.Printf("error: %v\n", err)
		}
	}
	return nil
}
func (l *StructLogger) StructLogs() []StructLog {
	return l.logs
}