github.com/Gessiux/neatchain@v1.3.1/chain/core/state_processor1.go (about) 1 package core 2 3 import ( 4 "fmt" 5 "math/big" 6 7 "github.com/Gessiux/neatchain/chain/core/state" 8 "github.com/Gessiux/neatchain/chain/core/types" 9 "github.com/Gessiux/neatchain/chain/core/vm" 10 "github.com/Gessiux/neatchain/chain/log" 11 neatAbi "github.com/Gessiux/neatchain/neatabi/abi" 12 "github.com/Gessiux/neatchain/params" 13 "github.com/Gessiux/neatchain/utilities/common" 14 "github.com/Gessiux/neatchain/utilities/crypto" 15 ) 16 17 // ApplyTransactionEx attempts to apply a transaction to the given state database 18 // and uses the input parameters for its environment. It returns the receipt 19 // for the transaction, gas used and an error if the transaction failed, 20 // indicating the block was invalid. 21 func ApplyTransactionEx(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, ops *types.PendingOps, 22 header *types.Header, tx *types.Transaction, usedGas *uint64, totalUsedMoney *big.Int, cfg vm.Config, cch CrossChainHelper, mining bool) (*types.Receipt, uint64, error) { 23 24 signer := types.MakeSigner(config, header.Number) 25 msg, err := tx.AsMessage(signer) 26 if err != nil { 27 return nil, 0, err 28 } 29 30 if !neatAbi.IsNeatChainContractAddr(tx.To()) { 31 32 //log.Debugf("ApplyTransactionEx 1\n") 33 34 // Create a new context to be used in the EVM environment 35 context := NewEVMContext(msg, header, bc, author) 36 37 //log.Debugf("ApplyTransactionEx 2\n") 38 39 // Create a new environment which holds all relevant information 40 // about the transaction and calling mechanisms. 41 vmenv := vm.NewEVM(context, statedb, config, cfg) 42 // Apply the transaction to the current state (included in the env) 43 _, gas, money, failed, err := ApplyMessageEx(vmenv, msg, gp) 44 if err != nil { 45 return nil, 0, err 46 } 47 48 //log.Debugf("ApplyTransactionEx 3\n") 49 // Update the state with pending changes 50 var root []byte 51 if config.IsByzantium(header.Number) { 52 //log.Debugf("ApplyTransactionEx(), is byzantium\n") 53 statedb.Finalise(true) 54 } else { 55 //log.Debugf("ApplyTransactionEx(), is not byzantium\n") 56 root = statedb.IntermediateRoot(false).Bytes() 57 } 58 *usedGas += gas 59 totalUsedMoney.Add(totalUsedMoney, money) 60 61 // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx 62 // based on the eip phase, we're passing wether the root touch-delete accounts. 63 receipt := types.NewReceipt(root, failed, *usedGas) 64 log.Debugf("ApplyTransactionEx,new receipt with (root,failed,*usedGas) = (%v,%v,%v)\n", root, failed, *usedGas) 65 receipt.TxHash = tx.Hash() 66 //log.Debugf("ApplyTransactionEx,new receipt with txhash %v\n", receipt.TxHash) 67 receipt.GasUsed = gas 68 //log.Debugf("ApplyTransactionEx,new receipt with gas %v\n", receipt.GasUsed) 69 // if the transaction created a contract, store the creation address in the receipt. 70 if msg.To() == nil { 71 receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) 72 } 73 // Set the receipt logs and create a bloom for filtering 74 receipt.Logs = statedb.GetLogs(tx.Hash()) 75 //log.Debugf("ApplyTransactionEx,new receipt with receipt.Logs %v\n", receipt.Logs) 76 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 77 receipt.BlockHash = statedb.BlockHash() 78 receipt.BlockNumber = header.Number 79 receipt.TransactionIndex = uint(statedb.TxIndex()) 80 //log.Debugf("ApplyTransactionEx,new receipt with receipt.Bloom %v\n", receipt.Bloom) 81 //log.Debugf("ApplyTransactionEx 4\n") 82 return receipt, gas, err 83 84 } else { 85 86 // the first 4 bytes is the function identifier 87 data := tx.Data() 88 function, err := neatAbi.FunctionTypeFromId(data[:4]) 89 if err != nil { 90 return nil, 0, err 91 } 92 log.Infof("ApplyTransactionEx() 0, Chain Function is %v", function.String()) 93 94 // check Function main/side flag 95 if config.IsMainChain() && !function.AllowInMainChain() { 96 return nil, 0, ErrNotAllowedInMainChain 97 } else if !config.IsMainChain() && !function.AllowInSideChain() { 98 return nil, 0, ErrNotAllowedInSideChain 99 } 100 101 from := msg.From() 102 // Make sure this transaction's nonce is correct 103 if msg.CheckNonce() { 104 nonce := statedb.GetNonce(from) 105 if nonce < msg.Nonce() { 106 log.Info("ApplyTransactionEx() abort due to nonce too high") 107 return nil, 0, ErrNonceTooHigh 108 } else if nonce > msg.Nonce() { 109 log.Info("ApplyTransactionEx() abort due to nonce too low") 110 return nil, 0, ErrNonceTooLow 111 } 112 } 113 114 // pre-buy gas according to the gas limit 115 gasLimit := tx.Gas() 116 gasValue := new(big.Int).Mul(new(big.Int).SetUint64(gasLimit), tx.GasPrice()) 117 if statedb.GetBalance(from).Cmp(gasValue) < 0 { 118 return nil, 0, fmt.Errorf("insufficient NEAT for gas (%x). Req %v, has %v", from.Bytes()[:4], gasValue, statedb.GetBalance(from)) 119 } 120 if err := gp.SubGas(gasLimit); err != nil { 121 return nil, 0, err 122 } 123 statedb.SubBalance(from, gasValue) 124 //log.Infof("ApplyTransactionEx() 1, gas is %v, gasPrice is %v, gasValue is %v\n", gasLimit, tx.GasPrice(), gasValue) 125 126 // use gas 127 gas := function.RequiredGas() 128 if gasLimit < gas { 129 return nil, 0, vm.ErrOutOfGas 130 } 131 132 // Check Tx Amount 133 if statedb.GetBalance(from).Cmp(tx.Value()) == -1 { 134 return nil, 0, fmt.Errorf("insufficient NEAT for tx amount (%x). Req %v, has %v", from.Bytes()[:4], tx.Value(), statedb.GetBalance(from)) 135 } 136 137 if applyCb := GetApplyCb(function); applyCb != nil { 138 if function.IsCrossChainType() { 139 if fn, ok := applyCb.(CrossChainApplyCb); ok { 140 cch.GetMutex().Lock() 141 err := fn(tx, statedb, ops, cch, mining) 142 cch.GetMutex().Unlock() 143 144 if err != nil { 145 return nil, 0, err 146 } 147 } else { 148 panic("callback func is wrong, this should not happened, please check the code") 149 } 150 } else { 151 if fn, ok := applyCb.(NonCrossChainApplyCb); ok { 152 if err := fn(tx, statedb, bc, ops); err != nil { 153 return nil, 0, err 154 } 155 } else { 156 panic("callback func is wrong, this should not happened, please check the code") 157 } 158 } 159 } 160 161 // refund gas 162 remainingGas := gasLimit - gas 163 remaining := new(big.Int).Mul(new(big.Int).SetUint64(remainingGas), tx.GasPrice()) 164 statedb.AddBalance(from, remaining) 165 gp.AddGas(remainingGas) 166 167 *usedGas += gas 168 totalUsedMoney.Add(totalUsedMoney, new(big.Int).Mul(new(big.Int).SetUint64(gas), tx.GasPrice())) 169 log.Infof("ApplyTransactionEx() 2, totalUsedMoney is %v\n", totalUsedMoney) 170 171 // Update the state with pending changes 172 var root []byte 173 if config.IsByzantium(header.Number) { 174 statedb.Finalise(true) 175 } else { 176 root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 177 } 178 receipt := types.NewReceipt(root, false, *usedGas) 179 receipt.TxHash = tx.Hash() 180 receipt.GasUsed = gas 181 182 // Set the receipt logs and create a bloom for filtering 183 receipt.Logs = statedb.GetLogs(tx.Hash()) 184 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 185 receipt.BlockHash = statedb.BlockHash() 186 receipt.BlockNumber = header.Number 187 receipt.TransactionIndex = uint(statedb.TxIndex()) 188 189 statedb.SetNonce(msg.From(), statedb.GetNonce(msg.From())+1) 190 //log.Infof("ApplyTransactionEx() 3, totalUsedMoney is %v\n", totalUsedMoney) 191 192 return receipt, 0, nil 193 } 194 }