execution.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. // Copyright 2020 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 t8ntool
  17. import (
  18. "fmt"
  19. "math/big"
  20. "os"
  21. "github.com/ethereum/go-ethereum/common"
  22. "github.com/ethereum/go-ethereum/common/math"
  23. "github.com/ethereum/go-ethereum/consensus/misc"
  24. "github.com/ethereum/go-ethereum/core"
  25. "github.com/ethereum/go-ethereum/core/rawdb"
  26. "github.com/ethereum/go-ethereum/core/state"
  27. "github.com/ethereum/go-ethereum/core/types"
  28. "github.com/ethereum/go-ethereum/core/vm"
  29. "github.com/ethereum/go-ethereum/crypto"
  30. "github.com/ethereum/go-ethereum/ethdb"
  31. "github.com/ethereum/go-ethereum/log"
  32. "github.com/ethereum/go-ethereum/params"
  33. "github.com/ethereum/go-ethereum/rlp"
  34. "github.com/ethereum/go-ethereum/trie"
  35. "golang.org/x/crypto/sha3"
  36. )
  37. type Prestate struct {
  38. Env stEnv `json:"env"`
  39. Pre core.GenesisAlloc `json:"pre"`
  40. }
  41. // ExecutionResult contains the execution status after running a state test, any
  42. // error that might have occurred and a dump of the final state if requested.
  43. type ExecutionResult struct {
  44. StateRoot common.Hash `json:"stateRoot"`
  45. TxRoot common.Hash `json:"txRoot"`
  46. ReceiptRoot common.Hash `json:"receiptRoot"`
  47. LogsHash common.Hash `json:"logsHash"`
  48. Bloom types.Bloom `json:"logsBloom" gencodec:"required"`
  49. Receipts types.Receipts `json:"receipts"`
  50. Rejected []int `json:"rejected,omitempty"`
  51. }
  52. type ommer struct {
  53. Delta uint64 `json:"delta"`
  54. Address common.Address `json:"address"`
  55. }
  56. //go:generate gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go
  57. type stEnv struct {
  58. Coinbase common.Address `json:"currentCoinbase" gencodec:"required"`
  59. Difficulty *big.Int `json:"currentDifficulty" gencodec:"required"`
  60. GasLimit uint64 `json:"currentGasLimit" gencodec:"required"`
  61. Number uint64 `json:"currentNumber" gencodec:"required"`
  62. Timestamp uint64 `json:"currentTimestamp" gencodec:"required"`
  63. BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
  64. Ommers []ommer `json:"ommers,omitempty"`
  65. }
  66. type stEnvMarshaling struct {
  67. Coinbase common.UnprefixedAddress
  68. Difficulty *math.HexOrDecimal256
  69. GasLimit math.HexOrDecimal64
  70. Number math.HexOrDecimal64
  71. Timestamp math.HexOrDecimal64
  72. }
  73. // Apply applies a set of transactions to a pre-state
  74. func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
  75. txs types.Transactions, miningReward int64,
  76. getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.Tracer, err error)) (*state.StateDB, *ExecutionResult, error) {
  77. // Capture errors for BLOCKHASH operation, if we haven't been supplied the
  78. // required blockhashes
  79. var hashError error
  80. getHash := func(num uint64) common.Hash {
  81. if pre.Env.BlockHashes == nil {
  82. hashError = fmt.Errorf("getHash(%d) invoked, no blockhashes provided", num)
  83. return common.Hash{}
  84. }
  85. h, ok := pre.Env.BlockHashes[math.HexOrDecimal64(num)]
  86. if !ok {
  87. hashError = fmt.Errorf("getHash(%d) invoked, blockhash for that block not provided", num)
  88. }
  89. return h
  90. }
  91. var (
  92. statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre)
  93. signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number))
  94. gaspool = new(core.GasPool)
  95. blockHash = common.Hash{0x13, 0x37}
  96. rejectedTxs []int
  97. includedTxs types.Transactions
  98. gasUsed = uint64(0)
  99. receipts = make(types.Receipts, 0)
  100. txIndex = 0
  101. )
  102. gaspool.AddGas(pre.Env.GasLimit)
  103. vmContext := vm.BlockContext{
  104. CanTransfer: core.CanTransfer,
  105. Transfer: core.Transfer,
  106. Coinbase: pre.Env.Coinbase,
  107. BlockNumber: new(big.Int).SetUint64(pre.Env.Number),
  108. Time: new(big.Int).SetUint64(pre.Env.Timestamp),
  109. Difficulty: pre.Env.Difficulty,
  110. GasLimit: pre.Env.GasLimit,
  111. GetHash: getHash,
  112. }
  113. // If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's
  114. // done in StateProcessor.Process(block, ...), right before transactions are applied.
  115. if chainConfig.DAOForkSupport &&
  116. chainConfig.DAOForkBlock != nil &&
  117. chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 {
  118. misc.ApplyDAOHardFork(statedb)
  119. }
  120. for i, tx := range txs {
  121. msg, err := tx.AsMessage(signer)
  122. if err != nil {
  123. log.Info("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
  124. rejectedTxs = append(rejectedTxs, i)
  125. continue
  126. }
  127. tracer, err := getTracerFn(txIndex, tx.Hash())
  128. if err != nil {
  129. return nil, nil, err
  130. }
  131. vmConfig.Tracer = tracer
  132. vmConfig.Debug = (tracer != nil)
  133. statedb.Prepare(tx.Hash(), blockHash, txIndex)
  134. txContext := core.NewEVMTxContext(msg)
  135. evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
  136. if chainConfig.IsYoloV2(vmContext.BlockNumber) {
  137. statedb.AddAddressToAccessList(msg.From())
  138. if dst := msg.To(); dst != nil {
  139. statedb.AddAddressToAccessList(*dst)
  140. // If it's a create-tx, the destination will be added inside evm.create
  141. }
  142. for _, addr := range evm.ActivePrecompiles() {
  143. statedb.AddAddressToAccessList(addr)
  144. }
  145. }
  146. snapshot := statedb.Snapshot()
  147. // (ret []byte, usedGas uint64, failed bool, err error)
  148. msgResult, err := core.ApplyMessage(evm, msg, gaspool)
  149. if err != nil {
  150. statedb.RevertToSnapshot(snapshot)
  151. log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
  152. rejectedTxs = append(rejectedTxs, i)
  153. continue
  154. }
  155. includedTxs = append(includedTxs, tx)
  156. if hashError != nil {
  157. return nil, nil, NewError(ErrorMissingBlockhash, hashError)
  158. }
  159. gasUsed += msgResult.UsedGas
  160. // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
  161. {
  162. var root []byte
  163. if chainConfig.IsByzantium(vmContext.BlockNumber) {
  164. statedb.Finalise(true)
  165. } else {
  166. root = statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)).Bytes()
  167. }
  168. receipt := types.NewReceipt(root, msgResult.Failed(), gasUsed)
  169. receipt.TxHash = tx.Hash()
  170. receipt.GasUsed = msgResult.UsedGas
  171. // if the transaction created a contract, store the creation address in the receipt.
  172. if msg.To() == nil {
  173. receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
  174. }
  175. // Set the receipt logs and create a bloom for filtering
  176. receipt.Logs = statedb.GetLogs(tx.Hash())
  177. receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
  178. // These three are non-consensus fields
  179. //receipt.BlockHash
  180. //receipt.BlockNumber =
  181. receipt.TransactionIndex = uint(txIndex)
  182. receipts = append(receipts, receipt)
  183. }
  184. txIndex++
  185. }
  186. statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))
  187. // Add mining reward?
  188. if miningReward > 0 {
  189. // Add mining reward. The mining reward may be `0`, which only makes a difference in the cases
  190. // where
  191. // - the coinbase suicided, or
  192. // - there are only 'bad' transactions, which aren't executed. In those cases,
  193. // the coinbase gets no txfee, so isn't created, and thus needs to be touched
  194. var (
  195. blockReward = big.NewInt(miningReward)
  196. minerReward = new(big.Int).Set(blockReward)
  197. perOmmer = new(big.Int).Div(blockReward, big.NewInt(32))
  198. )
  199. for _, ommer := range pre.Env.Ommers {
  200. // Add 1/32th for each ommer included
  201. minerReward.Add(minerReward, perOmmer)
  202. // Add (8-delta)/8
  203. reward := big.NewInt(8)
  204. reward.Sub(reward, big.NewInt(0).SetUint64(ommer.Delta))
  205. reward.Mul(reward, blockReward)
  206. reward.Div(reward, big.NewInt(8))
  207. statedb.AddBalance(ommer.Address, reward)
  208. }
  209. statedb.AddBalance(pre.Env.Coinbase, minerReward)
  210. }
  211. // Commit block
  212. root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber))
  213. if err != nil {
  214. fmt.Fprintf(os.Stderr, "Could not commit state: %v", err)
  215. return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err))
  216. }
  217. execRs := &ExecutionResult{
  218. StateRoot: root,
  219. TxRoot: types.DeriveSha(includedTxs, new(trie.Trie)),
  220. ReceiptRoot: types.DeriveSha(receipts, new(trie.Trie)),
  221. Bloom: types.CreateBloom(receipts),
  222. LogsHash: rlpHash(statedb.Logs()),
  223. Receipts: receipts,
  224. Rejected: rejectedTxs,
  225. }
  226. return statedb, execRs, nil
  227. }
  228. func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB {
  229. sdb := state.NewDatabase(db)
  230. statedb, _ := state.New(common.Hash{}, sdb, nil)
  231. for addr, a := range accounts {
  232. statedb.SetCode(addr, a.Code)
  233. statedb.SetNonce(addr, a.Nonce)
  234. statedb.SetBalance(addr, a.Balance)
  235. for k, v := range a.Storage {
  236. statedb.SetState(addr, k, v)
  237. }
  238. }
  239. // Commit and re-open to start with a clean state.
  240. root, _ := statedb.Commit(false)
  241. statedb, _ = state.New(root, sdb, nil)
  242. return statedb
  243. }
  244. func rlpHash(x interface{}) (h common.Hash) {
  245. hw := sha3.NewLegacyKeccak256()
  246. rlp.Encode(hw, x)
  247. hw.Sum(h[:0])
  248. return h
  249. }