github.com/gochain-io/gochain@v2.2.26+incompatible/core/state_processor.go (about) 1 // Copyright 2015 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 17 package core 18 19 import ( 20 "context" 21 22 "go.opencensus.io/trace" 23 24 "github.com/gochain-io/gochain/consensus" 25 "github.com/gochain-io/gochain/core/state" 26 "github.com/gochain-io/gochain/core/types" 27 "github.com/gochain-io/gochain/core/vm" 28 "github.com/gochain-io/gochain/crypto" 29 "github.com/gochain-io/gochain/log" 30 "github.com/gochain-io/gochain/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(ctx context.Context, block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { 60 ctx, span := trace.StartSpan(ctx, "StateProcessor.Process") 61 defer span.End() 62 txs := block.Transactions() 63 header := block.Header() 64 span.AddAttributes( 65 trace.Int64Attribute("number", header.Number.Int64()), 66 trace.Int64Attribute("txs", int64(len(txs))), 67 ) 68 69 var ( 70 receipts = make(types.Receipts, len(txs)) 71 usedGas = new(uint64) 72 allLogs []*types.Log 73 gp = new(GasPool).AddGas(block.GasLimit()) 74 ) 75 76 // Create a new emv context and environment. 77 evmContext := NewEVMContextLite(header, p.bc, nil) 78 vmenv := vm.NewEVM(evmContext, statedb, p.config, cfg) 79 signer := types.MakeSigner(p.config, header.Number) 80 81 // Iterate over and process the individual transactions 82 for i, tx := range txs { 83 _, span := trace.StartSpan(ctx, "StateDB.Prepare") 84 statedb.Prepare(tx.Hash(), block.Hash(), i) 85 span.End() 86 87 receipt, _, err := ApplyTransaction(ctx, vmenv, p.config, gp, statedb, header, tx, usedGas, signer) 88 if err != nil { 89 return nil, nil, 0, err 90 } 91 92 receipts[i] = receipt 93 allLogs = append(allLogs, receipt.Logs...) 94 } 95 // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) 96 _ = p.engine.Finalize(ctx, p.bc, header, statedb, block.Transactions(), receipts, false) 97 log.Info("Processed Block", "number", header.Number, "hash", header.Hash(), "count", len(txs), "diff", header.Difficulty, "coinbase", header.Coinbase, "parent", header.ParentHash) 98 99 return receipts, allLogs, *usedGas, nil 100 } 101 102 // ApplyTransaction attempts to apply a transaction to the given state database 103 // and uses the input parameters for its environment. It returns the receipt 104 // for the transaction, gas used and an error if the transaction failed, 105 // indicating the block was invalid. 106 func ApplyTransaction(ctx context.Context, vmenv *vm.EVM, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, signer types.Signer) (*types.Receipt, uint64, error) { 107 ctx, span := trace.StartSpan(ctx, "ApplyTransaction") 108 defer span.End() 109 110 msg, err := tx.AsMessage(ctx, signer) 111 if err != nil { 112 return nil, 0, err 113 } 114 115 vmenv.Context.Origin = msg.From() 116 vmenv.Context.GasPrice = msg.GasPrice() 117 vmenv.Reset() 118 119 // Apply the transaction to the current state (included in the env) 120 _, span = trace.StartSpan(ctx, "ApplyMessage") 121 _, gas, failed, err := ApplyMessage(vmenv, msg, gp) 122 span.End() 123 if err != nil { 124 return nil, 0, err 125 } 126 // Update the state with pending changes 127 var root []byte 128 if config.IsByzantium(header.Number) { 129 _, span := trace.StartSpan(ctx, "StateDB.Finalise") 130 statedb.Finalise(true) 131 span.End() 132 } else { 133 _, span := trace.StartSpan(ctx, "StateDB.IntermediateRoot") 134 root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 135 span.End() 136 } 137 *usedGas += gas 138 139 // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx 140 // based on the eip phase, we're passing wether the root touch-delete accounts. 141 _, span = trace.StartSpan(ctx, "NewReceipt") 142 receipt := types.NewReceipt(root, failed, *usedGas) 143 span.End() 144 145 receipt.TxHash = tx.Hash() 146 receipt.GasUsed = gas 147 // if the transaction created a contract, store the creation address in the receipt. 148 if msg.To() == nil { 149 receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) 150 } 151 152 // Set the receipt logs and create a bloom for filtering 153 _, span = trace.StartSpan(ctx, "StateDB.GetLogs") 154 receipt.Logs = statedb.GetLogs(tx.Hash()) 155 span.End() 156 157 _, span = trace.StartSpan(ctx, "CreateBloom") 158 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 159 span.End() 160 161 return receipt, gas, err 162 }