From 3c4421ccea81457046e3ff00e46fa9f6692204de Mon Sep 17 00:00:00 2001 From: Paladz Date: Wed, 26 Jun 2019 20:46:51 +0800 Subject: [PATCH] speed up valiate tx (#226) --- protocol/validation/block.go | 14 +++++----- protocol/validation/tx.go | 62 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/protocol/validation/block.go b/protocol/validation/block.go index b226a574..8ea143c0 100644 --- a/protocol/validation/block.go +++ b/protocol/validation/block.go @@ -88,17 +88,17 @@ func ValidateBlock(b *bc.Block, parent *types.BlockHeader) error { coinbaseAmount := consensus.BlockSubsidy(b.BlockHeader.Height) b.TransactionStatus = bc.NewTransactionStatus() - for i, tx := range b.Transactions { - gasStatus, err := ValidateTx(tx, b) - if !gasStatus.GasValid { - return errors.Wrapf(err, "validate of transaction %d of %d", i, len(b.Transactions)) + validateResults := ValidateTxs(b.Transactions, b) + for i, validateResult := range validateResults { + if !validateResult.gasStatus.GasValid { + return errors.Wrapf(validateResult.err, "validate of transaction %d of %d", i, len(b.Transactions)) } - if err := b.TransactionStatus.SetStatus(i, err != nil); err != nil { + if err := b.TransactionStatus.SetStatus(i, validateResult.err != nil); err != nil { return err } - coinbaseAmount += gasStatus.BTMValue - if blockGasSum += uint64(gasStatus.GasUsed); blockGasSum > consensus.MaxBlockGas { + coinbaseAmount += validateResult.gasStatus.BTMValue + if blockGasSum += uint64(validateResult.gasStatus.GasUsed); blockGasSum > consensus.MaxBlockGas { return errOverBlockLimit } } diff --git a/protocol/validation/tx.go b/protocol/validation/tx.go index 0d257514..1baf6c86 100644 --- a/protocol/validation/tx.go +++ b/protocol/validation/tx.go @@ -3,6 +3,7 @@ package validation import ( "fmt" "math" + "sync" "github.com/vapor/config" "github.com/vapor/consensus" @@ -12,7 +13,10 @@ import ( "github.com/vapor/protocol/vm" ) -const ruleAA = 142500 +const ( + validateWorkerNum = 32 + ruleAA = 142500 +) // validate transaction error var ( @@ -570,3 +574,59 @@ func ValidateTx(tx *bc.Tx, block *bc.Block) (*GasState, error) { } return vs.gasStatus, checkValid(vs, tx.TxHeader) } + +type validateTxWork struct { + i int + tx *bc.Tx + block *bc.Block +} + +type validateTxResult struct { + i int + gasStatus *GasState + err error +} + +func validateTxWorker(workCh chan *validateTxWork, resultCh chan *validateTxResult, closeCh chan struct{}, wg *sync.WaitGroup) { + for { + select { + case work := <-workCh: + gasStatus, err := ValidateTx(work.tx, work.block) + resultCh <- &validateTxResult{i: work.i, gasStatus: gasStatus, err: err} + case <-closeCh: + wg.Done() + return + } + } +} + +func ValidateTxs(txs []*bc.Tx, block *bc.Block) []*validateTxResult { + txSize := len(txs) + //init the goroutine validate worker + var wg sync.WaitGroup + workCh := make(chan *validateTxWork, txSize) + resultCh := make(chan *validateTxResult, txSize) + closeCh := make(chan struct{}) + for i := 0; i <= validateWorkerNum && i < txSize; i++ { + wg.Add(1) + go validateTxWorker(workCh, resultCh, closeCh, &wg) + } + + //sent the works + for i, tx := range txs { + workCh <- &validateTxWork{i: i, tx: tx, block: block} + } + + //collect validate results + results := make([]*validateTxResult, txSize) + for i := 0; i < txSize; i++ { + result := <-resultCh + results[result.i] = result + } + + close(closeCh) + wg.Wait() + close(workCh) + close(resultCh) + return results +} -- 2.11.0