execution.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // Copyright 2020 The go-ethereum Authors
  2. // This file is part of go-ethereum.
  3. //
  4. // go-ethereum is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU 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. // go-ethereum 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 General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with go-ethereum. 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/ethash"
  24. "github.com/ethereum/go-ethereum/consensus/misc"
  25. "github.com/ethereum/go-ethereum/core"
  26. "github.com/ethereum/go-ethereum/core/rawdb"
  27. "github.com/ethereum/go-ethereum/core/state"
  28. "github.com/ethereum/go-ethereum/core/types"
  29. "github.com/ethereum/go-ethereum/core/vm"
  30. "github.com/ethereum/go-ethereum/crypto"
  31. "github.com/ethereum/go-ethereum/ethdb"
  32. "github.com/ethereum/go-ethereum/log"
  33. "github.com/ethereum/go-ethereum/params"
  34. "github.com/ethereum/go-ethereum/rlp"
  35. "github.com/ethereum/go-ethereum/trie"
  36. "golang.org/x/crypto/sha3"
  37. )
  38. type Prestate struct {
  39. Env stEnv `json:"env"`
  40. Pre core.GenesisAlloc `json:"pre"`
  41. }
  42. // ExecutionResult contains the execution status after running a state test, any
  43. // error that might have occurred and a dump of the final state if requested.
  44. type ExecutionResult struct {
  45. StateRoot common.Hash `json:"stateRoot"`
  46. TxRoot common.Hash `json:"txRoot"`
  47. ReceiptRoot common.Hash `json:"receiptsRoot"`
  48. LogsHash common.Hash `json:"logsHash"`
  49. Bloom types.Bloom `json:"logsBloom" gencodec:"required"`
  50. Receipts types.Receipts `json:"receipts"`
  51. Rejected []*rejectedTx `json:"rejected,omitempty"`
  52. Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"`
  53. GasUsed math.HexOrDecimal64 `json:"gasUsed"`
  54. }
  55. type ommer struct {
  56. Delta uint64 `json:"delta"`
  57. Address common.Address `json:"address"`
  58. }
  59. //go:generate go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go
  60. type stEnv struct {
  61. Coinbase common.Address `json:"currentCoinbase" gencodec:"required"`
  62. Difficulty *big.Int `json:"currentDifficulty"`
  63. Random *big.Int `json:"currentRandom"`
  64. ParentDifficulty *big.Int `json:"parentDifficulty"`
  65. GasLimit uint64 `json:"currentGasLimit" gencodec:"required"`
  66. Number uint64 `json:"currentNumber" gencodec:"required"`
  67. Timestamp uint64 `json:"currentTimestamp" gencodec:"required"`
  68. ParentTimestamp uint64 `json:"parentTimestamp,omitempty"`
  69. BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"`
  70. Ommers []ommer `json:"ommers,omitempty"`
  71. BaseFee *big.Int `json:"currentBaseFee,omitempty"`
  72. ParentUncleHash common.Hash `json:"parentUncleHash"`
  73. }
  74. type stEnvMarshaling struct {
  75. Coinbase common.UnprefixedAddress
  76. Difficulty *math.HexOrDecimal256
  77. Random *math.HexOrDecimal256
  78. ParentDifficulty *math.HexOrDecimal256
  79. GasLimit math.HexOrDecimal64
  80. Number math.HexOrDecimal64
  81. Timestamp math.HexOrDecimal64
  82. ParentTimestamp math.HexOrDecimal64
  83. BaseFee *math.HexOrDecimal256
  84. }
  85. type rejectedTx struct {
  86. Index int `json:"index"`
  87. Err string `json:"error"`
  88. }
  89. // Apply applies a set of transactions to a pre-state
  90. func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
  91. txs types.Transactions, miningReward int64,
  92. getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error)) (*state.StateDB, *ExecutionResult, error) {
  93. // Capture errors for BLOCKHASH operation, if we haven't been supplied the
  94. // required blockhashes
  95. var hashError error
  96. getHash := func(num uint64) common.Hash {
  97. if pre.Env.BlockHashes == nil {
  98. hashError = fmt.Errorf("getHash(%d) invoked, no blockhashes provided", num)
  99. return common.Hash{}
  100. }
  101. h, ok := pre.Env.BlockHashes[math.HexOrDecimal64(num)]
  102. if !ok {
  103. hashError = fmt.Errorf("getHash(%d) invoked, blockhash for that block not provided", num)
  104. }
  105. return h
  106. }
  107. var (
  108. statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre)
  109. signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number))
  110. gaspool = new(core.GasPool)
  111. blockHash = common.Hash{0x13, 0x37}
  112. rejectedTxs []*rejectedTx
  113. includedTxs types.Transactions
  114. gasUsed = uint64(0)
  115. receipts = make(types.Receipts, 0)
  116. txIndex = 0
  117. )
  118. gaspool.AddGas(pre.Env.GasLimit)
  119. vmContext := vm.BlockContext{
  120. CanTransfer: core.CanTransfer,
  121. Transfer: core.Transfer,
  122. Coinbase: pre.Env.Coinbase,
  123. BlockNumber: new(big.Int).SetUint64(pre.Env.Number),
  124. Time: new(big.Int).SetUint64(pre.Env.Timestamp),
  125. Difficulty: pre.Env.Difficulty,
  126. GasLimit: pre.Env.GasLimit,
  127. GetHash: getHash,
  128. }
  129. // If currentBaseFee is defined, add it to the vmContext.
  130. if pre.Env.BaseFee != nil {
  131. vmContext.BaseFee = new(big.Int).Set(pre.Env.BaseFee)
  132. }
  133. // If random is defined, add it to the vmContext.
  134. if pre.Env.Random != nil {
  135. rnd := common.BigToHash(pre.Env.Random)
  136. vmContext.Random = &rnd
  137. }
  138. // If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's
  139. // done in StateProcessor.Process(block, ...), right before transactions are applied.
  140. if chainConfig.DAOForkSupport &&
  141. chainConfig.DAOForkBlock != nil &&
  142. chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 {
  143. misc.ApplyDAOHardFork(statedb)
  144. }
  145. for i, tx := range txs {
  146. msg, err := tx.AsMessage(signer, pre.Env.BaseFee)
  147. if err != nil {
  148. log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
  149. rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
  150. continue
  151. }
  152. tracer, err := getTracerFn(txIndex, tx.Hash())
  153. if err != nil {
  154. return nil, nil, err
  155. }
  156. vmConfig.Tracer = tracer
  157. vmConfig.Debug = (tracer != nil)
  158. statedb.Prepare(tx.Hash(), txIndex)
  159. txContext := core.NewEVMTxContext(msg)
  160. snapshot := statedb.Snapshot()
  161. evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
  162. // (ret []byte, usedGas uint64, failed bool, err error)
  163. msgResult, err := core.ApplyMessage(evm, msg, gaspool)
  164. if err != nil {
  165. statedb.RevertToSnapshot(snapshot)
  166. log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
  167. rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
  168. continue
  169. }
  170. includedTxs = append(includedTxs, tx)
  171. if hashError != nil {
  172. return nil, nil, NewError(ErrorMissingBlockhash, hashError)
  173. }
  174. gasUsed += msgResult.UsedGas
  175. // Receipt:
  176. {
  177. var root []byte
  178. if chainConfig.IsByzantium(vmContext.BlockNumber) {
  179. statedb.Finalise(true)
  180. } else {
  181. root = statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)).Bytes()
  182. }
  183. // Create a new receipt for the transaction, storing the intermediate root and
  184. // gas used by the tx.
  185. receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: gasUsed}
  186. if msgResult.Failed() {
  187. receipt.Status = types.ReceiptStatusFailed
  188. } else {
  189. receipt.Status = types.ReceiptStatusSuccessful
  190. }
  191. receipt.TxHash = tx.Hash()
  192. receipt.GasUsed = msgResult.UsedGas
  193. // If the transaction created a contract, store the creation address in the receipt.
  194. if msg.To() == nil {
  195. receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
  196. }
  197. // Set the receipt logs and create the bloom filter.
  198. receipt.Logs = statedb.GetLogs(tx.Hash(), blockHash)
  199. receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
  200. // These three are non-consensus fields:
  201. //receipt.BlockHash
  202. //receipt.BlockNumber
  203. receipt.TransactionIndex = uint(txIndex)
  204. receipts = append(receipts, receipt)
  205. }
  206. txIndex++
  207. }
  208. statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber))
  209. // Add mining reward?
  210. if miningReward > 0 {
  211. // Add mining reward. The mining reward may be `0`, which only makes a difference in the cases
  212. // where
  213. // - the coinbase suicided, or
  214. // - there are only 'bad' transactions, which aren't executed. In those cases,
  215. // the coinbase gets no txfee, so isn't created, and thus needs to be touched
  216. var (
  217. blockReward = big.NewInt(miningReward)
  218. minerReward = new(big.Int).Set(blockReward)
  219. perOmmer = new(big.Int).Div(blockReward, big.NewInt(32))
  220. )
  221. for _, ommer := range pre.Env.Ommers {
  222. // Add 1/32th for each ommer included
  223. minerReward.Add(minerReward, perOmmer)
  224. // Add (8-delta)/8
  225. reward := big.NewInt(8)
  226. reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
  227. reward.Mul(reward, blockReward)
  228. reward.Div(reward, big.NewInt(8))
  229. statedb.AddBalance(ommer.Address, reward)
  230. }
  231. statedb.AddBalance(pre.Env.Coinbase, minerReward)
  232. }
  233. // Commit block
  234. root, err := statedb.Commit(chainConfig.IsEIP158(vmContext.BlockNumber))
  235. if err != nil {
  236. fmt.Fprintf(os.Stderr, "Could not commit state: %v", err)
  237. return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err))
  238. }
  239. execRs := &ExecutionResult{
  240. StateRoot: root,
  241. TxRoot: types.DeriveSha(includedTxs, trie.NewStackTrie(nil)),
  242. ReceiptRoot: types.DeriveSha(receipts, trie.NewStackTrie(nil)),
  243. Bloom: types.CreateBloom(receipts),
  244. LogsHash: rlpHash(statedb.Logs()),
  245. Receipts: receipts,
  246. Rejected: rejectedTxs,
  247. Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty),
  248. GasUsed: (math.HexOrDecimal64)(gasUsed),
  249. }
  250. return statedb, execRs, nil
  251. }
  252. func MakePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB {
  253. sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true})
  254. statedb, _ := state.New(common.Hash{}, sdb, nil)
  255. for addr, a := range accounts {
  256. statedb.SetCode(addr, a.Code)
  257. statedb.SetNonce(addr, a.Nonce)
  258. statedb.SetBalance(addr, a.Balance)
  259. for k, v := range a.Storage {
  260. statedb.SetState(addr, k, v)
  261. }
  262. }
  263. // Commit and re-open to start with a clean state.
  264. root, _ := statedb.Commit(false)
  265. statedb, _ = state.New(root, sdb, nil)
  266. return statedb
  267. }
  268. func rlpHash(x interface{}) (h common.Hash) {
  269. hw := sha3.NewLegacyKeccak256()
  270. rlp.Encode(hw, x)
  271. hw.Sum(h[:0])
  272. return h
  273. }
  274. // calcDifficulty is based on ethash.CalcDifficulty. This method is used in case
  275. // the caller does not provide an explicit difficulty, but instead provides only
  276. // parent timestamp + difficulty.
  277. // Note: this method only works for ethash engine.
  278. func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime uint64,
  279. parentDifficulty *big.Int, parentUncleHash common.Hash) *big.Int {
  280. uncleHash := parentUncleHash
  281. if uncleHash == (common.Hash{}) {
  282. uncleHash = types.EmptyUncleHash
  283. }
  284. parent := &types.Header{
  285. ParentHash: common.Hash{},
  286. UncleHash: uncleHash,
  287. Difficulty: parentDifficulty,
  288. Number: new(big.Int).SetUint64(number - 1),
  289. Time: parentTime,
  290. }
  291. return ethash.CalcDifficulty(config, currentTime, parent)
  292. }