prestate.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright 2022 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package native
  17. import (
  18. "encoding/json"
  19. "math/big"
  20. "sync/atomic"
  21. "time"
  22. "github.com/ethereum/go-ethereum/common"
  23. "github.com/ethereum/go-ethereum/common/hexutil"
  24. "github.com/ethereum/go-ethereum/core/vm"
  25. "github.com/ethereum/go-ethereum/crypto"
  26. "github.com/ethereum/go-ethereum/eth/tracers"
  27. )
  28. func init() {
  29. register("prestateTracer", newPrestateTracer)
  30. }
  31. type prestate = map[common.Address]*account
  32. type account struct {
  33. Balance string `json:"balance"`
  34. Nonce uint64 `json:"nonce"`
  35. Code string `json:"code"`
  36. Storage map[common.Hash]common.Hash `json:"storage"`
  37. }
  38. type prestateTracer struct {
  39. env *vm.EVM
  40. prestate prestate
  41. create bool
  42. to common.Address
  43. gasLimit uint64 // Amount of gas bought for the whole tx
  44. interrupt uint32 // Atomic flag to signal execution interruption
  45. reason error // Textual reason for the interruption
  46. }
  47. func newPrestateTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) {
  48. // First callframe contains tx context info
  49. // and is populated on start and end.
  50. return &prestateTracer{prestate: prestate{}}, nil
  51. }
  52. // CaptureStart implements the EVMLogger interface to initialize the tracing operation.
  53. func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
  54. t.env = env
  55. t.create = create
  56. t.to = to
  57. t.lookupAccount(from)
  58. t.lookupAccount(to)
  59. // The recipient balance includes the value transferred.
  60. toBal := hexutil.MustDecodeBig(t.prestate[to].Balance)
  61. toBal = new(big.Int).Sub(toBal, value)
  62. t.prestate[to].Balance = hexutil.EncodeBig(toBal)
  63. // The sender balance is after reducing: value and gasLimit.
  64. // We need to re-add them to get the pre-tx balance.
  65. fromBal := hexutil.MustDecodeBig(t.prestate[from].Balance)
  66. gasPrice := env.TxContext.GasPrice
  67. consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit))
  68. fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas))
  69. t.prestate[from].Balance = hexutil.EncodeBig(fromBal)
  70. t.prestate[from].Nonce--
  71. }
  72. // CaptureEnd is called after the call finishes to finalize the tracing.
  73. func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, _ time.Duration, err error) {
  74. if t.create {
  75. // Exclude created contract.
  76. delete(t.prestate, t.to)
  77. }
  78. }
  79. // CaptureState implements the EVMLogger interface to trace a single step of VM execution.
  80. func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
  81. stack := scope.Stack
  82. stackData := stack.Data()
  83. stackLen := len(stackData)
  84. switch {
  85. case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE):
  86. slot := common.Hash(stackData[stackLen-1].Bytes32())
  87. t.lookupStorage(scope.Contract.Address(), slot)
  88. case stackLen >= 1 && (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT):
  89. addr := common.Address(stackData[stackLen-1].Bytes20())
  90. t.lookupAccount(addr)
  91. case stackLen >= 5 && (op == vm.DELEGATECALL || op == vm.CALL || op == vm.STATICCALL || op == vm.CALLCODE):
  92. addr := common.Address(stackData[stackLen-2].Bytes20())
  93. t.lookupAccount(addr)
  94. case op == vm.CREATE:
  95. addr := scope.Contract.Address()
  96. nonce := t.env.StateDB.GetNonce(addr)
  97. t.lookupAccount(crypto.CreateAddress(addr, nonce))
  98. case stackLen >= 4 && op == vm.CREATE2:
  99. offset := stackData[stackLen-2]
  100. size := stackData[stackLen-3]
  101. init := scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
  102. inithash := crypto.Keccak256(init)
  103. salt := stackData[stackLen-4]
  104. t.lookupAccount(crypto.CreateAddress2(scope.Contract.Address(), salt.Bytes32(), inithash))
  105. }
  106. }
  107. // CaptureFault implements the EVMLogger interface to trace an execution fault.
  108. func (t *prestateTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
  109. }
  110. // CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
  111. func (t *prestateTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
  112. }
  113. // CaptureExit is called when EVM exits a scope, even if the scope didn't
  114. // execute any code.
  115. func (t *prestateTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
  116. }
  117. func (t *prestateTracer) CaptureTxStart(gasLimit uint64) {
  118. t.gasLimit = gasLimit
  119. }
  120. func (t *prestateTracer) CaptureTxEnd(restGas uint64) {}
  121. // GetResult returns the json-encoded nested list of call traces, and any
  122. // error arising from the encoding or forceful termination (via `Stop`).
  123. func (t *prestateTracer) GetResult() (json.RawMessage, error) {
  124. res, err := json.Marshal(t.prestate)
  125. if err != nil {
  126. return nil, err
  127. }
  128. return json.RawMessage(res), t.reason
  129. }
  130. // Stop terminates execution of the tracer at the first opportune moment.
  131. func (t *prestateTracer) Stop(err error) {
  132. t.reason = err
  133. atomic.StoreUint32(&t.interrupt, 1)
  134. }
  135. // lookupAccount fetches details of an account and adds it to the prestate
  136. // if it doesn't exist there.
  137. func (t *prestateTracer) lookupAccount(addr common.Address) {
  138. if _, ok := t.prestate[addr]; ok {
  139. return
  140. }
  141. t.prestate[addr] = &account{
  142. Balance: bigToHex(t.env.StateDB.GetBalance(addr)),
  143. Nonce: t.env.StateDB.GetNonce(addr),
  144. Code: bytesToHex(t.env.StateDB.GetCode(addr)),
  145. Storage: make(map[common.Hash]common.Hash),
  146. }
  147. }
  148. // lookupStorage fetches the requested storage slot and adds
  149. // it to the prestate of the given contract. It assumes `lookupAccount`
  150. // has been performed on the contract before.
  151. func (t *prestateTracer) lookupStorage(addr common.Address, key common.Hash) {
  152. if _, ok := t.prestate[addr].Storage[key]; ok {
  153. return
  154. }
  155. t.prestate[addr].Storage[key] = t.env.StateDB.GetState(addr, key)
  156. }