github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/core/state_processor.go (about) 1 package core 2 3 import ( 4 "fmt" 5 "math/big" 6 7 "github.com/neatlab/neatio/chain/consensus" 8 "github.com/neatlab/neatio/chain/core/state" 9 "github.com/neatlab/neatio/chain/core/types" 10 "github.com/neatlab/neatio/chain/core/vm" 11 "github.com/neatlab/neatio/chain/log" 12 neatAbi "github.com/neatlab/neatio/neatabi/abi" 13 "github.com/neatlab/neatio/params" 14 "github.com/neatlab/neatio/utilities/common" 15 "github.com/neatlab/neatio/utilities/crypto" 16 ) 17 18 type StateProcessor struct { 19 config *params.ChainConfig 20 bc *BlockChain 21 engine consensus.Engine 22 cch CrossChainHelper 23 } 24 25 func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine, cch CrossChainHelper) *StateProcessor { 26 return &StateProcessor{ 27 config: config, 28 bc: bc, 29 engine: engine, 30 cch: cch, 31 } 32 } 33 34 func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *types.PendingOps, error) { 35 var ( 36 receipts types.Receipts 37 usedGas = new(uint64) 38 header = block.Header() 39 allLogs []*types.Log 40 gp = new(GasPool).AddGas(block.GasLimit()) 41 ops = new(types.PendingOps) 42 ) 43 44 totalUsedMoney := big.NewInt(0) 45 46 for i, tx := range block.Transactions() { 47 statedb.Prepare(tx.Hash(), block.Hash(), i) 48 49 receipt, err := ApplyTransactionEx(p.config, p.bc, nil, gp, statedb, ops, header, tx, 50 usedGas, totalUsedMoney, cfg, p.cch, false) 51 log.Debugf("(p *StateProcessor) Process(),after ApplyTransactionEx, receipt is %v\n", receipt) 52 if err != nil { 53 return nil, nil, 0, nil, err 54 } 55 receipts = append(receipts, receipt) 56 allLogs = append(allLogs, receipt.Logs...) 57 } 58 59 _, err := p.engine.Finalize(p.bc, header, statedb, block.Transactions(), totalUsedMoney, block.Uncles(), receipts, ops) 60 if err != nil { 61 return nil, nil, 0, nil, err 62 } 63 64 return receipts, allLogs, *usedGas, ops, nil 65 } 66 67 func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { 68 msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) 69 if err != nil { 70 return nil, err 71 } 72 73 context := NewEVMContext(msg, header, bc, author) 74 75 vmenv := vm.NewEVM(context, statedb, config, cfg) 76 77 result, err := ApplyMessage(vmenv, msg, gp) 78 if err != nil { 79 return nil, err 80 } 81 82 var root []byte 83 if config.IsByzantium(header.Number) { 84 statedb.Finalise(true) 85 } else { 86 root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 87 } 88 *usedGas += result.UsedGas 89 90 receipt := types.NewReceipt(root, result.Failed(), *usedGas) 91 receipt.TxHash = tx.Hash() 92 receipt.GasUsed = result.UsedGas 93 94 if msg.To() == nil { 95 receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) 96 } 97 98 receipt.Logs = statedb.GetLogs(tx.Hash()) 99 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 100 101 return receipt, err 102 } 103 104 func ApplyTransactionEx(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, ops *types.PendingOps, 105 header *types.Header, tx *types.Transaction, usedGas *uint64, totalUsedMoney *big.Int, cfg vm.Config, cch CrossChainHelper, mining bool) (*types.Receipt, error) { 106 107 signer := types.MakeSigner(config, header.Number) 108 msg, err := tx.AsMessage(signer) 109 if err != nil { 110 return nil, err 111 } 112 113 if !neatAbi.IsNeatChainContractAddr(tx.To()) { 114 115 context := NewEVMContext(msg, header, bc, author) 116 117 vmenv := vm.NewEVM(context, statedb, config, cfg) 118 119 result, money, err := ApplyMessageEx(vmenv, msg, gp) 120 if err != nil { 121 return nil, err 122 } 123 124 var root []byte 125 if config.IsByzantium(header.Number) { 126 127 statedb.Finalise(true) 128 } else { 129 130 root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 131 } 132 *usedGas += result.UsedGas 133 totalUsedMoney.Add(totalUsedMoney, money) 134 135 receipt := types.NewReceipt(root, result.Failed(), *usedGas) 136 log.Debugf("ApplyTransactionEx,new receipt with (root,failed,*usedGas) = (%v,%v,%v)\n", root, result.Failed(), *usedGas) 137 receipt.TxHash = tx.Hash() 138 139 receipt.GasUsed = result.UsedGas 140 141 if msg.To() == nil { 142 receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) 143 } 144 145 receipt.Logs = statedb.GetLogs(tx.Hash()) 146 147 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 148 receipt.BlockHash = statedb.BlockHash() 149 receipt.BlockNumber = header.Number 150 receipt.TransactionIndex = uint(statedb.TxIndex()) 151 152 return receipt, err 153 154 } else { 155 156 data := tx.Data() 157 function, err := neatAbi.FunctionTypeFromId(data[:4]) 158 if err != nil { 159 return nil, err 160 } 161 log.Infof("ApplyTransactionEx() 0, Chain Function is %v", function.String()) 162 163 if config.IsMainChain() && !function.AllowInMainChain() { 164 return nil, ErrNotAllowedInMainChain 165 } else if !config.IsMainChain() && !function.AllowInSideChain() { 166 return nil, ErrNotAllowedInSideChain 167 } 168 169 from := msg.From() 170 171 if msg.CheckNonce() { 172 nonce := statedb.GetNonce(from) 173 if nonce < msg.Nonce() { 174 log.Info("ApplyTransactionEx() abort due to nonce too high") 175 return nil, ErrNonceTooHigh 176 } else if nonce > msg.Nonce() { 177 log.Info("ApplyTransactionEx() abort due to nonce too low") 178 return nil, ErrNonceTooLow 179 } 180 } 181 182 gasLimit := tx.Gas() 183 gasValue := new(big.Int).Mul(new(big.Int).SetUint64(gasLimit), tx.GasPrice()) 184 if statedb.GetBalance(from).Cmp(gasValue) < 0 { 185 return nil, fmt.Errorf("insufficient NEAT for gas (%x). Req %v, has %v", from.Bytes()[:4], gasValue, statedb.GetBalance(from)) 186 } 187 if err := gp.SubGas(gasLimit); err != nil { 188 return nil, err 189 } 190 statedb.SubBalance(from, gasValue) 191 192 gas := function.RequiredGas() 193 if gasLimit < gas { 194 return nil, vm.ErrOutOfGas 195 } 196 197 if statedb.GetBalance(from).Cmp(tx.Value()) == -1 { 198 return nil, fmt.Errorf("insufficient NEAT for tx amount (%x). Req %v, has %v", from.Bytes()[:4], tx.Value(), statedb.GetBalance(from)) 199 } 200 201 if applyCb := GetApplyCb(function); applyCb != nil { 202 if function.IsCrossChainType() { 203 if fn, ok := applyCb.(CrossChainApplyCb); ok { 204 cch.GetMutex().Lock() 205 err := fn(tx, statedb, ops, cch, mining) 206 cch.GetMutex().Unlock() 207 208 if err != nil { 209 return nil, err 210 } 211 } else { 212 panic("callback func is wrong, this should not happened, please check the code") 213 } 214 } else { 215 if fn, ok := applyCb.(NonCrossChainApplyCb); ok { 216 if err := fn(tx, statedb, bc, ops); err != nil { 217 return nil, err 218 } 219 } else { 220 panic("callback func is wrong, this should not happened, please check the code") 221 } 222 } 223 } 224 225 remainingGas := gasLimit - gas 226 remaining := new(big.Int).Mul(new(big.Int).SetUint64(remainingGas), tx.GasPrice()) 227 statedb.AddBalance(from, remaining) 228 gp.AddGas(remainingGas) 229 230 *usedGas += gas 231 totalUsedMoney.Add(totalUsedMoney, new(big.Int).Mul(new(big.Int).SetUint64(gas), tx.GasPrice())) 232 log.Infof("ApplyTransactionEx() 2, totalUsedMoney is %v\n", totalUsedMoney) 233 234 var root []byte 235 if config.IsByzantium(header.Number) { 236 statedb.Finalise(true) 237 } else { 238 root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 239 } 240 241 receipt := types.NewReceipt(root, false, *usedGas) 242 receipt.TxHash = tx.Hash() 243 receipt.GasUsed = gas 244 245 receipt.Logs = statedb.GetLogs(tx.Hash()) 246 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 247 receipt.BlockHash = statedb.BlockHash() 248 receipt.BlockNumber = header.Number 249 receipt.TransactionIndex = uint(statedb.TxIndex()) 250 251 statedb.SetNonce(msg.From(), statedb.GetNonce(msg.From())+1) 252 253 return receipt, nil 254 } 255 }