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