@bsv/sdk 1.9.3 → 1.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/docs/fast-docs.png +0 -0
  3. package/docs/index.md +49 -44
  4. package/docs/swagger.png +0 -0
  5. package/package.json +1 -1
  6. package/docs/MARKDOWN_VALIDATION_GUIDE.md +0 -175
  7. package/docs/concepts/beef.md +0 -92
  8. package/docs/concepts/chain-tracking.md +0 -134
  9. package/docs/concepts/decentralized-identity.md +0 -221
  10. package/docs/concepts/fees.md +0 -249
  11. package/docs/concepts/identity-certificates.md +0 -307
  12. package/docs/concepts/index.md +0 -77
  13. package/docs/concepts/key-management.md +0 -185
  14. package/docs/concepts/script-templates.md +0 -176
  15. package/docs/concepts/sdk-philosophy.md +0 -80
  16. package/docs/concepts/signatures.md +0 -194
  17. package/docs/concepts/spv-verification.md +0 -118
  18. package/docs/concepts/transaction-encoding.md +0 -167
  19. package/docs/concepts/transaction-structure.md +0 -67
  20. package/docs/concepts/trust-model.md +0 -139
  21. package/docs/concepts/verification.md +0 -250
  22. package/docs/concepts/wallet-integration.md +0 -101
  23. package/docs/guides/development-wallet-setup.md +0 -374
  24. package/docs/guides/direct-transaction-creation.md +0 -147
  25. package/docs/guides/http-client-configuration.md +0 -488
  26. package/docs/guides/index.md +0 -138
  27. package/docs/guides/large-transactions.md +0 -448
  28. package/docs/guides/multisig-transactions.md +0 -792
  29. package/docs/guides/security-best-practices.md +0 -494
  30. package/docs/guides/transaction-batching.md +0 -132
  31. package/docs/guides/transaction-signing-methods.md +0 -419
  32. package/docs/reference/arc-config.md +0 -698
  33. package/docs/reference/brc-100.md +0 -33
  34. package/docs/reference/configuration.md +0 -835
  35. package/docs/reference/debugging.md +0 -705
  36. package/docs/reference/errors.md +0 -597
  37. package/docs/reference/index.md +0 -111
  38. package/docs/reference/network-config.md +0 -914
  39. package/docs/reference/op-codes.md +0 -325
  40. package/docs/reference/transaction-signatures.md +0 -95
  41. package/docs/tutorials/advanced-transaction.md +0 -572
  42. package/docs/tutorials/aes-encryption.md +0 -949
  43. package/docs/tutorials/authfetch-tutorial.md +0 -986
  44. package/docs/tutorials/ecdh-key-exchange.md +0 -549
  45. package/docs/tutorials/elliptic-curve-fundamentals.md +0 -606
  46. package/docs/tutorials/error-handling.md +0 -1216
  47. package/docs/tutorials/first-transaction-low-level.md +0 -205
  48. package/docs/tutorials/first-transaction.md +0 -275
  49. package/docs/tutorials/hashes-and-hmacs.md +0 -788
  50. package/docs/tutorials/identity-management.md +0 -729
  51. package/docs/tutorials/index.md +0 -219
  52. package/docs/tutorials/key-management.md +0 -538
  53. package/docs/tutorials/protowallet-development.md +0 -743
  54. package/docs/tutorials/script-construction.md +0 -690
  55. package/docs/tutorials/spv-merkle-proofs.md +0 -685
  56. package/docs/tutorials/testnet-transactions-low-level.md +0 -359
  57. package/docs/tutorials/transaction-broadcasting.md +0 -538
  58. package/docs/tutorials/transaction-types.md +0 -420
  59. package/docs/tutorials/type-42.md +0 -568
  60. package/docs/tutorials/uhrp-storage.md +0 -599
@@ -1,685 +0,0 @@
1
- # SPV and Merkle Proof Verification
2
-
3
- ## Introduction
4
-
5
- Simplified Payment Verification (SPV) is a method for verifying Bitcoin transactions without downloading the entire blockchain. Instead of storing all transaction data, SPV clients only need block headers and merkle proofs to verify that specific transactions are included in the blockchain.
6
-
7
- This tutorial covers:
8
-
9
- - Understanding SPV principles and merkle trees
10
- - Working with merkle proofs using the `MerklePath` class
11
- - Verifying transactions with the `Transaction.verify()` method
12
- - Implementing custom chain trackers for block header verification
13
- - Working with BEEF (BRC-62) structures for efficient SPV
14
-
15
- > **📚 Related Concepts**: Review [SPV Verification](../concepts/spv-verification.md), [Transaction Verification](../concepts/verification.md), and [BEEF Format](../concepts/beef.md) for foundational understanding.
16
-
17
- ## Prerequisites
18
-
19
- - Completed "Your First BSV Transaction" tutorial
20
- - Basic understanding of Bitcoin transaction structure
21
- - Familiarity with cryptographic hash functions
22
-
23
- ## Understanding SPV and Merkle Trees
24
-
25
- ### What is SPV?
26
-
27
- SPV allows lightweight clients to verify transactions without storing the full blockchain by:
28
-
29
- 1. **Block Headers Only**: Store only block headers (80 bytes each) instead of full blocks
30
- 2. **Merkle Proofs**: Use cryptographic proofs to verify transaction inclusion
31
- 3. **Chain Validation**: Verify the proof-of-work chain of block headers
32
- 4. **Script Validation**: Validate that transaction scripts are properly formed
33
-
34
- ### Merkle Trees in Bitcoin
35
-
36
- Bitcoin blocks organize transactions in a binary merkle tree structure:
37
-
38
- ```
39
- Merkle Root
40
- / \
41
- Hash AB Hash CD
42
- / \ / \
43
- Hash A Hash B Hash C Hash D
44
- | | | |
45
- Tx A Tx B Tx C Tx D
46
- ```
47
-
48
- A merkle proof provides the minimum hashes needed to compute the merkle root from a specific transaction.
49
-
50
- ## Working with MerklePath
51
-
52
- The `MerklePath` class represents a merkle proof for a specific transaction:
53
-
54
- ```typescript
55
- import { MerklePath, WhatsOnChain } from '@bsv/sdk'
56
-
57
- async function runMerkleExample() {
58
- // Create the merkle path first (our demonstration example)
59
- const blockHeight = 850000
60
- const merklePath = new MerklePath(blockHeight, [
61
- [
62
- { offset: 0, hash: 'ffeff11c25cde7c06d407490d81ef4d0db64aad6ab3d14393530701561a465ef', txid: true },
63
- { offset: 1, hash: 'b9ef07a62553ef8b0898a79c291b92c60f7932260888bde0dab2dd2610d8668e' }
64
- ]
65
- ])
66
-
67
- // Example tx
68
- const txid = 'ffeff11c25cde7c06d407490d81ef4d0db64aad6ab3d14393530701561a465ef'
69
-
70
- // Create a chain tracker for mainnet
71
- const chainTracker = new WhatsOnChain('main')
72
-
73
- // Verify the merkle proof
74
- const isValid = await merklePath.verify(txid, chainTracker)
75
- console.log('Merkle proof valid:', isValid)
76
-
77
- // Note: This will return false because our example merkle path
78
- // doesn't correspond to a real block on the BSV mainnet
79
- }
80
-
81
- runMerkleExample().catch(console.error)
82
- ```
83
-
84
- ## Working with Real Blockchain Data
85
-
86
- The example above demonstrates the fundamental concepts using a simplified 2-transaction block. In real BSV blockchain scenarios, blocks contain hundreds or thousands of transactions, creating much deeper merkle trees.
87
-
88
- **Our Working Example:**
89
-
90
- - **Block Height**: 850000 (arbitrary example height)
91
- - **Transaction ID**: `ffeff11c25cde7c06d407490d81ef4d0db64aad6ab3d14393530701561a465ef` (from BSV Technical Standards)
92
- - **Sibling Hash**: `b9ef07a62553ef8b0898a79c291b92c60f7932260888bde0dab2dd2610d8668e` (from BSV Technical Standards)
93
- - **Computed Merkle Root**: `6f0a2a566d54512576b3b32eb3a8ca5273d8f35d8bfba02123bb7aad59be1e61`
94
-
95
- **Real-World Complexity:**
96
- In actual BSV blocks, a transaction at index 12 (like in the BSV Technical Standards example) would require a merkle path with multiple levels:
97
-
98
- - **5 proof levels** for a block with ~32 transactions
99
- - **10 proof levels** for a block with ~1024 transactions
100
- - **20 proof levels** for a block with ~1 million transactions
101
-
102
- The logarithmic nature of merkle trees means even massive blocks require relatively few proof hashes for verification.
103
-
104
- ## Real Blockchain Merkle Paths
105
-
106
- In practice, merkle paths from real BSV blocks are more complex, with multiple levels representing the tree structure. The example above shows the simplest case - a block with only 2 transactions.
107
-
108
- **Real BSV Blockchain Example:**
109
- Based on data from the [BSV Technical Standards](https://tsc.bsvblockchain.org/standards/merkle-proof-standardised-format/), a transaction at index 12 in a larger block would have a merkle path with these hash values:
110
-
111
- - **Transaction**: `ffeff11c25cde7c06d407490d81ef4d0db64aad6ab3d14393530701561a465ef`
112
- - **Proof nodes**: 5 hash values that form the path to the merkle root
113
- - **Merkle root**: `75edb0a69eb195cdd81e310553aa4d25e18450e08f168532a2c2e9cf447bf169`
114
-
115
- The SDK handles the complex offset calculations automatically when parsing from binary formats or BEEF structures.
116
-
117
- ## Serialization Formats
118
-
119
- The BSV TypeScript SDK uses an internal object format for MerklePath construction, while the [BSV Technical Standards](https://tsc.bsvblockchain.org/standards/merkle-proof-standardised-format/) define a binary serialization format. The SDK handles the conversion between these formats internally.
120
-
121
- **Internal Format (used above):**
122
-
123
- - Array of levels, each containing leaf objects with `offset`, `hash`, `txid`, and `duplicate` properties
124
- - Direct construction allows for clear understanding of the merkle tree structure
125
-
126
- **Binary Format (from standards):**
127
-
128
- - Compact binary representation for network transmission and storage
129
- - Can be parsed using `MerklePath.fromHex()` when properly formatted
130
-
131
- ## Computing Merkle Roots
132
-
133
- You can compute the merkle root for a given transaction ID:
134
-
135
- ```typescript
136
- // Compute merkle root for a specific transaction
137
- const txid = 'ffeff11c25cde7c06d407490d81ef4d0db64aad6ab3d14393530701561a465ef'
138
- const merkleRoot = merklePath.computeRoot(txid)
139
-
140
- console.log('Computed merkle root:', merkleRoot)
141
-
142
- // How the merkle root is computed for our 2-transaction block:
143
- // 1. Take our transaction: ffeff11c25cde7c06d407490d81ef4d0db64aad6ab3d14393530701561a465ef
144
- // 2. Take sibling transaction: b9ef07a62553ef8b0898a79c291b92c60f7932260888bde0dab2dd2610d8668e
145
- // 3. Hash them together: SHA256(SHA256(txid + sibling))
146
- // 4. Result is the merkle root: 6f0a2a566d54512576b3b32eb3a8ca5273d8f35d8bfba02123bb7aad59be1e61
147
-
148
- console.log('Expected result: 6f0a2a566d54512576b3b32eb3a8ca5273d8f35d8bfba02123bb7aad59be1e61')
149
- console.log('Merkle root matches expected:', merkleRoot === '6f0a2a566d54512576b3b32eb3a8ca5273d8f35d8bfba02123bb7aad59be1e61')
150
- ```
151
-
152
- ## Understanding Merkle Tree Computation
153
-
154
- The merkle root computation follows a specific mathematical process:
155
-
156
- **For a 2-transaction block (our example):**
157
-
158
- ```
159
- Level 0 (Leaves): [Transaction A] [Transaction B]
160
- | |
161
- Level 1 (Root): [Hash(A + B)]
162
- ```
163
-
164
- **Step-by-step process:**
165
-
166
- 1. **Start with transaction IDs** (already hashed)
167
- 2. **Concatenate them**: `ffeff11c...465ef` + `b9ef07a6...8668e`
168
- 3. **Double SHA256**: `SHA256(SHA256(concatenated_data))`
169
- 4. **Result**: The merkle root that represents the entire block
170
-
171
- **For larger blocks (e.g., 4 transactions):**
172
-
173
- ```
174
- Level 0: [Tx A] [Tx B] [Tx C] [Tx D]
175
- | | | |
176
- Level 1: [Hash(A+B)] [Hash(C+D)]
177
- | |
178
- Level 2: [Hash(AB + CD)]
179
- ```
180
-
181
- This tree structure allows you to prove any transaction's inclusion with only `log₂(n)` hashes, making verification extremely efficient even for blocks with millions of transactions.
182
-
183
- ## Verifying Merkle Proofs
184
-
185
- Verify that a transaction is included in a block using a chain tracker:
186
-
187
- ```typescript
188
- import { MerklePath, WhatsOnChain } from '@bsv/sdk'
189
-
190
- async function runMerkleVerificationExample() {
191
- // Create a simple merkle path for demonstration
192
- // This is a 2-transaction block example from BSV Technical Standards
193
- const blockHeight = 850000
194
- const merklePath = new MerklePath(blockHeight, [
195
- [
196
- { offset: 0, hash: 'ffeff11c25cde7c06d407490d81ef4d0db64aad6ab3d14393530701561a465ef', txid: true },
197
- { offset: 1, hash: 'b9ef07a62553ef8b0898a79c291b92c60f7932260888bde0dab2dd2610d8668e' }
198
- ]
199
- ])
200
-
201
- // Example transaction ID
202
- const txid = 'ffeff11c25cde7c06d407490d81ef4d0db64aad6ab3d14393530701561a465ef'
203
-
204
- // Create a chain tracker for mainnet
205
- const chainTracker = new WhatsOnChain('main')
206
-
207
- try {
208
- // Compute the merkle root (this works with our demonstration data)
209
- const merkleRoot = merklePath.computeRoot(txid)
210
- console.log('Computed merkle root:', merkleRoot)
211
-
212
- // Verify the merkle proof (this will return false for our demo data)
213
- const isValid = await merklePath.verify(txid, chainTracker)
214
- console.log('Merkle proof valid:', isValid)
215
-
216
- // Note: This returns false because our example uses demonstration data
217
- // rather than real blockchain merkle proof data
218
- if (!isValid) {
219
- console.log('ℹ️ This is expected - our example uses synthetic data for learning purposes')
220
- console.log(' Real applications receive merkle paths from BEEF structures or blockchain services')
221
- }
222
- } catch (error) {
223
- console.error('Error verifying merkle proof:', error)
224
- }
225
- }
226
-
227
- // Run the example
228
- runMerkleVerificationExample().catch(console.error)
229
- ```
230
-
231
- ## Chain Trackers
232
-
233
- Chain trackers verify that merkle roots are valid for specific block heights. The SDK provides the `WhatsOnChain` implementation:
234
-
235
- ### Using WhatsOnChain Chain Tracker
236
-
237
- ```typescript
238
- import { WhatsOnChain } from '@bsv/sdk'
239
-
240
- async function runChainTrackerExample() {
241
- // Mainnet chain tracker
242
- const mainnetTracker = new WhatsOnChain('main')
243
-
244
- // Testnet chain tracker
245
- const testnetTracker = new WhatsOnChain('test', {
246
- apiKey: 'your-api-key' // Optional for higher rate limits
247
- })
248
-
249
- try {
250
- // Check current blockchain height
251
- const currentHeight = await mainnetTracker.currentHeight()
252
- console.log('Current block height:', currentHeight)
253
-
254
- // Verify a merkle root for a specific height
255
- const isValidRoot = await mainnetTracker.isValidRootForHeight(
256
- 'merkle-root-hex',
257
- 850000
258
- )
259
- console.log('Valid merkle root:', isValidRoot)
260
- console.log('NOTE - this is expected to be false, as our example uses demonstration data')
261
- } catch (error) {
262
- console.error('Chain tracker error:', error)
263
- }
264
- }
265
-
266
- // Run the example
267
- runChainTrackerExample().catch(console.error)
268
- ```
269
-
270
- ## Transaction Verification with SPV
271
-
272
- The `Transaction.verify()` method performs complete SPV verification:
273
-
274
- ### Basic Transaction Verification
275
-
276
- ```typescript
277
- import { Transaction, WhatsOnChain, SatoshisPerKilobyte } from '@bsv/sdk'
278
-
279
- async function runTransactionVerificationExample() {
280
- // Create transaction from BEEF data
281
- const beefHex = 'your-beef-hex-data'
282
- const transaction = Transaction.fromHexBEEF(beefHex)
283
-
284
- // Set up chain tracker and fee model
285
- const chainTracker = new WhatsOnChain('main')
286
- const feeModel = new SatoshisPerKilobyte(1)
287
-
288
- // Verify the transaction
289
- try {
290
- const isValid = await transaction.verify(chainTracker, feeModel)
291
- console.log('Transaction valid:', isValid)
292
- console.log('NOTE - this is expected to be false, as our example uses demonstration data')
293
- } catch (error) {
294
- console.error('Verification failed:', error.message)
295
- }
296
- }
297
-
298
- // Run the example
299
- runTransactionVerificationExample().catch(console.error)
300
- ```
301
-
302
- ### Scripts-Only Verification
303
-
304
- ```typescript
305
- async function runScriptsOnlyVerificationExample() {
306
- // Assuming you have a transaction from previous example
307
- const beefHex = 'your-beef-hex-data'
308
- const transaction = Transaction.fromHexBEEF(beefHex)
309
-
310
- try {
311
- // Verify only scripts without checking block headers
312
- const isScriptValid = await transaction.verify('scripts only')
313
- console.log('Scripts valid:', isScriptValid)
314
- } catch (error) {
315
- console.error('Script verification failed:', error.message)
316
- }
317
- }
318
-
319
- // Run the example
320
- runScriptsOnlyVerificationExample().catch(console.error)
321
- ```
322
-
323
- ### Working with BEEF Structures
324
-
325
- BEEF (BRC-62) provides an efficient format for SPV data:
326
-
327
- ### Creating BEEF from Transaction
328
-
329
- ```typescript
330
- // Create a transaction with inputs and merkle proofs
331
- const tx = new Transaction()
332
- // ... add inputs and outputs ...
333
-
334
- // Convert to BEEF format
335
- const beefData = tx.toBEEF()
336
- const beefHex = Buffer.from(beefData).toString('hex')
337
-
338
- console.log('BEEF hex:', beefHex)
339
- ```
340
-
341
- ### Parsing BEEF Data
342
-
343
- ```typescript
344
- // Parse BEEF structure
345
- const transaction = Transaction.fromHexBEEF(beefHex)
346
-
347
- console.log('Transaction ID:', Buffer.from(transaction.id()).toString('hex'))
348
- console.log('Input count:', transaction.inputs.length)
349
- console.log('Output count:', transaction.outputs.length)
350
-
351
- // Check if merkle paths are included
352
- transaction.inputs.forEach((input, index) => {
353
- if (input.sourceTransaction?.merklePath) {
354
- console.log(`Input ${index} has merkle proof at height:`,
355
- input.sourceTransaction.merklePath.blockHeight)
356
- }
357
- })
358
- ```
359
-
360
- ## Practical Example: Payment Verification
361
-
362
- Let's create a complete example that verifies a payment transaction:
363
-
364
- ```typescript
365
- import {
366
- Transaction,
367
- WhatsOnChain,
368
- SatoshisPerKilobyte,
369
- PrivateKey,
370
- P2PKH
371
- } from '@bsv/sdk'
372
-
373
- async function verifyPayment(beefHex: string): Promise<boolean> {
374
- try {
375
- // Parse the BEEF transaction
376
- const transaction = Transaction.fromHexBEEF(beefHex)
377
-
378
- // Set up verification components
379
- const chainTracker = new WhatsOnChain('main')
380
-
381
- // Perform SPV verification
382
- const isValid = await transaction.verify(chainTracker)
383
-
384
- if (isValid) {
385
- console.log('✅ Payment verified successfully!')
386
-
387
- // Extract payment details
388
- const txid = Buffer.from(transaction.id()).toString('hex')
389
- console.log('Transaction ID:', txid)
390
-
391
- // Check outputs for payment amounts
392
- transaction.outputs.forEach((output, index) => {
393
- console.log(`Output ${index}: ${output.satoshis} satoshis`)
394
-
395
- // Check if it's a P2PKH output (OP_DUP OP_HASH160 <20-byte-hash> OP_EQUALVERIFY OP_CHECKSIG)
396
- try {
397
- const script = output.lockingScript
398
- const chunks = script.chunks
399
- if (chunks.length === 5 &&
400
- chunks[0].op === 118 && // OP_DUP
401
- chunks[1].op === 169 && // OP_HASH160
402
- chunks[2].data && chunks[2].data.length === 20 &&
403
- chunks[3].op === 136 && // OP_EQUALVERIFY
404
- chunks[4].op === 172) { // OP_CHECKSIG
405
- const pubKeyHash = Buffer.from(chunks[2].data).toString('hex')
406
- console.log(` → P2PKH address hash: ${pubKeyHash}`)
407
- } else {
408
- console.log(` → Custom script output`)
409
- }
410
- } catch {
411
- console.log(` → Custom script output`)
412
- }
413
- })
414
-
415
- return true
416
- } else {
417
- console.log('❌ Payment verification failed')
418
- return false
419
- }
420
- } catch (error) {
421
- console.error('Verification error:', (error as Error).message)
422
- return false
423
- }
424
- }
425
-
426
- // Example usage
427
- const exampleBEEF = '0100beef01fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f785dd7de98eed895dbedfe4e5bc70d1502ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e010b00bc4ff395efd11719b277694cface5aa50d085a0bb81f613f70313acd28cf4557010400574b2d9142b8d28b61d88e3b2c3f44d858411356b49a28a4643b6d1a6a092a5201030051a05fc84d531b5d250c23f4f886f6812f9fe3f402d61607f977b4ecd2701c19010000fd781529d58fc2523cf396a7f25440b409857e7e221766c57214b1d38c7b481f01010062f542f45ea3660f86c013ced80534cb5fd4c19d66c56e7e8c5d4bf2d40acc5e010100b121e91836fd7cd5102b654e9f72f3cf6fdbfd0b161c53a9c54b12c841126331020100000001cd4e4cac3c7b56920d1e7655e7e260d31f29d9a388d04910f1bbd72304a79029010000006b483045022100e75279a205a547c445719420aa3138bf14743e3f42618e5f86a19bde14bb95f7022064777d34776b05d816daf1699493fcdf2ef5a5ab1ad710d9c97bfb5b8f7cef3641210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000001000100000001ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9aa2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013c660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000000'
428
-
429
- async function runPaymentVerificationExample() {
430
- console.log('=== Payment Verification Example ===\n')
431
-
432
- // Verify the payment
433
- const isValid = await verifyPayment(exampleBEEF)
434
-
435
- if (isValid) {
436
- console.log('\n✅ Payment successfully verified using SPV!')
437
- console.log('This transaction can be trusted without downloading the full blockchain.')
438
- } else {
439
- console.log('\n❌ Payment verification failed!')
440
- console.log('This transaction should not be trusted.')
441
- }
442
-
443
- console.log('\n=== Payment Processing Workflow ===')
444
- console.log('1. Customer sends BEEF-encoded transaction')
445
- console.log('2. Merchant verifies transaction using SPV')
446
- console.log('3. If valid, merchant can safely accept payment')
447
- console.log('4. No need to wait for confirmations or run full node')
448
- }
449
-
450
- runPaymentVerificationExample().catch(console.error)
451
- ```
452
-
453
- ## Advanced SPV Patterns
454
-
455
- ### Batch Verification
456
-
457
- Verify multiple transactions efficiently:
458
-
459
- ```typescript
460
- async function verifyMultipleTransactions(beefHexArray: string[]): Promise<boolean[]> {
461
- const chainTracker = new WhatsOnChain('main')
462
- const feeModel = new SatoshisPerKilobyte(1)
463
-
464
- const results = await Promise.all(
465
- beefHexArray.map(async (beefHex) => {
466
- try {
467
- const tx = Transaction.fromHexBEEF(beefHex)
468
- return await tx.verify(chainTracker, feeModel)
469
- } catch (error) {
470
- console.error('Verification failed:', error.message)
471
- return false
472
- }
473
- })
474
- )
475
-
476
- return results
477
- }
478
- ```
479
-
480
- ### Merkle Proof Validation
481
-
482
- Manually validate merkle proofs:
483
-
484
- ```typescript
485
- function validateMerkleProof(
486
- txid: string,
487
- merklePath: MerklePath,
488
- expectedRoot: string
489
- ): boolean {
490
- try {
491
- const computedRoot = merklePath.computeRoot(txid)
492
- return computedRoot === expectedRoot
493
- } catch (error) {
494
- console.error('Error computing merkle root:', error.message)
495
- return false
496
- }
497
- }
498
-
499
- // Example usage
500
- const isValidProof = validateMerkleProof(
501
- 'transaction-id',
502
- merklePath,
503
- 'expected-merkle-root'
504
- )
505
- console.log('Merkle proof valid:', isValidProof)
506
- ```
507
-
508
- ### Custom Memory Limits
509
-
510
- Control script execution memory usage:
511
-
512
- ```typescript
513
- // Verify with custom memory limit (in bytes)
514
- const isValid = await transaction.verify(
515
- chainTracker,
516
- feeModel,
517
- 1024 * 1024 // 1MB memory limit
518
- )
519
- ```
520
-
521
- ## Error Handling and Debugging
522
-
523
- ### Common Verification Errors
524
-
525
- ```typescript
526
- async function robustVerification(beefHex: string): Promise<void> {
527
- try {
528
- const transaction = Transaction.fromHexBEEF(beefHex)
529
-
530
- // Set up verification components
531
- const chainTracker = new WhatsOnChain('main')
532
-
533
- console.log('🔍 Starting transaction verification...')
534
- console.log('Transaction ID:', Buffer.from(transaction.id()).toString('hex'))
535
-
536
- // Perform SPV verification
537
- const isValid = await transaction.verify(chainTracker)
538
-
539
- if (!isValid) {
540
- console.log('❌ Transaction verification failed. Checking components...')
541
-
542
- // Check individual merkle proofs
543
- for (let i = 0; i < transaction.inputs.length; i++) {
544
- const input = transaction.inputs[i]
545
- if (input.sourceTransaction?.merklePath) {
546
- try {
547
- const sourceTxid = Buffer.from(input.sourceTransaction.id()).toString('hex')
548
- const proofValid = await input.sourceTransaction.merklePath.verify(
549
- sourceTxid,
550
- chainTracker
551
- )
552
- console.log(` Input ${i} merkle proof: ${proofValid ? '✅' : '❌'}`)
553
- } catch (err) {
554
- console.log(` Input ${i} merkle proof: ❌ (${(err as Error).message})`)
555
- }
556
- } else {
557
- console.log(` Input ${i}: No merkle path provided`)
558
- }
559
- }
560
-
561
- // Try scripts-only verification
562
- try {
563
- const scriptsValid = await transaction.verify('scripts only')
564
- console.log(' Scripts validation:', scriptsValid ? '✅' : '❌')
565
- } catch (err) {
566
- console.log(' Scripts validation: ❌ (', (err as Error).message, ')')
567
- }
568
- } else {
569
- console.log('✅ Transaction verification successful!')
570
- }
571
-
572
- } catch (error) {
573
- const errorMessage = (error as Error).message
574
-
575
- console.log('❌ Verification failed with error:')
576
-
577
- if (errorMessage.includes('Missing source transaction')) {
578
- console.error(' → BEEF structure incomplete - missing input transactions')
579
- console.error(' → Solution: Ensure all input transactions are included in BEEF')
580
- } else if (errorMessage.includes('Merkle root')) {
581
- console.error(' → Merkle proof verification failed')
582
- console.error(' → Solution: Check merkle path data and chain tracker connectivity')
583
- } else if (errorMessage.includes('script')) {
584
- console.error(' → Script validation failed')
585
- console.error(' → Solution: Check unlocking scripts and signature validity')
586
- } else if (errorMessage.includes('BEEF')) {
587
- console.error(' → BEEF parsing error')
588
- console.error(' → Solution: Verify BEEF format and encoding')
589
- } else {
590
- console.error(' → Unexpected error:', errorMessage)
591
- }
592
- }
593
- }
594
- ```
595
-
596
- ### Network-Specific Verification
597
-
598
- ```typescript
599
- async function verifyOnNetwork(beefHex: string, network: 'main' | 'test'): Promise<boolean> {
600
- const chainTracker = new WhatsOnChain(network)
601
- const transaction = Transaction.fromHexBEEF(beefHex)
602
-
603
- console.log(`Verifying on ${network}net...`)
604
- return await transaction.verify(chainTracker)
605
- }
606
- ```
607
-
608
- ## Best Practices
609
-
610
- ### 1. Chain Tracker Selection
611
-
612
- ```typescript
613
- // Production: Use WhatsOnChain with API key
614
- const productionTracker = new WhatsOnChain('main', {
615
- apiKey: process.env.WHATSONCHAIN_API_KEY
616
- })
617
-
618
- // Development: Use testnet
619
- const devTracker = new WhatsOnChain('test')
620
-
621
- // Testing: Use mock tracker
622
- const testTracker: ChainTracker = {
623
- async isValidRootForHeight() { return true },
624
- async currentHeight() { return 850000 }
625
- }
626
- ```
627
-
628
- ### 2. Error Recovery
629
-
630
- ```typescript
631
- async function verifyWithRetry(beefHex: string, maxRetries = 3): Promise<boolean> {
632
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
633
- try {
634
- const transaction = Transaction.fromHexBEEF(beefHex)
635
- const chainTracker = new WhatsOnChain('main')
636
-
637
- return await transaction.verify(chainTracker)
638
- } catch (error) {
639
- console.log(`Attempt ${attempt} failed:`, (error as Error).message)
640
-
641
- if (attempt === maxRetries) {
642
- throw error
643
- }
644
-
645
- // Wait before retry
646
- await new Promise(resolve => setTimeout(resolve, 1000 * attempt))
647
- }
648
- }
649
-
650
- return false
651
- }
652
- ```
653
-
654
- ## Summary
655
-
656
- SPV and merkle proof verification enable lightweight Bitcoin clients to verify transactions without storing the full blockchain. The BSV TypeScript SDK provides comprehensive tools for:
657
-
658
- - **MerklePath**: Computing and verifying merkle proofs
659
- - **ChainTracker**: Validating merkle roots against block headers
660
- - **Transaction.verify()**: Complete SPV verification
661
- - **BEEF**: Efficient SPV data structures
662
-
663
- Key takeaways:
664
-
665
- - SPV trades storage for bandwidth and computation
666
- - Merkle proofs provide cryptographic inclusion proofs
667
- - Chain trackers ensure merkle roots are valid
668
- - BEEF structures optimize SPV data transmission
669
- - Always use trusted chain trackers in production
670
- - Implement proper error handling and retry logic
671
-
672
- This foundation enables building lightweight Bitcoin applications that can verify payments and transactions without running a full node.
673
-
674
- Understanding of `WalletClient` usage is also important for building robust applications. `WalletClient` provides high-level transaction verification, but understanding SPV verification gives you the ability to build lightweight applications that can verify transactions without downloading the entire blockchain.
675
-
676
- ## SPV vs Full Node vs `WalletClient` Verification
677
-
678
- | Method | `WalletClient` | SPV | Full Node |
679
- | --- | --- | --- | --- |
680
- | **Storage** | High | Low | High |
681
- | **Bandwidth** | Low | High | Low |
682
- | **Verification** | High-level | Low-level | High-level |
683
- | **Security** | High | High | High |
684
-
685
- The `WalletClient` approach is recommended for most applications, while SPV verification is valuable for specialized lightweight applications.