diff --git a/gcs/builder/builder.go b/gcs/builder/builder.go index 71bb69f..bc7f1da 100644 --- a/gcs/builder/builder.go +++ b/gcs/builder/builder.go @@ -194,6 +194,16 @@ func (b *GCSBuilder) AddScript(script []byte) *GCSBuilder { return b.AddEntries(data) } +// AddWitness adds each item of the passed filter stack to the filer. +func (b *GCSBuilder) AddWitness(witness wire.TxWitness) *GCSBuilder { + // Do nothing if the builder's already errored out. + if b.err != nil { + return b + } + + return b.AddEntries(witness) +} + // Build returns a function which builds a GCS filter with the given parameters // and data. func (b *GCSBuilder) Build() (*gcs.Filter, error) { @@ -318,19 +328,36 @@ func BuildBasicFilter(block *wire.MsgBlock) (*gcs.Filter, error) { func BuildExtFilter(block *wire.MsgBlock) (*gcs.Filter, error) { blockHash := block.BlockHash() b := WithKeyHash(&blockHash) + + // If the filter had an issue with the specified key, then we force it + // to bubble up here by calling the Key() function. _, err := b.Key() if err != nil { return nil, err } + + // In order to build an extended filter, we add the hash of each + // transaction as well as each piece of witness data included in both + // the sigScript and the witness stack of an input. for i, tx := range block.Transactions { + // First we'll compute the bash of the transaction and add that + // directly to the filter. txHash := tx.TxHash() b.AddHash(&txHash) + // Skip the inputs for the coinbase transaction if i != 0 { + // Next, for each input, we'll add the sigScript (if + // it's present), and also the witness stack (if it's + // present) for _, txIn := range tx.TxIn { if txIn.SignatureScript != nil { b.AddScript(txIn.SignatureScript) } + + if len(txIn.Witness) != 0 { + b.AddWitness(txIn.Witness) + } } } } diff --git a/gcs/builder/builder_test.go b/gcs/builder/builder_test.go index ca49382..3325df3 100644 --- a/gcs/builder/builder_test.go +++ b/gcs/builder/builder_test.go @@ -49,6 +49,20 @@ var ( testHash = "000000000000000000496d7ff9bd2c96154a8d64260e8b3b411e625712abb14c" testAddr = "3Nxwenay9Z8Lc9JBiywExpnEFiLp6Afp8v" + + witness = [][]byte{ + []byte{0x4c, 0xb1, 0xab, 0x12, 0x57, 0x62, 0x1e, 0x41, + 0x3b, 0x8b, 0x0e, 0x26, 0x64, 0x8d, 0x4a, 0x15, + 0x3b, 0x8b, 0x0e, 0x26, 0x64, 0x8d, 0x4a, 0x15, + 0x3b, 0x8b, 0x0e, 0x26, 0x64, 0x8d, 0x4a, 0x15}, + + []byte{0xdd, 0xa3, 0x5a, 0x14, 0x88, 0xfb, 0x97, 0xb6, + 0xeb, 0x3f, 0xe6, 0xe9, 0xef, 0x2a, 0x25, 0x81, + 0x4e, 0x39, 0x6f, 0xb5, 0xdc, 0x29, 0x5f, 0xe9, + 0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98, + 0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98, + 0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98}, + } ) // TestUseBlockHash tests using a block hash as a filter key. @@ -88,11 +102,11 @@ func TestUseBlockHash(t *testing.T) { hex.EncodeToString(key[:]), hex.EncodeToString(testKey[:])) } - BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, t) + BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, witness, t) // Create a GCSBuilder with a key hash and non-default P and test it. b = builder.WithKeyHashP(hash, 30) - BuilderTest(b, hash, 30, outPoint, addrBytes, t) + BuilderTest(b, hash, 30, outPoint, addrBytes, witness, t) // Create a GCSBuilder with a random key, set the key from a hash // manually, check that the key is correct, and test it. @@ -108,7 +122,7 @@ func TestUseBlockHash(t *testing.T) { hex.EncodeToString(key[:]), hex.EncodeToString(testKey[:])) } - BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, t) + BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, witness, t) // Create a GCSBuilder with a random key and test it. b = builder.WithRandomKey() @@ -118,7 +132,7 @@ func TestUseBlockHash(t *testing.T) { err.Error()) } t.Logf("Random Key 1: %s", hex.EncodeToString(key1[:])) - BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, t) + BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, witness, t) // Create a GCSBuilder with a random key and non-default P and test it. b = builder.WithRandomKeyP(30) @@ -131,7 +145,7 @@ func TestUseBlockHash(t *testing.T) { if key2 == key1 { t.Fatalf("Random keys are the same!") } - BuilderTest(b, hash, 30, outPoint, addrBytes, t) + BuilderTest(b, hash, 30, outPoint, addrBytes, witness, t) // Create a GCSBuilder with a known key and test it. b = builder.WithKey(testKey) @@ -145,7 +159,7 @@ func TestUseBlockHash(t *testing.T) { hex.EncodeToString(key[:]), hex.EncodeToString(testKey[:])) } - BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, t) + BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, witness, t) // Create a GCSBuilder with a known key and non-default P and test it. b = builder.WithKeyP(testKey, 30) @@ -159,7 +173,7 @@ func TestUseBlockHash(t *testing.T) { hex.EncodeToString(key[:]), hex.EncodeToString(testKey[:])) } - BuilderTest(b, hash, 30, outPoint, addrBytes, t) + BuilderTest(b, hash, 30, outPoint, addrBytes, witness, t) // Create a GCSBuilder with a known key and too-high P and ensure error // works throughout all functions that use it. @@ -177,7 +191,9 @@ func TestUseBlockHash(t *testing.T) { } func BuilderTest(b *builder.GCSBuilder, hash *chainhash.Hash, p uint8, - outPoint wire.OutPoint, addrBytes []byte, t *testing.T) { + outPoint wire.OutPoint, addrBytes []byte, witness wire.TxWitness, + t *testing.T) { + key, err := b.Key() if err != nil { t.Fatalf("Builder instantiation with key hash failed: %s", @@ -256,4 +272,14 @@ func BuilderTest(b *builder.GCSBuilder, hash *chainhash.Hash, p uint8, t.Logf("Filter didn't match when it should have!") } + // Add a routine witness stack, build a filter, and test that it + // matches. + b.AddWitness(witness) + match, err = f.MatchAny(key, witness) + if err != nil { + t.Fatalf("Filter match any failed: %s", err) + } + if !match { + t.Logf("Filter didn't match when it should have!") + } }