// ValidateTxs validate the trade transaction.
func (m *MovCore) ValidateTxs(txs []*types.Tx, verifyResults []*bc.TxVerifyResult) error {
for i, tx := range txs {
- if common.IsMatchedTx(tx) {
- if err := validateMatchedTx(tx, verifyResults[i]); err != nil {
- return err
- }
+ if err := m.ValidateTx(tx, verifyResults[i]); err != nil {
+ return err
}
+ }
+ return nil
+}
- if common.IsCancelOrderTx(tx) {
- if err := validateCancelOrderTx(tx, verifyResults[i]); err != nil {
- return err
- }
+func (m *MovCore) ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult) error {
+ if common.IsMatchedTx(tx) {
+ if err := validateMatchedTx(tx, verifyResult); err != nil {
+ return err
}
+ }
- for _, output := range tx.Outputs {
- if !segwit.IsP2WMCScript(output.ControlProgram()) {
- continue
- }
- if verifyResults[i].StatusFail {
- return errStatusFailMustFalse
- }
+ if common.IsCancelOrderTx(tx) {
+ if err := validateCancelOrderTx(tx, verifyResult); err != nil {
+ return err
+ }
+ }
- if err := validateMagneticContractArgs(output.AssetAmount().Amount, output.ControlProgram()); err != nil {
- return err
- }
+ for _, output := range tx.Outputs {
+ if !segwit.IsP2WMCScript(output.ControlProgram()) {
+ continue
+ }
+ if verifyResult.StatusFail {
+ return errStatusFailMustFalse
+ }
+
+ if err := validateMagneticContractArgs(output.AssetAmount().Amount, output.ControlProgram()); err != nil {
+ return err
}
}
return nil
if block.Height < m.startBlockHeight {
return nil
}
+
if block.Height == m.startBlockHeight {
blockHash := block.Hash()
if err := m.movStore.InitDBState(block.Height, &blockHash); err != nil {
if block.Height <= m.startBlockHeight {
return nil
}
+
deleteOrders, addOrders, err := applyTransactions(block.Transactions)
if err != nil {
return err
// NewBlockTemplate returns a new block template that is ready to be solved
func NewBlockTemplate(chain *protocol.Chain, txPool *protocol.TxPool, accountManager *account.Manager, timestamp uint64) (*types.Block, error) {
- block, err := createBasicBlock(chain, accountManager, timestamp)
- if err != nil {
- return nil, err
- }
+ block := createBasicBlock(chain, timestamp)
view := state.NewUtxoViewpoint()
txStatus := bc.NewTransactionStatus()
- if err := txStatus.SetStatus(0, false); err != nil {
+
+ gasLeft, err := applyCoinbaseTransaction(chain, block, txStatus, accountManager, int64(consensus.ActiveNetParams.MaxBlockGas))
+ if err != nil {
return nil, err
}
- gasLeft, err := applyTransactionFromPool(chain, view, block, txStatus, int64(consensus.ActiveNetParams.MaxBlockGas))
+ gasLeft, err = applyTransactionFromPool(chain, view, block, txStatus, gasLeft)
if err != nil {
return nil, err
}
return block, err
}
-func createBasicBlock(chain *protocol.Chain, accountManager *account.Manager, timestamp uint64) (*types.Block, error) {
+func createBasicBlock(chain *protocol.Chain, timestamp uint64) *types.Block {
preBlockHeader := chain.BestBlockHeader()
- coinbaseTx, err := createCoinbaseTx(accountManager, chain, preBlockHeader)
- if err != nil {
- return nil, errors.Wrap(err, "fail on create coinbase tx")
- }
-
return &types.Block{
BlockHeader: types.BlockHeader{
Version: 1,
BlockCommitment: types.BlockCommitment{},
BlockWitness: types.BlockWitness{Witness: make([][]byte, consensus.ActiveNetParams.NumOfConsensusNode)},
},
- Transactions: []*types.Tx{coinbaseTx},
- }, nil
+ }
+}
+
+func applyCoinbaseTransaction(chain *protocol.Chain, block *types.Block, txStatus *bc.TransactionStatus, accountManager *account.Manager, gasLeft int64) (int64, error) {
+ coinbaseTx, err := createCoinbaseTx(accountManager, chain, chain.BestBlockHeader())
+ if err != nil {
+ return 0, errors.Wrap(err, "fail on create coinbase tx")
+ }
+
+ gasState, err := validation.ValidateTx(coinbaseTx.Tx, &bc.Block{BlockHeader: &bc.BlockHeader{Height: chain.BestBlockHeight() + 1}})
+ if err != nil {
+ return 0, err
+ }
+
+ block.Transactions = append(block.Transactions, coinbaseTx)
+ if err := txStatus.SetStatus(0, false); err != nil {
+ return 0, err
+ }
+
+ return gasLeft - gasState.GasUsed, nil
}
+
func applyTransactionFromPool(chain *protocol.Chain, view *state.UtxoViewpoint, block *types.Block, txStatus *bc.TransactionStatus, gasLeft int64) (int64, error) {
poolTxs := getAllTxsFromPool(chain.GetTxPool())
results, gasLeft := preValidateTxs(poolTxs, chain, view, gasLeft)
for _, result := range results {
- if result.err != nil {
+ if result.err != nil && !result.gasOnly {
blkGenSkipTxForErr(chain.GetTxPool(), &result.tx.ID, result.err)
continue
}
results, gasLeft := preValidateTxs(txs, chain, view, gasLeft)
for _, result := range results {
- if result.err != nil && result.gasOnly {
- continue
+ if result.err != nil {
+ return err
}
if err := txStatus.SetStatus(len(block.Transactions), result.gasOnly); err != nil {
validateResults := validation.ValidateTxs(bcTxs, bcBlock)
for i := 0; i < len(validateResults) && gasLeft > 0; i++ {
gasOnlyTx := false
+ var err error
gasStatus := validateResults[i].GetGasState()
- if err := validateResults[i].GetError(); err != nil {
+ if err = validateResults[i].GetError(); err != nil {
if !gasStatus.GasValid {
results = append(results, &validateTxResult{tx: txs[i], err: err})
continue
gasOnlyTx = true
}
- if err := chain.GetTransactionsUtxo(view, []*bc.Tx{bcTxs[i]}); err != nil {
+ if err = chain.GetTransactionsUtxo(view, []*bc.Tx{bcTxs[i]}); err != nil {
results = append(results, &validateTxResult{tx: txs[i], err: err})
continue
}
break
}
- if err := view.ApplyTransaction(bcBlock, bcTxs[i], gasOnlyTx); err != nil {
+ if err = view.ApplyTransaction(bcBlock, bcTxs[i], gasOnlyTx); err != nil {
results = append(results, &validateTxResult{tx: txs[i], err: err})
continue
}
- results = append(results, &validateTxResult{tx: txs[i], gasOnly: gasOnlyTx})
+ for _, subProtocol := range chain.SubProtocols() {
+ verifyResult := &bc.TxVerifyResult{StatusFail: validateResults[i].GetError() != nil}
+ if err = subProtocol.ValidateTx(txs[i], verifyResult); err != nil {
+ results = append(results, &validateTxResult{tx: txs[i], err: err})
+ break
+ }
+ }
+
+ results = append(results, &validateTxResult{tx: txs[i], gasOnly: gasOnlyTx, err: err})
gasLeft -= gasStatus.GasUsed
}
return results, gasLeft
ChainStatus() (uint64, *bc.Hash, error)
ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error
ValidateTxs(txs []*types.Tx, verifyResults []*bc.TxVerifyResult) error
+ ValidateTx(tx *types.Tx, verifyResult *bc.TxVerifyResult) error
ApplyBlock(block *types.Block) error
DetachBlock(block *types.Block) error
}
return errors.Wrap(err, subProtocol.Name(), "sub protocol detach block err")
}
- protocolHeight, protocolHash, err = subProtocol.ChainStatus()
- if err != nil {
- return errors.Wrap(err, "failed on get sub protocol status")
- }
+ protocolHeight, protocolHash = block.Height -1, &block.PreviousBlockHash
}
for height := protocolHeight + 1; height <= c.BestBlockHeight(); height++ {
return errors.Wrap(err, subProtocol.Name(), "sub protocol apply block err")
}
- protocolHeight, protocolHash, err = subProtocol.ChainStatus()
- if err != nil {
- return errors.Wrap(err, "failed on get sub protocol status")
- }
+ blockHash := block.Hash()
+ protocolHeight, protocolHash = block.Height, &blockHash
if *protocolHash != block.Hash() {
return errors.Wrap(errors.New("sub protocol status sync err"), subProtocol.Name())