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