ab6388e0c6
In this commit, we remoec the AddScript method as it's no longer used, and AddEntry should be used in place for adding pkScripts to the filters.
282 lines
7.8 KiB
Go
282 lines
7.8 KiB
Go
// Copyright (c) 2017 The btcsuite developers
|
|
// Copyright (c) 2017 The Lightning Network Developers
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package builder_test
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"testing"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
"github.com/btcsuite/btcd/txscript"
|
|
"github.com/btcsuite/btcd/wire"
|
|
"github.com/btcsuite/btcutil"
|
|
"github.com/btcsuite/btcutil/gcs"
|
|
"github.com/btcsuite/btcutil/gcs/builder"
|
|
)
|
|
|
|
var (
|
|
// No need to allocate an err variable in every test
|
|
err error
|
|
|
|
// List of values for building a filter
|
|
contents = [][]byte{
|
|
[]byte("Alex"),
|
|
[]byte("Bob"),
|
|
[]byte("Charlie"),
|
|
[]byte("Dick"),
|
|
[]byte("Ed"),
|
|
[]byte("Frank"),
|
|
[]byte("George"),
|
|
[]byte("Harry"),
|
|
[]byte("Ilya"),
|
|
[]byte("John"),
|
|
[]byte("Kevin"),
|
|
[]byte("Larry"),
|
|
[]byte("Michael"),
|
|
[]byte("Nate"),
|
|
[]byte("Owen"),
|
|
[]byte("Paul"),
|
|
[]byte("Quentin"),
|
|
}
|
|
|
|
testKey = [16]byte{0x4c, 0xb1, 0xab, 0x12, 0x57, 0x62, 0x1e, 0x41,
|
|
0x3b, 0x8b, 0x0e, 0x26, 0x64, 0x8d, 0x4a, 0x15}
|
|
|
|
testHash = "000000000000000000496d7ff9bd2c96154a8d64260e8b3b411e625712abb14c"
|
|
|
|
testAddr = "3Nxwenay9Z8Lc9JBiywExpnEFiLp6Afp8v"
|
|
|
|
witness = [][]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},
|
|
|
|
{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.
|
|
func TestUseBlockHash(t *testing.T) {
|
|
// Block hash #448710, pretty high difficulty.
|
|
hash, err := chainhash.NewHashFromStr(testHash)
|
|
if err != nil {
|
|
t.Fatalf("Hash from string failed: %s", err.Error())
|
|
}
|
|
|
|
// wire.OutPoint
|
|
outPoint := wire.OutPoint{
|
|
Hash: *hash,
|
|
Index: 4321,
|
|
}
|
|
|
|
// btcutil.Address
|
|
addr, err := btcutil.DecodeAddress(testAddr, &chaincfg.MainNetParams)
|
|
if err != nil {
|
|
t.Fatalf("Address decode failed: %s", err.Error())
|
|
}
|
|
addrBytes, err := txscript.PayToAddrScript(addr)
|
|
if err != nil {
|
|
t.Fatalf("Address script build failed: %s", err.Error())
|
|
}
|
|
|
|
// Create a GCSBuilder with a key hash and check that the key is derived
|
|
// correctly, then test it.
|
|
b := builder.WithKeyHash(hash)
|
|
key, err := b.Key()
|
|
if err != nil {
|
|
t.Fatalf("Builder instantiation with key hash failed: %s",
|
|
err.Error())
|
|
}
|
|
if key != testKey {
|
|
t.Fatalf("Key not derived correctly from key hash:\n%s\n%s",
|
|
hex.EncodeToString(key[:]),
|
|
hex.EncodeToString(testKey[:]))
|
|
}
|
|
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.WithKeyHashPM(hash, 30, 90)
|
|
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.
|
|
b = builder.WithRandomKey()
|
|
b.SetKeyFromHash(hash)
|
|
key, err = b.Key()
|
|
if err != nil {
|
|
t.Fatalf("Builder instantiation with known key failed: %s",
|
|
err.Error())
|
|
}
|
|
if key != testKey {
|
|
t.Fatalf("Key not copied correctly from known key:\n%s\n%s",
|
|
hex.EncodeToString(key[:]),
|
|
hex.EncodeToString(testKey[:]))
|
|
}
|
|
BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, witness, t)
|
|
|
|
// Create a GCSBuilder with a random key and test it.
|
|
b = builder.WithRandomKey()
|
|
key1, err := b.Key()
|
|
if err != nil {
|
|
t.Fatalf("Builder instantiation with random key failed: %s",
|
|
err.Error())
|
|
}
|
|
t.Logf("Random Key 1: %s", hex.EncodeToString(key1[:]))
|
|
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.WithRandomKeyPM(30, 90)
|
|
key2, err := b.Key()
|
|
if err != nil {
|
|
t.Fatalf("Builder instantiation with random key failed: %s",
|
|
err.Error())
|
|
}
|
|
t.Logf("Random Key 2: %s", hex.EncodeToString(key2[:]))
|
|
if key2 == key1 {
|
|
t.Fatalf("Random keys are the same!")
|
|
}
|
|
BuilderTest(b, hash, 30, outPoint, addrBytes, witness, t)
|
|
|
|
// Create a GCSBuilder with a known key and test it.
|
|
b = builder.WithKey(testKey)
|
|
key, err = b.Key()
|
|
if err != nil {
|
|
t.Fatalf("Builder instantiation with known key failed: %s",
|
|
err.Error())
|
|
}
|
|
if key != testKey {
|
|
t.Fatalf("Key not copied correctly from known key:\n%s\n%s",
|
|
hex.EncodeToString(key[:]),
|
|
hex.EncodeToString(testKey[:]))
|
|
}
|
|
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.WithKeyPM(testKey, 30, 90)
|
|
key, err = b.Key()
|
|
if err != nil {
|
|
t.Fatalf("Builder instantiation with known key failed: %s",
|
|
err.Error())
|
|
}
|
|
if key != testKey {
|
|
t.Fatalf("Key not copied correctly from known key:\n%s\n%s",
|
|
hex.EncodeToString(key[:]),
|
|
hex.EncodeToString(testKey[:]))
|
|
}
|
|
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.
|
|
b = builder.WithRandomKeyPM(33, 99).SetKeyFromHash(hash).SetKey(testKey)
|
|
b.SetP(30).AddEntry(hash.CloneBytes()).AddEntries(contents).
|
|
AddHash(hash).AddEntry(addrBytes)
|
|
_, err = b.Key()
|
|
if err != gcs.ErrPTooBig {
|
|
t.Fatalf("No error on P too big!")
|
|
}
|
|
_, err = b.Build()
|
|
if err != gcs.ErrPTooBig {
|
|
t.Fatalf("No error on P too big!")
|
|
}
|
|
}
|
|
|
|
func BuilderTest(b *builder.GCSBuilder, hash *chainhash.Hash, p uint8,
|
|
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",
|
|
err.Error())
|
|
}
|
|
|
|
// Build a filter and test matches.
|
|
b.AddEntries(contents)
|
|
f, err := b.Build()
|
|
if err != nil {
|
|
t.Fatalf("Filter build failed: %s", err.Error())
|
|
}
|
|
if f.P() != p {
|
|
t.Fatalf("Filter built with wrong probability")
|
|
}
|
|
match, err := f.Match(key, []byte("Nate"))
|
|
if err != nil {
|
|
t.Fatalf("Filter match failed: %s", err)
|
|
}
|
|
if !match {
|
|
t.Fatal("Filter didn't match when it should have!")
|
|
}
|
|
match, err = f.Match(key, []byte("weks"))
|
|
if err != nil {
|
|
t.Fatalf("Filter match failed: %s", err)
|
|
}
|
|
if match {
|
|
t.Logf("False positive match, should be 1 in 2**%d!",
|
|
builder.DefaultP)
|
|
}
|
|
|
|
// Add a hash, build a filter, and test matches
|
|
b.AddHash(hash)
|
|
f, err = b.Build()
|
|
if err != nil {
|
|
t.Fatalf("Filter build failed: %s", err.Error())
|
|
}
|
|
match, err = f.Match(key, hash.CloneBytes())
|
|
if err != nil {
|
|
t.Fatalf("Filter match failed: %s", err)
|
|
}
|
|
if !match {
|
|
t.Fatal("Filter didn't match when it should have!")
|
|
}
|
|
|
|
// Add a script, build a filter, and test matches
|
|
b.AddEntry(addrBytes)
|
|
f, err = b.Build()
|
|
if err != nil {
|
|
t.Fatalf("Filter build failed: %s", err.Error())
|
|
}
|
|
match, err = f.MatchAny(key, [][]byte{addrBytes})
|
|
if err != nil {
|
|
t.Fatalf("Filter match any failed: %s", err)
|
|
}
|
|
if !match {
|
|
t.Fatal("Filter didn't match when it should have!")
|
|
}
|
|
|
|
// Add a routine witness stack, build a filter, and test that it
|
|
// matches.
|
|
b.AddWitness(witness)
|
|
f, err = b.Build()
|
|
if err != nil {
|
|
t.Fatalf("Filter build failed: %s", err.Error())
|
|
}
|
|
match, err = f.MatchAny(key, witness)
|
|
if err != nil {
|
|
t.Fatalf("Filter match any failed: %s", err)
|
|
}
|
|
if !match {
|
|
t.Fatal("Filter didn't match when it should have!")
|
|
}
|
|
|
|
// Check that adding duplicate items does not increase filter size.
|
|
originalSize := f.N()
|
|
b.AddEntry(addrBytes)
|
|
b.AddWitness(witness)
|
|
f, err = b.Build()
|
|
if err != nil {
|
|
t.Fatalf("Filter build failed: %s", err.Error())
|
|
}
|
|
if f.N() != originalSize {
|
|
t.Fatal("Filter size increased with duplicate items")
|
|
}
|
|
}
|