hashcache.go raw

   1  package txscript
   2  
   3  import (
   4  	"sync"
   5  	
   6  	"github.com/p9c/p9/pkg/chainhash"
   7  	"github.com/p9c/p9/pkg/wire"
   8  )
   9  
  10  // TxSigHashes houses the partial set of sighashes introduced within BIP0143. This partial set of sighashes may be
  11  // re-used within each input across a transaction when validating all inputs. As a result, validation complexity for
  12  // SigHashAll can be reduced by a polynomial factor.
  13  type TxSigHashes struct {
  14  	HashPrevOuts chainhash.Hash
  15  	HashSequence chainhash.Hash
  16  	HashOutputs  chainhash.Hash
  17  }
  18  
  19  // NewTxSigHashes computes, and returns the cached sighashes of the given transaction.
  20  func NewTxSigHashes(tx *wire.MsgTx) *TxSigHashes {
  21  	return &TxSigHashes{
  22  		HashPrevOuts: calcHashPrevOuts(tx),
  23  		HashSequence: calcHashSequence(tx),
  24  		HashOutputs:  calcHashOutputs(tx),
  25  	}
  26  }
  27  
  28  // HashCache houses a set of partial sighashes keyed by txid. The set of partial sighashes are those introduced within
  29  // BIP0143 by the new more efficient sighash digest calculation algorithm. Using this threadsafe shared cache, multiple
  30  // goroutines can safely re-use the pre-computed partial sighashes speeding up validation time amongst all inputs found
  31  // within a block.
  32  type HashCache struct {
  33  	sigHashes map[chainhash.Hash]*TxSigHashes
  34  	sync.RWMutex
  35  }
  36  
  37  // NewHashCache returns a new instance of the HashCache given a maximum number of entries which may exist within it at
  38  // anytime.
  39  func NewHashCache(maxSize uint) *HashCache {
  40  	return &HashCache{
  41  		sigHashes: make(map[chainhash.Hash]*TxSigHashes, maxSize),
  42  	}
  43  }
  44  
  45  // AddSigHashes computes, then adds the partial sighashes for the passed transaction.
  46  func (h *HashCache) AddSigHashes(tx *wire.MsgTx) {
  47  	h.Lock()
  48  	h.sigHashes[tx.TxHash()] = NewTxSigHashes(tx)
  49  	h.Unlock()
  50  }
  51  
  52  // ContainsHashes returns true if the partial sighashes for the passed transaction currently exist within the HashCache,
  53  // and false otherwise.
  54  func (h *HashCache) ContainsHashes(txid *chainhash.Hash) bool {
  55  	h.RLock()
  56  	_, found := h.sigHashes[*txid]
  57  	h.RUnlock()
  58  	return found
  59  }
  60  
  61  // GetSigHashes possibly returns the previously cached partial sighashes for the passed transaction. This function also
  62  // returns an additional boolean value indicating if the sighashes for the passed transaction were found to be present
  63  // within the HashCache.
  64  func (h *HashCache) GetSigHashes(txid *chainhash.Hash) (*TxSigHashes, bool) {
  65  	h.RLock()
  66  	item, found := h.sigHashes[*txid]
  67  	h.RUnlock()
  68  	return item, found
  69  }
  70  
  71  // PurgeSigHashes removes all partial sighashes from the HashCache belonging to the passed transaction.
  72  func (h *HashCache) PurgeSigHashes(txid *chainhash.Hash) {
  73  	h.Lock()
  74  	delete(h.sigHashes, *txid)
  75  	h.Unlock()
  76  }
  77