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