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