github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/evmcore/txtracer/tx_tracer.go (about)

     1  package txtracer
     2  
     3  import (
     4  	"encoding/json"
     5  	"math/big"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/holiman/uint256"
    10  
    11  	"github.com/unicornultrafoundation/go-u2u/common"
    12  	"github.com/unicornultrafoundation/go-u2u/common/hexutil"
    13  	"github.com/unicornultrafoundation/go-u2u/core/types"
    14  	"github.com/unicornultrafoundation/go-u2u/core/vm"
    15  	txtracer "github.com/unicornultrafoundation/go-u2u/gossip/txtracer"
    16  	"github.com/unicornultrafoundation/go-u2u/log"
    17  )
    18  
    19  // TraceStructLogger is a transaction trace creator
    20  type TraceStructLogger struct {
    21  	store       *txtracer.Store
    22  	from        *common.Address
    23  	to          *common.Address
    24  	newAddress  *common.Address
    25  	blockHash   common.Hash
    26  	tx          common.Hash
    27  	txIndex     uint
    28  	blockNumber big.Int
    29  	value       big.Int
    30  
    31  	gasUsed      uint64
    32  	rootTrace    *CallTrace
    33  	inputData    []byte
    34  	state        []depthState
    35  	traceAddress []uint32
    36  	stack        []*big.Int
    37  	reverted     bool
    38  	output       []byte
    39  	err          error
    40  }
    41  
    42  // NewTraceStructLogger creates new instance of trace creator
    43  func NewTraceStructLogger(store *txtracer.Store) *TraceStructLogger {
    44  	traceStructLogger := TraceStructLogger{
    45  		store: store,
    46  		stack: make([]*big.Int, 30),
    47  	}
    48  	return &traceStructLogger
    49  }
    50  
    51  // CaptureStart implements the tracer interface to initialize the tracing operation.
    52  func (tr *TraceStructLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
    53  	defer func() {
    54  		if r := recover(); r != nil {
    55  			log.Error("Tracer CaptureStart failed", r)
    56  		}
    57  	}()
    58  	// Create main trace holder
    59  	txTrace := CallTrace{
    60  		Actions: make([]ActionTrace, 0),
    61  	}
    62  
    63  	// Check if To is defined. If not, it is create address call
    64  	callType := CREATE
    65  	var newAddress *common.Address
    66  	if tr.to != nil {
    67  		callType = CALL
    68  	} else {
    69  		newAddress = &to
    70  	}
    71  
    72  	// Store input data
    73  	tr.inputData = input
    74  	if gas == 0 && tr.gasUsed != 0 {
    75  		gas = tr.gasUsed
    76  	}
    77  
    78  	// Make transaction trace root object
    79  	blockTrace := NewActionTrace(tr.blockHash, tr.blockNumber, tr.tx, uint64(tr.txIndex), callType)
    80  	var txAction *AddressAction
    81  	if CREATE == callType {
    82  		txAction = NewAddressAction(tr.from, gas, tr.inputData, nil, hexutil.Big(tr.value), nil)
    83  		if newAddress != nil {
    84  			blockTrace.Result.Address = newAddress
    85  			blockTrace.Result.Code = hexutil.Bytes(tr.output)
    86  		}
    87  	} else {
    88  		txAction = NewAddressAction(tr.from, gas, tr.inputData, tr.to, hexutil.Big(tr.value), &callType)
    89  		out := hexutil.Bytes(tr.output)
    90  		blockTrace.Result.Output = &out
    91  	}
    92  	blockTrace.Action = *txAction
    93  
    94  	// Add root object into Tracer
    95  	txTrace.AddTrace(blockTrace)
    96  	tr.rootTrace = &txTrace
    97  
    98  	// Init all needed variables
    99  	tr.state = []depthState{{0, create}}
   100  	tr.traceAddress = make([]uint32, 0)
   101  	tr.rootTrace.Stack = append(tr.rootTrace.Stack, &tr.rootTrace.Actions[len(tr.rootTrace.Actions)-1])
   102  }
   103  
   104  // stackPosFromEnd returns object from stack at givven position from end of stack
   105  func stackPosFromEnd(stackData []uint256.Int, pos int) *big.Int {
   106  	if len(stackData) <= pos || pos < 0 {
   107  		log.Warn("Tracer accessed out of bound stack", "size", len(stackData), "index", pos)
   108  		return new(big.Int)
   109  	}
   110  	return new(big.Int).Set(stackData[len(stackData)-1-pos].ToBig())
   111  }
   112  
   113  // CaptureState implements creating of traces based on getting opCodes from evm during contract processing
   114  func (tr *TraceStructLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
   115  	defer func() {
   116  		if r := recover(); r != nil {
   117  			log.Error("Tracer CaptureState failed", r)
   118  		}
   119  	}()
   120  	// When going back from inner call
   121  	for lastState(tr.state).level >= depth {
   122  		result := tr.rootTrace.Stack[len(tr.rootTrace.Stack)-1].Result
   123  		if lastState(tr.state).create && result != nil {
   124  			if len(scope.Stack.Data()) > 0 {
   125  				addr := common.BytesToAddress(stackPosFromEnd(scope.Stack.Data(), 0).Bytes())
   126  				result.Address = &addr
   127  				result.GasUsed = hexutil.Uint64(gas)
   128  			}
   129  		}
   130  		tr.traceAddress = removeTraceAddressLevel(tr.traceAddress, depth)
   131  		tr.state = tr.state[:len(tr.state)-1]
   132  		tr.rootTrace.Stack = tr.rootTrace.Stack[:len(tr.rootTrace.Stack)-1]
   133  		if lastState(tr.state).level == depth {
   134  			break
   135  		}
   136  	}
   137  
   138  	// Match processed instruction and create trace based on it
   139  	switch op {
   140  	case vm.CREATE, vm.CREATE2:
   141  		tr.traceAddress = addTraceAddress(tr.traceAddress, depth)
   142  		fromTrace := tr.rootTrace.Stack[len(tr.rootTrace.Stack)-1]
   143  
   144  		// Get input data from memory
   145  		offset := stackPosFromEnd(scope.Stack.Data(), 1).Uint64()
   146  		inputSize := stackPosFromEnd(scope.Stack.Data(), 2).Uint64()
   147  		var input []byte
   148  		if inputSize > 0 {
   149  			if offset <= offset+inputSize &&
   150  				offset+inputSize <= uint64(len(scope.Memory.Data())) {
   151  				input = make([]byte, inputSize)
   152  				copy(input, scope.Memory.Data()[offset:offset+inputSize])
   153  			}
   154  		}
   155  
   156  		// Create new trace
   157  		trace := NewActionTraceFromTrace(fromTrace, CREATE, tr.traceAddress)
   158  		from := scope.Contract.Address()
   159  		traceAction := NewAddressAction(&from, gas, input, nil, fromTrace.Action.Value, nil)
   160  		trace.Action = *traceAction
   161  		trace.Result.GasUsed = hexutil.Uint64(gas)
   162  		fromTrace.childTraces = append(fromTrace.childTraces, trace)
   163  		tr.rootTrace.Stack = append(tr.rootTrace.Stack, trace)
   164  		tr.state = append(tr.state, depthState{depth, true})
   165  
   166  	case vm.CALL, vm.CALLCODE, vm.DELEGATECALL, vm.STATICCALL:
   167  		var (
   168  			inOffset, inSize   uint64
   169  			retOffset, retSize uint64
   170  			input              []byte
   171  			value              = big.NewInt(0)
   172  		)
   173  
   174  		if vm.DELEGATECALL == op || vm.STATICCALL == op {
   175  			inOffset = stackPosFromEnd(scope.Stack.Data(), 2).Uint64()
   176  			inSize = stackPosFromEnd(scope.Stack.Data(), 3).Uint64()
   177  			retOffset = stackPosFromEnd(scope.Stack.Data(), 4).Uint64()
   178  			retSize = stackPosFromEnd(scope.Stack.Data(), 5).Uint64()
   179  		} else {
   180  			inOffset = stackPosFromEnd(scope.Stack.Data(), 3).Uint64()
   181  			inSize = stackPosFromEnd(scope.Stack.Data(), 4).Uint64()
   182  			retOffset = stackPosFromEnd(scope.Stack.Data(), 5).Uint64()
   183  			retSize = stackPosFromEnd(scope.Stack.Data(), 6).Uint64()
   184  			// only CALL and CALLCODE need `value` field
   185  			value = stackPosFromEnd(scope.Stack.Data(), 2)
   186  		}
   187  		if inSize > 0 {
   188  			if inOffset <= inOffset+inSize &&
   189  				inOffset+inSize <= uint64(len(scope.Memory.Data())) {
   190  				input = make([]byte, inSize)
   191  				copy(input, scope.Memory.Data()[inOffset:inOffset+inSize])
   192  			}
   193  		}
   194  		tr.traceAddress = addTraceAddress(tr.traceAddress, depth)
   195  		fromTrace := tr.rootTrace.Stack[len(tr.rootTrace.Stack)-1]
   196  		// create new trace
   197  		trace := NewActionTraceFromTrace(fromTrace, CALL, tr.traceAddress)
   198  		from := scope.Contract.Address()
   199  		addr := common.BytesToAddress(stackPosFromEnd(scope.Stack.Data(), 1).Bytes())
   200  		callType := strings.ToLower(op.String())
   201  		traceAction := NewAddressAction(&from, gas, input, &addr, hexutil.Big(*value), &callType)
   202  		trace.Action = *traceAction
   203  		fromTrace.childTraces = append(fromTrace.childTraces, trace)
   204  		trace.Result.RetOffset = retOffset
   205  		trace.Result.RetSize = retSize
   206  		tr.rootTrace.Stack = append(tr.rootTrace.Stack, trace)
   207  		tr.state = append(tr.state, depthState{depth, false})
   208  
   209  	case vm.RETURN, vm.STOP:
   210  		if tr != nil {
   211  			result := tr.rootTrace.Stack[len(tr.rootTrace.Stack)-1].Result
   212  			if result != nil {
   213  				var data []byte
   214  
   215  				if vm.STOP != op {
   216  					offset := stackPosFromEnd(scope.Stack.Data(), 0).Uint64()
   217  					size := stackPosFromEnd(scope.Stack.Data(), 1).Uint64()
   218  					if size > 0 {
   219  						if offset <= offset+size &&
   220  							offset+size <= uint64(len(scope.Memory.Data())) {
   221  							data = make([]byte, size)
   222  							copy(data, scope.Memory.Data()[offset:offset+size])
   223  						}
   224  					}
   225  				}
   226  
   227  				if lastState(tr.state).create {
   228  					result.Code = data
   229  				} else {
   230  					result.GasUsed = hexutil.Uint64(gas)
   231  					out := hexutil.Bytes(data)
   232  					result.Output = &out
   233  				}
   234  			}
   235  		}
   236  
   237  	case vm.REVERT:
   238  		tr.reverted = true
   239  		tr.rootTrace.Stack[len(tr.rootTrace.Stack)-1].Result = nil
   240  		tr.rootTrace.Stack[len(tr.rootTrace.Stack)-1].Error = "Reverted"
   241  
   242  	case vm.SELFDESTRUCT:
   243  		tr.traceAddress = addTraceAddress(tr.traceAddress, depth)
   244  		fromTrace := tr.rootTrace.Stack[len(tr.rootTrace.Stack)-1]
   245  		trace := NewActionTraceFromTrace(fromTrace, SELFDESTRUCT, tr.traceAddress)
   246  		action := fromTrace.Action
   247  
   248  		from := scope.Contract.Address()
   249  		traceAction := NewAddressAction(nil, 0, nil, nil, action.Value, nil)
   250  		traceAction.Address = &from
   251  		// set refund values
   252  		refundAddress := common.BytesToAddress(stackPosFromEnd(scope.Stack.Data(), 0).Bytes())
   253  		traceAction.RefundAddress = &refundAddress
   254  		// Add `balance` field for convenient usage
   255  		traceAction.Balance = &traceAction.Value
   256  		trace.Action = *traceAction
   257  		fromTrace.childTraces = append(fromTrace.childTraces, trace)
   258  	}
   259  }
   260  
   261  // CaptureEnd is called after the call finishes to finalize the tracing.
   262  func (tr *TraceStructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
   263  	defer func() {
   264  		if r := recover(); r != nil {
   265  			log.Error("Tracer CaptureEnd failed", r)
   266  		}
   267  	}()
   268  	log.Debug("TraceStructLogger capture END", "tx hash", tr.tx.String(), "duration", t, "gasUsed", gasUsed)
   269  	if gasUsed > 0 {
   270  		if tr.rootTrace.Actions[0].Result != nil {
   271  			tr.rootTrace.Actions[0].Result.GasUsed = hexutil.Uint64(gasUsed)
   272  		}
   273  		tr.rootTrace.lastTrace().Action.Gas = hexutil.Uint64(gasUsed)
   274  
   275  		tr.gasUsed = gasUsed
   276  	}
   277  	tr.output = output
   278  }
   279  
   280  func (*TraceStructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
   281  }
   282  
   283  // CaptureExit is called when returning from an inner call
   284  func (tr *TraceStructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {
   285  	defer func() {
   286  		if r := recover(); r != nil {
   287  			log.Error("Tracer CaptureExit failed", r)
   288  		}
   289  	}()
   290  	// When going back from inner call
   291  	result := tr.rootTrace.Stack[len(tr.rootTrace.Stack)-1].Result
   292  	if result != nil {
   293  		result.GasUsed = hexutil.Uint64(gasUsed)
   294  	}
   295  }
   296  
   297  // CaptureFault implements the Tracer interface to trace an execution fault
   298  // while running an opcode.
   299  func (tr *TraceStructLogger) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
   300  	return
   301  }
   302  
   303  // Reset function to be able to reuse logger
   304  func (tr *TraceStructLogger) reset() {
   305  	tr.to = nil
   306  	tr.from = nil
   307  	tr.inputData = nil
   308  	tr.rootTrace = nil
   309  	tr.reverted = false
   310  }
   311  
   312  // SetTx basic setter
   313  func (tr *TraceStructLogger) SetTx(tx common.Hash) {
   314  	tr.tx = tx
   315  }
   316  
   317  // SetFrom basic setter
   318  func (tr *TraceStructLogger) SetFrom(from common.Address) {
   319  	tr.from = &from
   320  }
   321  
   322  // SetTo basic setter
   323  func (tr *TraceStructLogger) SetTo(to *common.Address) {
   324  	tr.to = to
   325  }
   326  
   327  // SetValue basic setter
   328  func (tr *TraceStructLogger) SetValue(value big.Int) {
   329  	tr.value = value
   330  }
   331  
   332  // SetBlockHash basic setter
   333  func (tr *TraceStructLogger) SetBlockHash(blockHash common.Hash) {
   334  	tr.blockHash = blockHash
   335  }
   336  
   337  // SetBlockNumber basic setter
   338  func (tr *TraceStructLogger) SetBlockNumber(blockNumber *big.Int) {
   339  	tr.blockNumber = *blockNumber
   340  }
   341  
   342  // SetTxIndex basic setter
   343  func (tr *TraceStructLogger) SetTxIndex(txIndex uint) {
   344  	tr.txIndex = txIndex
   345  }
   346  
   347  // SetNewAddress basic setter
   348  func (tr *TraceStructLogger) SetNewAddress(newAddress common.Address) {
   349  	tr.newAddress = &newAddress
   350  }
   351  
   352  // SetGasUsed basic setter
   353  func (tr *TraceStructLogger) SetGasUsed(gasUsed uint64) {
   354  	tr.gasUsed = gasUsed
   355  }
   356  
   357  // ProcessTx finalizes trace proces and stores result into key-value persistant store
   358  func (tr *TraceStructLogger) ProcessTx() {
   359  	if tr.rootTrace != nil {
   360  		tr.rootTrace.lastTrace().Action.Gas = hexutil.Uint64(tr.gasUsed)
   361  		if tr.rootTrace.lastTrace().Result != nil {
   362  			tr.rootTrace.lastTrace().Result.GasUsed = hexutil.Uint64(tr.gasUsed)
   363  		}
   364  		tr.rootTrace.processLastTrace()
   365  	}
   366  }
   367  
   368  // GetTraceActions returns action traces after recording evm process
   369  func (tr *TraceStructLogger) SaveTrace() {
   370  	if tr.rootTrace == nil {
   371  		tr.rootTrace = &CallTrace{}
   372  		tr.rootTrace.AddTrace(GetErrorTrace(tr.blockHash, tr.blockNumber, tr.from, tr.to, tr.tx, tr.gasUsed, tr.err))
   373  
   374  	}
   375  
   376  	//if tr.store != nil && tr.rootTrace != nil {
   377  	if tr.store != nil {
   378  		// Convert trace objects to json byte array and save it
   379  		tracesBytes, _ := json.Marshal(tr.rootTrace.Actions)
   380  		tr.store.SetTxTrace(tr.tx, tracesBytes)
   381  		log.Debug("Added tx trace", "txHash", tr.tx.String())
   382  	}
   383  	tr.reset()
   384  }
   385  
   386  // GetTraceActions returns action traces after recording evm process
   387  func (tr *TraceStructLogger) GetTraceActions() *[]ActionTrace {
   388  	if tr.rootTrace != nil {
   389  		return &tr.rootTrace.Actions
   390  	}
   391  	empty := make([]ActionTrace, 0)
   392  	return &empty
   393  }
   394  
   395  // CallTrace is struct for holding tracing results
   396  type CallTrace struct {
   397  	Actions []ActionTrace  `json:"result"`
   398  	Stack   []*ActionTrace `json:"-"`
   399  }
   400  
   401  // AddTrace Append trace to call trace list
   402  func (callTrace *CallTrace) AddTrace(blockTrace *ActionTrace) {
   403  	if callTrace.Actions == nil {
   404  		callTrace.Actions = make([]ActionTrace, 0)
   405  	}
   406  	callTrace.Actions = append(callTrace.Actions, *blockTrace)
   407  }
   408  
   409  // AddTraces Append traces to call trace list
   410  func (callTrace *CallTrace) AddTraces(traces *[]ActionTrace, traceIndex *[]hexutil.Uint) {
   411  	for _, trace := range *traces {
   412  		if traceIndex == nil || equalContent(traceIndex, trace.TraceAddress) {
   413  			callTrace.AddTrace(&trace)
   414  		}
   415  	}
   416  }
   417  
   418  // equalContent tells whether index and traceIndex are the same
   419  func equalContent(index *[]hexutil.Uint, traceIndex []uint32) bool {
   420  	if len(*index) != len(traceIndex) {
   421  		return false
   422  	}
   423  	for i, v := range *index {
   424  		if uint32(v) != traceIndex[i] {
   425  			return false
   426  		}
   427  	}
   428  	return true
   429  }
   430  
   431  // lastTrace Get last trace in call trace list
   432  func (callTrace *CallTrace) lastTrace() *ActionTrace {
   433  	if len(callTrace.Actions) > 0 {
   434  		return &callTrace.Actions[len(callTrace.Actions)-1]
   435  	}
   436  	return nil
   437  }
   438  
   439  // NewActionTrace creates new instance of type ActionTrace
   440  func NewActionTrace(bHash common.Hash, bNumber big.Int, tHash common.Hash, tPos uint64, tType string) *ActionTrace {
   441  	return &ActionTrace{
   442  		BlockHash:           bHash,
   443  		BlockNumber:         bNumber,
   444  		TransactionHash:     tHash,
   445  		TransactionPosition: tPos,
   446  		TraceType:           tType,
   447  		TraceAddress:        make([]uint32, 0),
   448  		Result:              &TraceActionResult{},
   449  	}
   450  }
   451  
   452  // NewActionTraceFromTrace creates new instance of type ActionTrace
   453  // based on another trace
   454  func NewActionTraceFromTrace(actionTrace *ActionTrace, tType string, traceAddress []uint32) *ActionTrace {
   455  	trace := NewActionTrace(
   456  		actionTrace.BlockHash,
   457  		actionTrace.BlockNumber,
   458  		actionTrace.TransactionHash,
   459  		actionTrace.TransactionPosition,
   460  		tType)
   461  	trace.TraceAddress = traceAddress
   462  	return trace
   463  }
   464  
   465  const (
   466  	CALL         = "call"
   467  	CREATE       = "create"
   468  	SELFDESTRUCT = "suicide"
   469  )
   470  
   471  // ActionTrace represents single interaction with blockchain
   472  type ActionTrace struct {
   473  	childTraces         []*ActionTrace     `json:"-"`
   474  	Action              AddressAction      `json:"action"`
   475  	BlockHash           common.Hash        `json:"blockHash"`
   476  	BlockNumber         big.Int            `json:"blockNumber"`
   477  	Result              *TraceActionResult `json:"result,omitempty"`
   478  	Error               string             `json:"error,omitempty"`
   479  	Subtraces           uint64             `json:"subtraces"`
   480  	TraceAddress        []uint32           `json:"traceAddress"`
   481  	TransactionHash     common.Hash        `json:"transactionHash"`
   482  	TransactionPosition uint64             `json:"transactionPosition"`
   483  	TraceType           string             `json:"type"`
   484  }
   485  
   486  // NewAddressAction creates specific information about trace addresses
   487  func NewAddressAction(from *common.Address, gas uint64, data []byte, to *common.Address, value hexutil.Big, callType *string) *AddressAction {
   488  	action := AddressAction{
   489  		From:     from,
   490  		To:       to,
   491  		Gas:      hexutil.Uint64(gas),
   492  		Value:    value,
   493  		CallType: callType,
   494  	}
   495  	if callType == nil {
   496  		action.Init = hexutil.Bytes(data)
   497  	} else {
   498  		action.Input = hexutil.Bytes(data)
   499  	}
   500  	return &action
   501  }
   502  
   503  // AddressAction represents more specific information about
   504  // account interaction
   505  type AddressAction struct {
   506  	CallType      *string         `json:"callType,omitempty"`
   507  	From          *common.Address `json:"from"`
   508  	To            *common.Address `json:"to,omitempty"`
   509  	Value         hexutil.Big     `json:"value"`
   510  	Gas           hexutil.Uint64  `json:"gas"`
   511  	Init          hexutil.Bytes   `json:"init,omitempty"`
   512  	Input         hexutil.Bytes   `json:"input,omitempty"`
   513  	Address       *common.Address `json:"address,omitempty"`
   514  	RefundAddress *common.Address `json:"refund_address,omitempty"`
   515  	Balance       *hexutil.Big    `json:"balance,omitempty"`
   516  }
   517  
   518  // TraceActionResult holds information related to result of the
   519  // processed transaction
   520  type TraceActionResult struct {
   521  	GasUsed   hexutil.Uint64  `json:"gasUsed"`
   522  	Output    *hexutil.Bytes  `json:"output,omitempty"`
   523  	Code      hexutil.Bytes   `json:"code,omitempty"`
   524  	Address   *common.Address `json:"address,omitempty"`
   525  	RetOffset uint64          `json:"-"`
   526  	RetSize   uint64          `json:"-"`
   527  }
   528  
   529  // depthState is struct for having state of logs processing
   530  type depthState struct {
   531  	level  int
   532  	create bool
   533  }
   534  
   535  // returns last state
   536  func lastState(state []depthState) *depthState {
   537  	return &state[len(state)-1]
   538  }
   539  
   540  // adds trace address and retuns it
   541  func addTraceAddress(traceAddress []uint32, depth int) []uint32 {
   542  	index := depth - 1
   543  	result := make([]uint32, len(traceAddress))
   544  	copy(result, traceAddress)
   545  	if len(result) <= index {
   546  		result = append(result, 0)
   547  	} else {
   548  		result[index]++
   549  	}
   550  	return result
   551  }
   552  
   553  // removes trace address based on depth of process
   554  func removeTraceAddressLevel(traceAddress []uint32, depth int) []uint32 {
   555  	if len(traceAddress) > depth {
   556  		result := make([]uint32, len(traceAddress))
   557  		copy(result, traceAddress)
   558  
   559  		result = result[:len(result)-1]
   560  		return result
   561  	}
   562  	return traceAddress
   563  }
   564  
   565  // processLastTrace initiates final information distribution
   566  // accros result traces
   567  func (callTrace *CallTrace) processLastTrace() {
   568  	trace := &callTrace.Actions[len(callTrace.Actions)-1]
   569  	callTrace.processTrace(trace)
   570  }
   571  
   572  // processTrace goes thru all trace results and sets info
   573  func (callTrace *CallTrace) processTrace(trace *ActionTrace) {
   574  	trace.Subtraces = uint64(len(trace.childTraces))
   575  	for _, childTrace := range trace.childTraces {
   576  		if CALL == trace.TraceType {
   577  			childTrace.Action.From = trace.Action.To
   578  		} else {
   579  			if trace.Result != nil {
   580  				childTrace.Action.From = trace.Result.Address
   581  			}
   582  		}
   583  
   584  		if childTrace.Result != nil {
   585  			if trace.Action.Gas > childTrace.Result.GasUsed {
   586  				childTrace.Action.Gas = trace.Action.Gas - childTrace.Result.GasUsed
   587  			} else {
   588  				childTrace.Action.Gas = childTrace.Result.GasUsed
   589  			}
   590  		}
   591  		callTrace.AddTrace(childTrace)
   592  		callTrace.processTrace(callTrace.lastTrace())
   593  	}
   594  }
   595  
   596  // GetErrorTrace constructs filled error trace
   597  func GetErrorTrace(blockHash common.Hash, blockNumber big.Int, from *common.Address, to *common.Address, txHash common.Hash, index uint64, err error) *ActionTrace {
   598  	return createErrorTrace(blockHash, blockNumber, from, to, txHash, 0, []byte{}, hexutil.Big{}, index, err)
   599  }
   600  
   601  // GetErrorTrace constructs filled error trace
   602  func GetErrorTraceFromLogger(tr *TraceStructLogger) *ActionTrace {
   603  	if tr == nil {
   604  		return nil
   605  	} else {
   606  		return createErrorTrace(tr.blockHash, tr.blockNumber, tr.from, tr.to, tr.tx, tr.gasUsed, tr.inputData, hexutil.Big(tr.value), uint64(tr.txIndex), tr.err)
   607  	}
   608  }
   609  
   610  // GetErrorTrace constructs filled error trace
   611  func GetErrorTraceFromMsg(msg *types.Message, blockHash common.Hash, blockNumber big.Int, txHash common.Hash, index uint64, err error) *ActionTrace {
   612  	if msg == nil {
   613  		return createErrorTrace(blockHash, blockNumber, nil, &common.Address{}, txHash, 0, []byte{}, hexutil.Big{}, index, err)
   614  	} else {
   615  		from := msg.From()
   616  		return createErrorTrace(blockHash, blockNumber, &from, msg.To(), txHash, msg.Gas(), msg.Data(), hexutil.Big(*msg.Value()), index, err)
   617  	}
   618  }
   619  
   620  // createErrorTrace constructs filled error trace
   621  func createErrorTrace(blockHash common.Hash, blockNumber big.Int,
   622  	from *common.Address, to *common.Address,
   623  	txHash common.Hash, gas uint64, input []byte,
   624  	value hexutil.Big,
   625  	index uint64, err error) *ActionTrace {
   626  
   627  	var blockTrace *ActionTrace
   628  	var txAction *AddressAction
   629  
   630  	if from == nil {
   631  		from = &common.Address{}
   632  	}
   633  
   634  	callType := CALL
   635  	if to != nil {
   636  		blockTrace = NewActionTrace(blockHash, blockNumber, txHash, index, CALL)
   637  		txAction = NewAddressAction(from, gas, input, to, hexutil.Big{}, &callType)
   638  	} else {
   639  		blockTrace = NewActionTrace(blockHash, blockNumber, txHash, index, CREATE)
   640  		txAction = NewAddressAction(from, gas, input, nil, hexutil.Big{}, nil)
   641  	}
   642  	blockTrace.Action = *txAction
   643  	blockTrace.Result = nil
   644  	if err != nil {
   645  		blockTrace.Error = err.Error()
   646  	} else {
   647  		blockTrace.Error = "Reverted"
   648  	}
   649  	return blockTrace
   650  }