core: reuse mempool from AddBlock() for bc.isTxStillRelevant()
It's already there most of the time and creating another slice is just a waste of time. Checking for presence with map is also a little faster.
This commit is contained in:
parent
26339c75dc
commit
7310e748e3
1 changed files with 28 additions and 34 deletions
|
@ -4,7 +4,6 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sort"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
@ -200,7 +199,7 @@ func (bc *Blockchain) init() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return bc.storeBlock(genesisBlock)
|
return bc.storeBlock(genesisBlock, nil)
|
||||||
}
|
}
|
||||||
if ver != version {
|
if ver != version {
|
||||||
return fmt.Errorf("storage version mismatch betweeen %s and %s", version, ver)
|
return fmt.Errorf("storage version mismatch betweeen %s and %s", version, ver)
|
||||||
|
@ -413,6 +412,7 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
|
||||||
bc.addLock.Lock()
|
bc.addLock.Lock()
|
||||||
defer bc.addLock.Unlock()
|
defer bc.addLock.Unlock()
|
||||||
|
|
||||||
|
var mp *mempool.Pool
|
||||||
expectedHeight := bc.BlockHeight() + 1
|
expectedHeight := bc.BlockHeight() + 1
|
||||||
if expectedHeight != block.Index {
|
if expectedHeight != block.Index {
|
||||||
return fmt.Errorf("expected %d, got %d: %w", expectedHeight, block.Index, ErrInvalidBlockIndex)
|
return fmt.Errorf("expected %d, got %d: %w", expectedHeight, block.Index, ErrInvalidBlockIndex)
|
||||||
|
@ -430,28 +430,26 @@ func (bc *Blockchain) AddBlock(block *block.Block) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("block %s is invalid: %w", block.Hash().StringLE(), err)
|
return fmt.Errorf("block %s is invalid: %w", block.Hash().StringLE(), err)
|
||||||
}
|
}
|
||||||
if bc.config.VerifyTransactions {
|
mp = mempool.New(len(block.Transactions))
|
||||||
var mp = mempool.New(len(block.Transactions))
|
for _, tx := range block.Transactions {
|
||||||
for _, tx := range block.Transactions {
|
var err error
|
||||||
var err error
|
// Transactions are verified before adding them
|
||||||
// Transactions are verified before adding them
|
// into the pool, so there is no point in doing
|
||||||
// into the pool, so there is no point in doing
|
// it again even if we're verifying in-block transactions.
|
||||||
// it again even if we're verifying in-block transactions.
|
if bc.memPool.ContainsKey(tx.Hash()) {
|
||||||
if bc.memPool.ContainsKey(tx.Hash()) {
|
err = mp.Add(tx, bc)
|
||||||
err = mp.Add(tx, bc)
|
if err == nil {
|
||||||
if err == nil {
|
continue
|
||||||
continue
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = bc.verifyAndPoolTx(tx, mp)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("transaction %s failed to verify: %w", tx.Hash().StringLE(), err)
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
err = bc.verifyAndPoolTx(tx, mp)
|
||||||
|
}
|
||||||
|
if err != nil && bc.config.VerifyTransactions {
|
||||||
|
return fmt.Errorf("transaction %s failed to verify: %w", tx.Hash().StringLE(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bc.storeBlock(block)
|
return bc.storeBlock(block, mp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddHeaders processes the given headers and add them to the
|
// AddHeaders processes the given headers and add them to the
|
||||||
|
@ -569,7 +567,7 @@ func (bc *Blockchain) GetStateRoot(height uint32) (*state.MPTRootState, error) {
|
||||||
// storeBlock performs chain update using the block given, it executes all
|
// storeBlock performs chain update using the block given, it executes all
|
||||||
// transactions with all appropriate side-effects and updates Blockchain state.
|
// transactions with all appropriate side-effects and updates Blockchain state.
|
||||||
// This is the only way to change Blockchain state.
|
// This is the only way to change Blockchain state.
|
||||||
func (bc *Blockchain) storeBlock(block *block.Block) error {
|
func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error {
|
||||||
cache := dao.NewCached(bc.dao)
|
cache := dao.NewCached(bc.dao)
|
||||||
writeBuf := io.NewBufBinWriter()
|
writeBuf := io.NewBufBinWriter()
|
||||||
appExecResults := make([]*state.AppExecResult, 0, 1+len(block.Transactions))
|
appExecResults := make([]*state.AppExecResult, 0, 1+len(block.Transactions))
|
||||||
|
@ -612,8 +610,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
||||||
writeBuf.Reset()
|
writeBuf.Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
var txHashes = make([]util.Uint256, len(block.Transactions))
|
for _, tx := range block.Transactions {
|
||||||
for i, tx := range block.Transactions {
|
|
||||||
if err := cache.StoreAsTransaction(tx, block.Index, writeBuf); err != nil {
|
if err := cache.StoreAsTransaction(tx, block.Index, writeBuf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -654,11 +651,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
||||||
return fmt.Errorf("failed to store tx exec result: %w", err)
|
return fmt.Errorf("failed to store tx exec result: %w", err)
|
||||||
}
|
}
|
||||||
writeBuf.Reset()
|
writeBuf.Reset()
|
||||||
txHashes[i] = tx.Hash()
|
|
||||||
}
|
}
|
||||||
sort.Slice(txHashes, func(i, j int) bool {
|
|
||||||
return txHashes[i].CompareTo(txHashes[j]) < 0
|
|
||||||
})
|
|
||||||
|
|
||||||
root := bc.dao.MPT.StateRoot()
|
root := bc.dao.MPT.StateRoot()
|
||||||
var prevHash util.Uint256
|
var prevHash util.Uint256
|
||||||
|
@ -700,7 +693,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
||||||
}
|
}
|
||||||
bc.topBlock.Store(block)
|
bc.topBlock.Store(block)
|
||||||
atomic.StoreUint32(&bc.blockHeight, block.Index)
|
atomic.StoreUint32(&bc.blockHeight, block.Index)
|
||||||
bc.memPool.RemoveStale(func(tx *transaction.Transaction) bool { return bc.isTxStillRelevant(tx, txHashes) }, bc)
|
bc.memPool.RemoveStale(func(tx *transaction.Transaction) bool { return bc.isTxStillRelevant(tx, txpool) }, bc)
|
||||||
bc.lock.Unlock()
|
bc.lock.Unlock()
|
||||||
|
|
||||||
updateBlockHeightMetric(block.Index)
|
updateBlockHeightMetric(block.Index)
|
||||||
|
@ -1305,17 +1298,18 @@ func (bc *Blockchain) verifyTxAttributes(tx *transaction.Transaction) error {
|
||||||
|
|
||||||
// isTxStillRelevant is a callback for mempool transaction filtering after the
|
// isTxStillRelevant is a callback for mempool transaction filtering after the
|
||||||
// new block addition. It returns false for transactions added by the new block
|
// new block addition. It returns false for transactions added by the new block
|
||||||
// (passed via txHashes) and does witness reverification for non-standard
|
// (passed via txpool) and does witness reverification for non-standard
|
||||||
// contracts. It operates under the assumption that full transaction verification
|
// contracts. It operates under the assumption that full transaction verification
|
||||||
// was already done so we don't need to check basic things like size, input/output
|
// was already done so we don't need to check basic things like size, input/output
|
||||||
// correctness, presence in blocks before the new one, etc.
|
// correctness, presence in blocks before the new one, etc.
|
||||||
func (bc *Blockchain) isTxStillRelevant(t *transaction.Transaction, txHashes []util.Uint256) bool {
|
func (bc *Blockchain) isTxStillRelevant(t *transaction.Transaction, txpool *mempool.Pool) bool {
|
||||||
var recheckWitness bool
|
var recheckWitness bool
|
||||||
|
|
||||||
index := sort.Search(len(txHashes), func(i int) bool {
|
if txpool == nil {
|
||||||
return txHashes[i].CompareTo(t.Hash()) >= 0
|
if bc.dao.HasTransaction(t.Hash()) {
|
||||||
})
|
return false
|
||||||
if index < len(txHashes) && txHashes[index].Equals(t.Hash()) {
|
}
|
||||||
|
} else if txpool.ContainsKey(t.Hash()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if err := bc.verifyTxAttributes(t); err != nil {
|
if err := bc.verifyTxAttributes(t); err != nil {
|
||||||
|
|
Loading…
Reference in a new issue