github.com/theQRL/go-zond@v0.1.1/cmd/evm/internal/t8ntool/execution.go (about) 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 17 package t8ntool 18 19 import ( 20 "fmt" 21 "math/big" 22 23 "github.com/theQRL/go-zond/common" 24 "github.com/theQRL/go-zond/common/math" 25 "github.com/theQRL/go-zond/consensus/ethash" 26 "github.com/theQRL/go-zond/consensus/misc" 27 "github.com/theQRL/go-zond/consensus/misc/eip4844" 28 "github.com/theQRL/go-zond/core" 29 "github.com/theQRL/go-zond/core/rawdb" 30 "github.com/theQRL/go-zond/core/state" 31 "github.com/theQRL/go-zond/core/types" 32 "github.com/theQRL/go-zond/core/vm" 33 "github.com/theQRL/go-zond/crypto" 34 "github.com/theQRL/go-zond/zonddb" 35 "github.com/theQRL/go-zond/log" 36 "github.com/theQRL/go-zond/params" 37 "github.com/theQRL/go-zond/rlp" 38 "github.com/theQRL/go-zond/trie" 39 "golang.org/x/crypto/sha3" 40 ) 41 42 type Prestate struct { 43 Env stEnv `json:"env"` 44 Pre core.GenesisAlloc `json:"pre"` 45 } 46 47 // ExecutionResult contains the execution status after running a state test, any 48 // error that might have occurred and a dump of the final state if requested. 49 type ExecutionResult struct { 50 StateRoot common.Hash `json:"stateRoot"` 51 TxRoot common.Hash `json:"txRoot"` 52 ReceiptRoot common.Hash `json:"receiptsRoot"` 53 LogsHash common.Hash `json:"logsHash"` 54 Bloom types.Bloom `json:"logsBloom" gencodec:"required"` 55 Receipts types.Receipts `json:"receipts"` 56 Rejected []*rejectedTx `json:"rejected,omitempty"` 57 Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` 58 GasUsed math.HexOrDecimal64 `json:"gasUsed"` 59 BaseFee *math.HexOrDecimal256 `json:"currentBaseFee,omitempty"` 60 WithdrawalsRoot *common.Hash `json:"withdrawalsRoot,omitempty"` 61 CurrentExcessBlobGas *math.HexOrDecimal64 `json:"currentExcessBlobGas,omitempty"` 62 CurrentBlobGasUsed *math.HexOrDecimal64 `json:"currentBlobGasUsed,omitempty"` 63 } 64 65 type ommer struct { 66 Delta uint64 `json:"delta"` 67 Address common.Address `json:"address"` 68 } 69 70 //go:generate go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go 71 type stEnv struct { 72 Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` 73 Difficulty *big.Int `json:"currentDifficulty"` 74 Random *big.Int `json:"currentRandom"` 75 ParentDifficulty *big.Int `json:"parentDifficulty"` 76 ParentBaseFee *big.Int `json:"parentBaseFee,omitempty"` 77 ParentGasUsed uint64 `json:"parentGasUsed,omitempty"` 78 ParentGasLimit uint64 `json:"parentGasLimit,omitempty"` 79 GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` 80 Number uint64 `json:"currentNumber" gencodec:"required"` 81 Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` 82 ParentTimestamp uint64 `json:"parentTimestamp,omitempty"` 83 BlockHashes map[math.HexOrDecimal64]common.Hash `json:"blockHashes,omitempty"` 84 Ommers []ommer `json:"ommers,omitempty"` 85 Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` 86 BaseFee *big.Int `json:"currentBaseFee,omitempty"` 87 ParentUncleHash common.Hash `json:"parentUncleHash"` 88 ExcessBlobGas *uint64 `json:"excessBlobGas,omitempty"` 89 ParentExcessBlobGas *uint64 `json:"parentExcessBlobGas,omitempty"` 90 ParentBlobGasUsed *uint64 `json:"parentBlobGasUsed,omitempty"` 91 ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` 92 } 93 94 type stEnvMarshaling struct { 95 Coinbase common.UnprefixedAddress 96 Difficulty *math.HexOrDecimal256 97 Random *math.HexOrDecimal256 98 ParentDifficulty *math.HexOrDecimal256 99 ParentBaseFee *math.HexOrDecimal256 100 ParentGasUsed math.HexOrDecimal64 101 ParentGasLimit math.HexOrDecimal64 102 GasLimit math.HexOrDecimal64 103 Number math.HexOrDecimal64 104 Timestamp math.HexOrDecimal64 105 ParentTimestamp math.HexOrDecimal64 106 BaseFee *math.HexOrDecimal256 107 ExcessBlobGas *math.HexOrDecimal64 108 ParentExcessBlobGas *math.HexOrDecimal64 109 ParentBlobGasUsed *math.HexOrDecimal64 110 } 111 112 type rejectedTx struct { 113 Index int `json:"index"` 114 Err string `json:"error"` 115 } 116 117 // Apply applies a set of transactions to a pre-state 118 func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, 119 txs types.Transactions, miningReward int64, 120 getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error)) (*state.StateDB, *ExecutionResult, error) { 121 // Capture errors for BLOCKHASH operation, if we haven't been supplied the 122 // required blockhashes 123 var hashError error 124 getHash := func(num uint64) common.Hash { 125 if pre.Env.BlockHashes == nil { 126 hashError = fmt.Errorf("getHash(%d) invoked, no blockhashes provided", num) 127 return common.Hash{} 128 } 129 h, ok := pre.Env.BlockHashes[math.HexOrDecimal64(num)] 130 if !ok { 131 hashError = fmt.Errorf("getHash(%d) invoked, blockhash for that block not provided", num) 132 } 133 return h 134 } 135 var ( 136 statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre) 137 signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) 138 gaspool = new(core.GasPool) 139 blockHash = common.Hash{0x13, 0x37} 140 rejectedTxs []*rejectedTx 141 includedTxs types.Transactions 142 gasUsed = uint64(0) 143 receipts = make(types.Receipts, 0) 144 txIndex = 0 145 ) 146 gaspool.AddGas(pre.Env.GasLimit) 147 vmContext := vm.BlockContext{ 148 CanTransfer: core.CanTransfer, 149 Transfer: core.Transfer, 150 Coinbase: pre.Env.Coinbase, 151 BlockNumber: new(big.Int).SetUint64(pre.Env.Number), 152 Time: pre.Env.Timestamp, 153 Difficulty: pre.Env.Difficulty, 154 GasLimit: pre.Env.GasLimit, 155 GetHash: getHash, 156 } 157 // If currentBaseFee is defined, add it to the vmContext. 158 if pre.Env.BaseFee != nil { 159 vmContext.BaseFee = new(big.Int).Set(pre.Env.BaseFee) 160 } 161 // If random is defined, add it to the vmContext. 162 if pre.Env.Random != nil { 163 rnd := common.BigToHash(pre.Env.Random) 164 vmContext.Random = &rnd 165 } 166 // If excessBlobGas is defined, add it to the vmContext. 167 if pre.Env.ExcessBlobGas != nil { 168 vmContext.ExcessBlobGas = pre.Env.ExcessBlobGas 169 } else { 170 // If it is not explicitly defined, but we have the parent values, we try 171 // to calculate it ourselves. 172 parentExcessBlobGas := pre.Env.ParentExcessBlobGas 173 parentBlobGasUsed := pre.Env.ParentBlobGasUsed 174 if parentExcessBlobGas != nil && parentBlobGasUsed != nil { 175 excessBlobGas := eip4844.CalcExcessBlobGas(*parentExcessBlobGas, *parentBlobGasUsed) 176 vmContext.ExcessBlobGas = &excessBlobGas 177 } 178 } 179 // If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's 180 // done in StateProcessor.Process(block, ...), right before transactions are applied. 181 if chainConfig.DAOForkSupport && 182 chainConfig.DAOForkBlock != nil && 183 chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 { 184 misc.ApplyDAOHardFork(statedb) 185 } 186 if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil { 187 evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) 188 core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) 189 } 190 var blobGasUsed uint64 191 for i, tx := range txs { 192 if tx.Type() == types.BlobTxType && vmContext.ExcessBlobGas == nil { 193 errMsg := "blob tx used but field env.ExcessBlobGas missing" 194 log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", errMsg) 195 rejectedTxs = append(rejectedTxs, &rejectedTx{i, errMsg}) 196 continue 197 } 198 msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee) 199 if err != nil { 200 log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err) 201 rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) 202 continue 203 } 204 tracer, err := getTracerFn(txIndex, tx.Hash()) 205 if err != nil { 206 return nil, nil, err 207 } 208 vmConfig.Tracer = tracer 209 statedb.SetTxContext(tx.Hash(), txIndex) 210 211 var ( 212 txContext = core.NewEVMTxContext(msg) 213 snapshot = statedb.Snapshot() 214 prevGas = gaspool.Gas() 215 ) 216 evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig) 217 218 // (ret []byte, usedGas uint64, failed bool, err error) 219 msgResult, err := core.ApplyMessage(evm, msg, gaspool) 220 if err != nil { 221 statedb.RevertToSnapshot(snapshot) 222 log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err) 223 rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) 224 gaspool.SetGas(prevGas) 225 continue 226 } 227 if tx.Type() == types.BlobTxType { 228 blobGasUsed += params.BlobTxBlobGasPerBlob 229 } 230 includedTxs = append(includedTxs, tx) 231 if hashError != nil { 232 return nil, nil, NewError(ErrorMissingBlockhash, hashError) 233 } 234 gasUsed += msgResult.UsedGas 235 236 // Receipt: 237 { 238 var root []byte 239 if chainConfig.IsByzantium(vmContext.BlockNumber) { 240 statedb.Finalise(true) 241 } else { 242 root = statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)).Bytes() 243 } 244 245 // Create a new receipt for the transaction, storing the intermediate root and 246 // gas used by the tx. 247 receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: gasUsed} 248 if msgResult.Failed() { 249 receipt.Status = types.ReceiptStatusFailed 250 } else { 251 receipt.Status = types.ReceiptStatusSuccessful 252 } 253 receipt.TxHash = tx.Hash() 254 receipt.GasUsed = msgResult.UsedGas 255 256 // If the transaction created a contract, store the creation address in the receipt. 257 if msg.To == nil { 258 receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) 259 } 260 261 // Set the receipt logs and create the bloom filter. 262 receipt.Logs = statedb.GetLogs(tx.Hash(), vmContext.BlockNumber.Uint64(), blockHash) 263 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 264 // These three are non-consensus fields: 265 //receipt.BlockHash 266 //receipt.BlockNumber 267 receipt.TransactionIndex = uint(txIndex) 268 receipts = append(receipts, receipt) 269 } 270 271 txIndex++ 272 } 273 statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)) 274 // Add mining reward? (-1 means rewards are disabled) 275 if miningReward >= 0 { 276 // Add mining reward. The mining reward may be `0`, which only makes a difference in the cases 277 // where 278 // - the coinbase self-destructed, or 279 // - there are only 'bad' transactions, which aren't executed. In those cases, 280 // the coinbase gets no txfee, so isn't created, and thus needs to be touched 281 var ( 282 blockReward = big.NewInt(miningReward) 283 minerReward = new(big.Int).Set(blockReward) 284 perOmmer = new(big.Int).Div(blockReward, big.NewInt(32)) 285 ) 286 for _, ommer := range pre.Env.Ommers { 287 // Add 1/32th for each ommer included 288 minerReward.Add(minerReward, perOmmer) 289 // Add (8-delta)/8 290 reward := big.NewInt(8) 291 reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta)) 292 reward.Mul(reward, blockReward) 293 reward.Div(reward, big.NewInt(8)) 294 statedb.AddBalance(ommer.Address, reward) 295 } 296 statedb.AddBalance(pre.Env.Coinbase, minerReward) 297 } 298 // Apply withdrawals 299 for _, w := range pre.Env.Withdrawals { 300 // Amount is in gwei, turn into wei 301 amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei)) 302 statedb.AddBalance(w.Address, amount) 303 } 304 // Commit block 305 root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber)) 306 if err != nil { 307 return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) 308 } 309 execRs := &ExecutionResult{ 310 StateRoot: root, 311 TxRoot: types.DeriveSha(includedTxs, trie.NewStackTrie(nil)), 312 ReceiptRoot: types.DeriveSha(receipts, trie.NewStackTrie(nil)), 313 Bloom: types.CreateBloom(receipts), 314 LogsHash: rlpHash(statedb.Logs()), 315 Receipts: receipts, 316 Rejected: rejectedTxs, 317 Difficulty: (*math.HexOrDecimal256)(vmContext.Difficulty), 318 GasUsed: (math.HexOrDecimal64)(gasUsed), 319 BaseFee: (*math.HexOrDecimal256)(vmContext.BaseFee), 320 } 321 if pre.Env.Withdrawals != nil { 322 h := types.DeriveSha(types.Withdrawals(pre.Env.Withdrawals), trie.NewStackTrie(nil)) 323 execRs.WithdrawalsRoot = &h 324 } 325 if vmContext.ExcessBlobGas != nil { 326 execRs.CurrentExcessBlobGas = (*math.HexOrDecimal64)(vmContext.ExcessBlobGas) 327 execRs.CurrentBlobGasUsed = (*math.HexOrDecimal64)(&blobGasUsed) 328 } 329 // Re-create statedb instance with new root upon the updated database 330 // for accessing latest states. 331 statedb, err = state.New(root, statedb.Database(), nil) 332 if err != nil { 333 return nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err)) 334 } 335 return statedb, execRs, nil 336 } 337 338 func MakePreState(db zonddb.Database, accounts core.GenesisAlloc) *state.StateDB { 339 sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true}) 340 statedb, _ := state.New(types.EmptyRootHash, sdb, nil) 341 for addr, a := range accounts { 342 statedb.SetCode(addr, a.Code) 343 statedb.SetNonce(addr, a.Nonce) 344 statedb.SetBalance(addr, a.Balance) 345 for k, v := range a.Storage { 346 statedb.SetState(addr, k, v) 347 } 348 } 349 // Commit and re-open to start with a clean state. 350 root, _ := statedb.Commit(0, false) 351 statedb, _ = state.New(root, sdb, nil) 352 return statedb 353 } 354 355 func rlpHash(x interface{}) (h common.Hash) { 356 hw := sha3.NewLegacyKeccak256() 357 rlp.Encode(hw, x) 358 hw.Sum(h[:0]) 359 return h 360 } 361 362 // calcDifficulty is based on ethash.CalcDifficulty. This method is used in case 363 // the caller does not provide an explicit difficulty, but instead provides only 364 // parent timestamp + difficulty. 365 // Note: this method only works for ethash engine. 366 func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime uint64, 367 parentDifficulty *big.Int, parentUncleHash common.Hash) *big.Int { 368 uncleHash := parentUncleHash 369 if uncleHash == (common.Hash{}) { 370 uncleHash = types.EmptyUncleHash 371 } 372 parent := &types.Header{ 373 ParentHash: common.Hash{}, 374 UncleHash: uncleHash, 375 Difficulty: parentDifficulty, 376 Number: new(big.Int).SetUint64(number - 1), 377 Time: parentTime, 378 } 379 return ethash.CalcDifficulty(config, currentTime, parent) 380 }