github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/core/state_processor.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "math/big" 21 22 "github.com/SmartMeshFoundation/Spectrum/common" 23 "github.com/SmartMeshFoundation/Spectrum/consensus" 24 "github.com/SmartMeshFoundation/Spectrum/consensus/misc" 25 "github.com/SmartMeshFoundation/Spectrum/core/state" 26 "github.com/SmartMeshFoundation/Spectrum/core/types" 27 "github.com/SmartMeshFoundation/Spectrum/core/vm" 28 "github.com/SmartMeshFoundation/Spectrum/crypto" 29 "github.com/SmartMeshFoundation/Spectrum/log" 30 "github.com/SmartMeshFoundation/Spectrum/params" 31 ) 32 33 // StateProcessor is a basic Processor, which takes care of transitioning 34 // state from one point to another. 35 // 36 // StateProcessor implements Processor. 37 type StateProcessor struct { 38 config *params.ChainConfig // Chain configuration options 39 bc *BlockChain // Canonical block chain 40 engine consensus.Engine // Consensus engine used for block rewards 41 } 42 43 // NewStateProcessor initialises a new StateProcessor. 44 func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor { 45 return &StateProcessor{ 46 config: config, 47 bc: bc, 48 engine: engine, 49 } 50 } 51 52 // Process processes the state changes according to the Ethereum rules by running 53 // the transaction messages using the statedb and applying any rewards to both 54 // the processor (coinbase) and any included uncles. 55 // 56 // Process returns the receipts and logs accumulated during the process and 57 // returns the amount of gas that was used in the process. If any of the 58 // transactions failed to execute due to insufficient gas it will return an error. 59 func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) { 60 var ( 61 receipts types.Receipts 62 totalUsedGas = big.NewInt(0) 63 header = block.Header() 64 allLogs []*types.Log 65 gp = new(GasPool).AddGas(block.GasLimit()) 66 ) 67 // Mutate the the block and state according to any hard-fork specs 68 if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { 69 misc.ApplyDAOHardFork(statedb) 70 } 71 // Iterate over and process the individual transactions 72 for i, tx := range block.Transactions() { 73 statedb.Prepare(tx.Hash(), block.Hash(), i) 74 //fmt.Println("--Process>>>>>>",i,tx.Hash().String()) 75 receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, totalUsedGas, cfg) 76 if err != nil { 77 return nil, nil, nil, err 78 } 79 //fmt.Println("--Process>>>>>>",totalUsedGas) 80 receipts = append(receipts, receipt) 81 allLogs = append(allLogs, receipt.Logs...) 82 } 83 // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) 84 p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts) 85 86 return receipts, allLogs, totalUsedGas, nil 87 } 88 89 // ApplyTransaction attempts to apply a transaction to the given state database 90 // and uses the input parameters for its environment. It returns the receipt 91 // for the transaction, gas used and an error if the transaction failed, 92 // indicating the block was invalid. 93 func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, *big.Int, error) { 94 msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) 95 if err != nil { 96 return nil, nil, err 97 } 98 // Create a new context to be used in the EVM environment 99 context := NewEVMContext(msg, header, bc, author) 100 // Create a new environment which holds all relevant information 101 // about the transaction and calling mechanisms. 102 vmenv := vm.NewEVM(context, statedb, config, cfg) 103 // Apply the transaction to the current state (included in the env) 104 _, gas, failed, err := ApplyMessage(vmenv, msg, gp, bc.currentBlock.Number()) 105 if err != nil { 106 return nil, nil, err 107 } 108 109 // Update the state with pending changes 110 var root []byte 111 if config.IsByzantium(header.Number) { 112 statedb.Finalise(true) 113 } else { 114 root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 115 } 116 // add by liangc 117 if params.IsSIP001Block(bc.currentBlock.Number()) && tx.To() != nil && params.IsChiefAddress(*tx.To()) && params.IsChiefUpdate(tx.Data()) { 118 log.Debug("⛽️ --> pay_back_chief_gas", "txid", tx.Hash().Hex(), "gas", gas) 119 gp.AddGas(gas) 120 } else { 121 usedGas.Add(usedGas, gas) 122 } 123 // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx 124 // based on the eip phase, we're passing wether the root touch-delete accounts. 125 // TODO may be error 126 receipt := types.NewReceipt(root, failed, usedGas) 127 receipt.TxHash = tx.Hash() 128 // add by liangc : fit gaslimt 129 if !(params.IsSIP001Block(bc.currentBlock.Number()) && tx.To() != nil && params.IsChiefAddress(*tx.To()) && params.IsChiefUpdate(tx.Data())) { 130 receipt.GasUsed = new(big.Int).Set(gas) 131 } 132 // if the transaction created a contract, store the creation address in the receipt. 133 if msg.To() == nil { 134 receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) 135 } 136 137 // Set the receipt logs and create a bloom for filtering 138 receipt.Logs = statedb.GetLogs(tx.Hash()) 139 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 140 141 return receipt, gas, err 142 }