builder_test.go raw

   1  package builder_test
   2  
   3  import (
   4  	"encoding/hex"
   5  	"github.com/p9c/p9/pkg/btcaddr"
   6  	"testing"
   7  	
   8  	"github.com/p9c/p9/pkg/chaincfg"
   9  	"github.com/p9c/p9/pkg/chainhash"
  10  	"github.com/p9c/p9/pkg/gcs"
  11  	"github.com/p9c/p9/pkg/gcs/builder"
  12  	"github.com/p9c/p9/pkg/txscript"
  13  	"github.com/p9c/p9/pkg/wire"
  14  )
  15  
  16  var (
  17  	// // No need to allocate an err variable in every test
  18  	// e error
  19  	// List of values for building a filter
  20  	contents = [][]byte{
  21  		[]byte("Alex"),
  22  		[]byte("Bob"),
  23  		[]byte("Charlie"),
  24  		[]byte("Dick"),
  25  		[]byte("Ed"),
  26  		[]byte("Frank"),
  27  		[]byte("George"),
  28  		[]byte("Harry"),
  29  		[]byte("Ilya"),
  30  		[]byte("John"),
  31  		[]byte("Kevin"),
  32  		[]byte("Larry"),
  33  		[]byte("Michael"),
  34  		[]byte("Nate"),
  35  		[]byte("Owen"),
  36  		[]byte("Paul"),
  37  		[]byte("Quentin"),
  38  	}
  39  	testKey = [16]byte{
  40  		0x4c, 0xb1, 0xab, 0x12, 0x57, 0x62, 0x1e, 0x41,
  41  		0x3b, 0x8b, 0x0e, 0x26, 0x64, 0x8d, 0x4a, 0x15,
  42  	}
  43  	testHash = "000000000000000000496d7ff9bd2c96154a8d64260e8b3b411e625712abb14c"
  44  	testAddr = "3Nxwenay9Z8Lc9JBiywExpnEFiLp6Afp8v"
  45  	witness  = [][]byte{
  46  		{
  47  			0x4c, 0xb1, 0xab, 0x12, 0x57, 0x62, 0x1e, 0x41,
  48  			0x3b, 0x8b, 0x0e, 0x26, 0x64, 0x8d, 0x4a, 0x15,
  49  			0x3b, 0x8b, 0x0e, 0x26, 0x64, 0x8d, 0x4a, 0x15,
  50  			0x3b, 0x8b, 0x0e, 0x26, 0x64, 0x8d, 0x4a, 0x15,
  51  		},
  52  		{
  53  			0xdd, 0xa3, 0x5a, 0x14, 0x88, 0xfb, 0x97, 0xb6,
  54  			0xeb, 0x3f, 0xe6, 0xe9, 0xef, 0x2a, 0x25, 0x81,
  55  			0x4e, 0x39, 0x6f, 0xb5, 0xdc, 0x29, 0x5f, 0xe9,
  56  			0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98,
  57  			0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98,
  58  			0x94, 0xb9, 0x67, 0x89, 0xb2, 0x1a, 0x03, 0x98,
  59  		},
  60  	}
  61  )
  62  
  63  // TestUseBlockHash tests using a block hash as a filter key.
  64  func TestUseBlockHash(t *testing.T) {
  65  	// Block hash #448710, pretty high difficulty.
  66  	hash, e := chainhash.NewHashFromStr(testHash)
  67  	if e != nil {
  68  		t.Fatalf("Hash from string failed: %s", e.Error())
  69  	}
  70  	// wire.OutPoint
  71  	outPoint := wire.OutPoint{
  72  		Hash:  *hash,
  73  		Index: 4321,
  74  	}
  75  	// util.Address
  76  	addr, e := btcaddr.Decode(testAddr, &chaincfg.MainNetParams)
  77  	if e != nil {
  78  		t.Fatalf("Address decode failed: %s", e.Error())
  79  	}
  80  	addrBytes, e := txscript.PayToAddrScript(addr)
  81  	if e != nil {
  82  		t.Fatalf("Address script podbuild failed: %s", e.Error())
  83  	}
  84  	// Create a GCS with a key hash and check that the key is derived correctly, then test it.
  85  	b := builder.WithKeyHash(hash)
  86  	key, e := b.Key()
  87  	if e != nil {
  88  		t.Fatalf(
  89  			"Builder instantiation with key hash failed: %s",
  90  			e.Error(),
  91  		)
  92  	}
  93  	if key != testKey {
  94  		t.Fatalf(
  95  			"Key not derived correctly from key hash:\n%s\n%s",
  96  			hex.EncodeToString(key[:]),
  97  			hex.EncodeToString(testKey[:]),
  98  		)
  99  	}
 100  	BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, witness, t)
 101  	// Create a GCS with a key hash and non-default P and test it.
 102  	b = builder.WithKeyHashPM(hash, 30, 90)
 103  	BuilderTest(b, hash, 30, outPoint, addrBytes, witness, t)
 104  	// Create a GCS with a random key, set the key from a hash manually, check that the key is correct, and test it.
 105  	b = builder.WithRandomKey()
 106  	b.SetKeyFromHash(hash)
 107  	key, e = b.Key()
 108  	if e != nil {
 109  		t.Fatalf(
 110  			"Builder instantiation with known key failed: %s",
 111  			e.Error(),
 112  		)
 113  	}
 114  	if key != testKey {
 115  		t.Fatalf(
 116  			"Key not copied correctly from known key:\n%s\n%s",
 117  			hex.EncodeToString(key[:]),
 118  			hex.EncodeToString(testKey[:]),
 119  		)
 120  	}
 121  	BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, witness, t)
 122  	// Create a GCS with a random key and test it.
 123  	b = builder.WithRandomKey()
 124  	key1, e := b.Key()
 125  	if e != nil {
 126  		t.Fatalf(
 127  			"Builder instantiation with random key failed: %s",
 128  			e.Error(),
 129  		)
 130  	}
 131  	t.Logf("Random Key 1: %s", hex.EncodeToString(key1[:]))
 132  	BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, witness, t)
 133  	// Create a GCS with a random key and non-default P and test it.
 134  	b = builder.WithRandomKeyPM(30, 90)
 135  	key2, e := b.Key()
 136  	if e != nil {
 137  		t.Fatalf(
 138  			"Builder instantiation with random key failed: %s",
 139  			e.Error(),
 140  		)
 141  	}
 142  	t.Logf("Random Key 2: %s", hex.EncodeToString(key2[:]))
 143  	if key2 == key1 {
 144  		t.Fatalf("Random keys are the same!")
 145  	}
 146  	BuilderTest(b, hash, 30, outPoint, addrBytes, witness, t)
 147  	// Create a GCS with a known key and test it.
 148  	b = builder.WithKey(testKey)
 149  	key, e = b.Key()
 150  	if e != nil {
 151  		t.Fatalf(
 152  			"Builder instantiation with known key failed: %s",
 153  			e.Error(),
 154  		)
 155  	}
 156  	if key != testKey {
 157  		t.Fatalf(
 158  			"Key not copied correctly from known key:\n%s\n%s",
 159  			hex.EncodeToString(key[:]),
 160  			hex.EncodeToString(testKey[:]),
 161  		)
 162  	}
 163  	BuilderTest(b, hash, builder.DefaultP, outPoint, addrBytes, witness, t)
 164  	// Create a GCS with a known key and non-default P and test it.
 165  	b = builder.WithKeyPM(testKey, 30, 90)
 166  	key, e = b.Key()
 167  	if e != nil {
 168  		t.Fatalf(
 169  			"Builder instantiation with known key failed: %s",
 170  			e.Error(),
 171  		)
 172  	}
 173  	if key != testKey {
 174  		t.Fatalf(
 175  			"Key not copied correctly from known key:\n%s\n%s",
 176  			hex.EncodeToString(key[:]),
 177  			hex.EncodeToString(testKey[:]),
 178  		)
 179  	}
 180  	BuilderTest(b, hash, 30, outPoint, addrBytes, witness, t)
 181  	// Create a GCS with a known key and too-high P and ensure error works throughout all functions that use it.
 182  	b = builder.WithRandomKeyPM(33, 99).SetKeyFromHash(hash).SetKey(testKey)
 183  	b.SetP(30).AddEntry(hash.CloneBytes()).AddEntries(contents).
 184  		AddHash(hash).AddEntry(addrBytes)
 185  	_, e = b.Key()
 186  	if e != gcs.ErrPTooBig {
 187  		t.Fatalf("No error on P too big!")
 188  	}
 189  	_, e = b.Build()
 190  	if e != gcs.ErrPTooBig {
 191  		t.Fatalf("No error on P too big!")
 192  	}
 193  }
 194  func BuilderTest(
 195  	b *builder.GCS, hash *chainhash.Hash, p uint8,
 196  	outPoint wire.OutPoint, addrBytes []byte, witness wire.TxWitness,
 197  	t *testing.T,
 198  ) {
 199  	key, e := b.Key()
 200  	if e != nil {
 201  		t.Fatalf(
 202  			"Builder instantiation with key hash failed: %s",
 203  			e.Error(),
 204  		)
 205  	}
 206  	// Build a filter and test matches.
 207  	b.AddEntries(contents)
 208  	f, e := b.Build()
 209  	if e != nil {
 210  		t.Fatalf("Filter podbuild failed: %s", e.Error())
 211  	}
 212  	if f.P() != p {
 213  		t.Fatalf("Filter built with wrong probability")
 214  	}
 215  	match, e := f.Match(key, []byte("Nate"))
 216  	if e != nil {
 217  		t.Fatalf("Filter match failed: %s", e)
 218  	}
 219  	if !match {
 220  		t.Fatal("Filter didn't match when it should have!")
 221  	}
 222  	match, e = f.Match(key, []byte("weks"))
 223  	if e != nil {
 224  		t.Fatalf("Filter match failed: %s", e)
 225  	}
 226  	if match {
 227  		t.Logf(
 228  			"False positive match, should be 1 in 2**%d!",
 229  			builder.DefaultP,
 230  		)
 231  	}
 232  	// Add a hash, podbuild a filter, and test matches
 233  	b.AddHash(hash)
 234  	f, e = b.Build()
 235  	if e != nil {
 236  		t.Fatalf("Filter podbuild failed: %s", e.Error())
 237  	}
 238  	match, e = f.Match(key, hash.CloneBytes())
 239  	if e != nil {
 240  		t.Fatalf("Filter match failed: %s", e)
 241  	}
 242  	if !match {
 243  		t.Fatal("Filter didn't match when it should have!")
 244  	}
 245  	// Add a script, podbuild a filter, and test matches
 246  	b.AddEntry(addrBytes)
 247  	f, e = b.Build()
 248  	if e != nil {
 249  		t.Fatalf("Filter podbuild failed: %s", e.Error())
 250  	}
 251  	match, e = f.MatchAny(key, [][]byte{addrBytes})
 252  	if e != nil {
 253  		t.Fatalf("Filter match any failed: %s", e)
 254  	}
 255  	if !match {
 256  		t.Fatal("Filter didn't match when it should have!")
 257  	}
 258  	// Add a routine witness stack, podbuild a filter, and test that it matches.
 259  	b.AddWitness(witness)
 260  	f, e = b.Build()
 261  	if e != nil {
 262  		t.Fatalf("Filter podbuild failed: %s", e.Error())
 263  	}
 264  	match, e = f.MatchAny(key, witness)
 265  	if e != nil {
 266  		t.Fatalf("Filter match any failed: %s", e)
 267  	}
 268  	if !match {
 269  		t.Fatal("Filter didn't match when it should have!")
 270  	}
 271  	// Chk that adding duplicate items does not increase filter size.
 272  	originalSize := f.N()
 273  	b.AddEntry(addrBytes)
 274  	b.AddWitness(witness)
 275  	f, e = b.Build()
 276  	if e != nil {
 277  		t.Fatalf("Filter podbuild failed: %s", e.Error())
 278  	}
 279  	if f.N() != originalSize {
 280  		t.Fatal("Filter size increased with duplicate items")
 281  	}
 282  }
 283