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  }