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 }