OSDN Git Service

opt code
authorshenao78 <shenao.78@163.com>
Wed, 30 Oct 2019 12:01:48 +0000 (20:01 +0800)
committershenao78 <shenao.78@163.com>
Wed, 30 Oct 2019 12:01:48 +0000 (20:01 +0800)
application/mov/mov_core.go
proposal/proposal.go
protocol/protocol.go
protocol/state/consensus_result.go

index 91f6248..729036f 100644 (file)
@@ -290,13 +290,13 @@ func (m *MovCore) DetachBlock(block *types.Block) error {
 }
 
 // BeforeProposalBlock return all transactions than can be matched, and the number of transactions cannot exceed the given capacity.
-func (m *MovCore) BeforeProposalBlock(capacity int, nodeProgram []byte) ([]*types.Tx, error) {
+func (m *MovCore) BeforeProposalBlock(nodeProgram []byte, gasLeft int64, calcGasUsed func(*types.Tx) (int64, error)) ([]*types.Tx, int64, error) {
        matchEngine := match.NewEngine(m.movStore, maxFeeRate, nodeProgram)
        tradePairMap := make(map[string]bool)
        tradePairIterator := database.NewTradePairIterator(m.movStore)
 
        var packagedTxs []*types.Tx
-       for len(packagedTxs) < capacity && tradePairIterator.HasNext() {
+       for gasLeft > 0 && tradePairIterator.HasNext() {
                tradePair := tradePairIterator.Next()
                if tradePairMap[tradePair.Key()] {
                        continue
@@ -304,16 +304,22 @@ func (m *MovCore) BeforeProposalBlock(capacity int, nodeProgram []byte) ([]*type
                tradePairMap[tradePair.Key()] = true
                tradePairMap[tradePair.Reverse().Key()] = true
 
-               for len(packagedTxs) < capacity && matchEngine.HasMatchedTx(tradePair, tradePair.Reverse()) {
+               for gasLeft > 0 && matchEngine.HasMatchedTx(tradePair, tradePair.Reverse()) {
                        matchedTx, err := matchEngine.NextMatchedTx(tradePair, tradePair.Reverse())
                        if err != nil {
-                               return nil, err
+                               return nil, 0, err
+                       }
+
+                       gasUsed, err := calcGasUsed(matchedTx)
+                       if err != nil {
+                               return nil, 0, err
                        }
 
                        packagedTxs = append(packagedTxs, matchedTx)
+                       gasLeft -= gasUsed
                }
        }
-       return packagedTxs, nil
+       return packagedTxs, gasLeft, nil
 }
 
 // IsDust block the transaction that are not generated by the match engine 
index 4dc59dc..24f48f1 100644 (file)
@@ -21,14 +21,24 @@ import (
 
 const (
        logModule = "mining"
-       maxBlockTxNum = 3000
 )
 
 // createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
 // based on the passed block height to the provided address.  When the address
 // is nil, the coinbase transaction will instead be redeemable by anyone.
-func createCoinbaseTx(accountManager *account.Manager, blockHeight uint64, rewards []state.CoinbaseReward) (tx *types.Tx, err error) {
-       arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(blockHeight, 10))...)
+func createCoinbaseTx(chain *protocol.Chain, accountManager *account.Manager, preBlockHeader *types.BlockHeader) (tx *types.Tx, err error) {
+       preBlockHash := preBlockHeader.Hash()
+       consensusResult, err := chain.GetConsensusResultByHash(&preBlockHash)
+       if err != nil {
+               return nil, err
+       }
+
+       rewards, err := consensusResult.GetCoinbaseRewards(preBlockHeader.Height)
+       if err != nil {
+               return nil, err
+       }
+
+       arbitrary := append([]byte{0x00}, []byte(strconv.FormatUint(preBlockHeader.Height + 1, 10))...)
        var script []byte
        if accountManager == nil {
                script, err = vmutil.DefaultCoinbaseProgram()
@@ -77,140 +87,193 @@ func createCoinbaseTx(accountManager *account.Manager, blockHeight uint64, rewar
 }
 
 // NewBlockTemplate returns a new block template that is ready to be solved
-func NewBlockTemplate(c *protocol.Chain, txPool *protocol.TxPool, accountManager *account.Manager, timestamp uint64) (b *types.Block, err error) {
+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
+       }
+
        view := state.NewUtxoViewpoint()
        txStatus := bc.NewTransactionStatus()
        if err := txStatus.SetStatus(0, false); err != nil {
                return nil, err
        }
-       txEntries := []*bc.Tx{nil}
-       gasUsed := uint64(0)
 
-       // get preblock info for generate next block
-       preBlockHeader := c.BestBlockHeader()
-       preBlockHash := preBlockHeader.Hash()
-       nextBlockHeight := preBlockHeader.Height + 1
+       gasLeft, err := applyTransactionFromPool(chain, view, block, txStatus, int64(consensus.ActiveNetParams.MaxBlockGas))
+       if err != nil {
+               return nil, err
+       }
+       
+       if err := applyTransactionFromSubProtocol(chain, view, block, txStatus, accountManager, gasLeft); err != nil {
+               return nil, err
+       }
 
-       b = &types.Block{
+       var txEntries []*bc.Tx
+       for _, tx := range block.Transactions {
+               txEntries = append(txEntries, tx.Tx)
+       }
+
+       block.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = types.TxMerkleRoot(txEntries)
+       if err != nil {
+               return nil, err
+       }
+
+       block.BlockHeader.BlockCommitment.TransactionStatusHash, err = types.TxStatusMerkleRoot(txStatus.VerifyStatus)
+
+       _, err = chain.SignBlock(block)
+       return block, err
+}
+
+func createBasicBlock(chain *protocol.Chain, accountManager *account.Manager, timestamp uint64) (*types.Block, error) {
+       preBlockHeader := chain.BestBlockHeader()
+       coinbaseTx, err := createCoinbaseTx(chain, accountManager, preBlockHeader)
+       if err != nil {
+               return nil, errors.Wrap(err, "fail on create coinbase tx")
+       }
+
+       return &types.Block{
                BlockHeader: types.BlockHeader{
                        Version:           1,
-                       Height:            nextBlockHeight,
-                       PreviousBlockHash: preBlockHash,
+                       Height:            preBlockHeader.Height + 1,
+                       PreviousBlockHash: preBlockHeader.Hash(),
                        Timestamp:         timestamp,
                        BlockCommitment:   types.BlockCommitment{},
                        BlockWitness:      types.BlockWitness{Witness: make([][]byte, consensus.ActiveNetParams.NumOfConsensusNode)},
                },
-       }
-       bcBlock := &bc.Block{BlockHeader: &bc.BlockHeader{Height: nextBlockHeight}}
-       b.Transactions = []*types.Tx{nil}
+               Transactions: []*types.Tx{coinbaseTx},
+       }, 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 {
+                       blkGenSkipTxForErr(chain.GetTxPool(), &result.tx.ID, result.err)
+                       continue
+               }
 
-       txs := txPool.GetTransactions()
-       sort.Sort(byTime(txs))
+               if err := txStatus.SetStatus(len(block.Transactions), result.gasOnly); err != nil {
+                       return 0, err
+               }
 
-       entriesTxs := []*bc.Tx{}
-       for _, txDesc := range txs {
-               entriesTxs = append(entriesTxs, txDesc.Tx.Tx)
+               block.Transactions = append(block.Transactions, result.tx)
        }
+       return gasLeft, nil
+}
 
-       subProtocolTxs, err := packageSubProtocolTxs(c, accountManager, maxBlockTxNum - len(entriesTxs))
+func applyTransactionFromSubProtocol(chain *protocol.Chain, view *state.UtxoViewpoint, block *types.Block, txStatus *bc.TransactionStatus, accountManager *account.Manager, gasLeft int64) error {
+       txs, err := getTxsFromSubProtocols(chain, accountManager, gasLeft)
        if err != nil {
-               return nil, err
+               return err
+       }
+
+       results, gasLeft := preValidateTxs(txs, chain, view, gasLeft)
+       for _, result := range results {
+               if result.err != nil {
+                       continue
+               }
+
+               if err := txStatus.SetStatus(len(block.Transactions), result.gasOnly); err != nil {
+                       return err
+               }
+
+               block.Transactions = append(block.Transactions, result.tx)
        }
-       for _, tx := range subProtocolTxs {
-               entriesTxs = append(entriesTxs, tx.Tx)
+       return nil
+}
+
+type validateTxResult struct {
+       tx      *types.Tx
+       gasOnly bool
+       err     error
+}
+
+func preValidateTxs(txs []*types.Tx, chain *protocol.Chain, view *state.UtxoViewpoint, gasLeft int64) ([]*validateTxResult, int64) {
+       var results []*validateTxResult
+
+       bcBlock := &bc.Block{BlockHeader: &bc.BlockHeader{Height: chain.BestBlockHeight() + 1}}
+       bcTxs := make([]*bc.Tx, len(txs))
+       for i, tx := range txs {
+               bcTxs[i] = tx.Tx
        }
 
-       validateResults := validation.ValidateTxs(entriesTxs, bcBlock)
-       for i, validateResult := range validateResults {
-               txDesc := txs[i]
-               tx := txDesc.Tx.Tx
+       validateResults := validation.ValidateTxs(bcTxs, bcBlock)
+       for i := 0; i < len(validateResults) && gasLeft > 0; i++ {
                gasOnlyTx := false
-
-               gasStatus := validateResult.GetGasState()
-               if validateResult.GetError() != nil {
+               gasStatus := validateResults[i].GetGasState()
+               if err := validateResults[i].GetError(); err != nil {
                        if !gasStatus.GasValid {
-                               blkGenSkipTxForErr(txPool, &tx.ID, err)
+                               results = append(results, &validateTxResult{tx: txs[i], err: err})
                                continue
                        }
                        gasOnlyTx = true
                }
 
-               if err := c.GetTransactionsUtxo(view, []*bc.Tx{tx}); err != nil {
-                       blkGenSkipTxForErr(txPool, &tx.ID, err)
+               if err := chain.GetTransactionsUtxo(view, []*bc.Tx{bcTxs[i]}); err != nil {
+                       results = append(results, &validateTxResult{tx: txs[i], err: err})
                        continue
                }
 
-               if gasUsed+uint64(gasStatus.GasUsed) > consensus.ActiveNetParams.MaxBlockGas {
+               if gasLeft-gasStatus.GasUsed < 0 {
                        break
                }
 
-               if err := view.ApplyTransaction(bcBlock, tx, gasOnlyTx); err != nil {
-                       blkGenSkipTxForErr(txPool, &tx.ID, err)
+               if err := view.ApplyTransaction(bcBlock, bcTxs[i], gasOnlyTx); err != nil {
+                       results = append(results, &validateTxResult{tx: txs[i], err: err})
                        continue
                }
 
-               if err := txStatus.SetStatus(len(b.Transactions), gasOnlyTx); err != nil {
-                       return nil, err
-               }
-
-               b.Transactions = append(b.Transactions, txDesc.Tx)
-               txEntries = append(txEntries, tx)
-               gasUsed += uint64(gasStatus.GasUsed)
-               if gasUsed == consensus.ActiveNetParams.MaxBlockGas {
-                       break
-               }
-
-       }
-
-       consensusResult, err := c.GetConsensusResultByHash(&preBlockHash)
-       if err != nil {
-               return nil, err
-       }
-
-       rewards, err := consensusResult.GetCoinbaseRewards(preBlockHeader.Height)
-       if err != nil {
-               return nil, err
+               results = append(results, &validateTxResult{tx: txs[i], gasOnly: gasOnlyTx})
+               gasLeft -= gasStatus.GasUsed
        }
+       return results, gasLeft
+}
 
-       // create coinbase transaction
-       b.Transactions[0], err = createCoinbaseTx(accountManager, nextBlockHeight, rewards)
-       if err != nil {
-               return nil, errors.Wrap(err, "fail on createCoinbaseTx")
-       }
+func getAllTxsFromPool(txPool *protocol.TxPool) []*types.Tx {
+       txDescList := txPool.GetTransactions()
+       sort.Sort(byTime(txDescList))
 
-       txEntries[0] = b.Transactions[0].Tx
-       b.BlockHeader.BlockCommitment.TransactionsMerkleRoot, err = types.TxMerkleRoot(txEntries)
-       if err != nil {
-               return nil, err
+       poolTxs := make([]*types.Tx, len(txDescList))
+       for i, txDesc := range txDescList {
+               poolTxs[i] = txDesc.Tx
        }
-
-       b.BlockHeader.BlockCommitment.TransactionStatusHash, err = types.TxStatusMerkleRoot(txStatus.VerifyStatus)
-
-       _, err = c.SignBlock(b)
-       return b, err
+       return poolTxs
 }
 
-func packageSubProtocolTxs(chain *protocol.Chain, accountManager *account.Manager, capacity int) ([]*types.Tx, error) {
-       var packageTxs []*types.Tx
+func getTxsFromSubProtocols(chain *protocol.Chain, accountManager *account.Manager, gasLeft int64) ([]*types.Tx, error) {
        cp, err := accountManager.GetCoinbaseControlProgram()
        if err != nil {
                return nil, err
        }
 
+       var result []*types.Tx
+       var subTxs []*types.Tx
        for i, p := range chain.SubProtocols() {
-               if capacity <= 0 {
+               if gasLeft <= 0 {
                        break
                }
 
-               txs, err := p.BeforeProposalBlock(capacity, cp)
+               subTxs, gasLeft, err = p.BeforeProposalBlock(cp, gasLeft, calcGasUsed(&bc.Block{BlockHeader: &bc.BlockHeader{Height: chain.BestBlockHeight() + 1}}))
                if err != nil {
                        log.WithFields(log.Fields{"module": logModule, "index": i, "error": err}).Error("failed on sub protocol txs package")
                        continue
                }
-               packageTxs = append(packageTxs, txs...)
-               capacity = capacity - len(txs)
+
+               result = append(result, subTxs...)
+       }
+       return result, nil
+}
+
+func calcGasUsed(bcBlock *bc.Block) func (*types.Tx) (int64, error) {
+       return func (tx *types.Tx) (int64, error) {
+               gasState, err := validation.ValidateTx(tx.Tx, bcBlock)
+               if err != nil {
+                       return 0, err
+               }
+
+               return gasState.GasUsed, nil
        }
-       return packageTxs, nil
 }
 
 func blkGenSkipTxForErr(txPool *protocol.TxPool, txHash *bc.Hash, err error) {
index 59880a7..4160a32 100644 (file)
@@ -21,7 +21,7 @@ const (
 
 type Protocoler interface {
        Name() string
-       BeforeProposalBlock(capacity int, nodeProgram []byte) ([]*types.Tx, error)
+       BeforeProposalBlock(nodeProgram []byte, gasLeft int64, calcGasUsed func(*types.Tx) (int64, error)) ([]*types.Tx, int64, error)
        ChainStatus() (uint64, *bc.Hash, error)
        ValidateBlock(block *types.Block, verifyResults []*bc.TxVerifyResult) error
        ValidateTxs(txs []*types.Tx, verifyResults []*bc.TxVerifyResult) error
index 9fd571b..cff2cfc 100644 (file)
@@ -329,8 +329,8 @@ func (c *ConsensusResult) GetCoinbaseRewards(blockHeight uint64) ([]CoinbaseRewa
 func federationNodes() map[string]*ConsensusNode {
        consensusResult := map[string]*ConsensusNode{}
        for i, xpub := range config.CommonConfig.Federation.Xpubs {
-               derivedXPub := xpub.Derive(fedConsensusPath)
-               consensusResult[derivedXPub.String()] = &ConsensusNode{XPub: derivedXPub, VoteNum: 0, Order: uint64(i)}
+               //derivedXPub := xpub.Derive(fedConsensusPath)
+               consensusResult[xpub.String()] = &ConsensusNode{XPub: xpub, VoteNum: 0, Order: uint64(i)}
        }
        return consensusResult
 }