Status: Fully implemented and tested (October 2025)
Implemented complete Golomb-Coded Sets (GCS) for client-side block filtering:
Implementation Details:
- GCS Filter Construction: Extracts scripts from blocks per BIP 158 specification
- Previous output scripts (scriptPubKeys being spent)
- Current output scriptPubKeys (except OP_RETURN)
- Automatic deduplication and lexicographic sorting
- NO input outpoints (key bug fix - basic filters don't include these)
- Golomb Encoding: Unary quotient + P-bit remainder (P=19, M=784931)
- Hash-to-Range: Multiply-and-shift technique (
fastReduction) instead of modulo- 64×64→128 bit multiplication returning upper 64 bits
- Avoids expensive modulo while maintaining uniform distribution
- This was the ROOT CAUSE of initial test failures
- SipHash-2-4: Keyed hash function using first 16 bytes of block hash (little-endian)
- BitStream: MSB-first bit-level I/O for compact encoding/decoding
- Lenient Script Parsing: Handle malformed scripts by storing raw bytes
script.ReadScriptBytes()reads without parsingTxOut.RawScriptBytes()returns raw bytes even if parse failed
- Filter Serialization: VarInt N (item count) + Golomb-coded deltas
Key Bug Fixes:
- Wrong hash-to-range algorithm - Used modulo instead of multiply-and-shift
- Researched btcd implementation to discover fastReduction technique
- Included outpoints incorrectly - Basic filters only include scripts, not outpoints
- Rejected malformed scripts - Some test vectors have intentionally unparseable scripts
- Script serialization corruption - Created
RawBytes()to avoid varint prefix issues
Test Results: All 10 BIP 158 official test vectors passing
- Genesis block
- Standard blocks (2, 3)
- Non-standard OP_RETURN outputs
- Empty output scripts
- Duplicate pushdata (malformed)
- Unparseable coinbase (malformed)
- Witness data transactions
- Empty data blocks
P2P Message Types Implemented (6 new messages):
getcfilters,cfilter- Request/receive compact filtersgetcfheaders,cfheaders- Request/receive filter headersgetcfcheckpt,cfcheckpt- Request/receive filter checkpoints
Files:
internal/network/gcs.go- GCS implementation with fastReductioninternal/network/gcs_test.go- BIP 158 test vectorsinternal/block/block.go-ExtractBasicFilterItems()methodinternal/script/script.go-ReadScriptBytes()andRawBytes()methodsinternal/transactions/txinputs.go- LenientParseTxOut()internal/encoding/bitstream.go- Bit-level I/O
Next Task: Create TestSPVFlow using BIP 158 filters instead of BIP 37 bloom filters
Status: Fully implemented and tested
Implemented complete bech32 encoding for native SegWit addresses:
- P2WPKH addresses (bc1q... for mainnet, tb1q... for testnet)
- P2WSH addresses (bc1q... with 32-byte witness programs)
- Full BIP 173 compliance with official test vectors
- Polymod checksum calculation
- 8-bit to 5-bit data conversion
- HRP (human-readable part) expansion
Key Bug Fix: Witness version is already 5-bit compatible (0-16), so it's added directly to the data array rather than being converted from 8-bit.
Files:
internal/address/bech32.go- Core bech32 encoding implementationinternal/address/address.go- Address type and generation functionsinternal/address/address_test.go- BIP 173 test vectors
Status: Complete migration across codebase
Refactored address generation to use a unified internal/address package:
Old API (deprecated):
addr := script.Address(testnet bool) string // Returns string, boolean flags
addr := publicKey.Address(compressed, testnet bool) stringNew API (current):
addrObj, err := script.AddressV2(network address.Network) (*address.Address, error)
addrObj, err := address.FromPublicKey(pubkey []byte, addrType address.AddrType, network address.Network)
addrObj, err := address.FromHash160(hash160 []byte, addrType address.AddrType, network address.Network)
addrObj, err := address.FromWitnessProgram(version byte, program []byte, network address.Network)Benefits:
- Type-safe
address.Networkenum (MAINNET, TESTNET) instead of boolean flags - Supports all address types: P2PKH, P2SH, P2WPKH, P2WSH
- Centralized address logic in
internal/addresspackage - Returns structured
Addressobject with.Stringproperty - Proper error handling
Migration Complete:
- ✅ All
script.Address()calls replaced withscript.AddressV2() - ✅ Code examples in README.md updated
- ✅ No remaining deprecated API usage in codebase
Replace the existing BIP 37 bloom filter-based SPV test with a BIP 158 compact block filter implementation.
Goal: Implement client-side block filtering using GCS filters instead of bloom filters
Why This Matters:
- BIP 37 bloom filters have privacy issues (server knows what you're looking for)
- BIP 158 filters are downloaded by the client, so server doesn't learn what you're searching for
- Filters are deterministic and can be cached
- Better privacy model for light clients
Tasks:
- Implement BIP 157 P2P protocol messages (already have message types defined)
- Create test that downloads compact filters from a BIP 157-enabled node
- Match filter contents against target addresses/scripts
- Request full blocks for matches
- Verify transactions found
Files to Modify:
internal/network/spv_test.go- Create newTestSPVFlowWithCompactFilters- May need to implement message serialization for the 6 BIP 157 message types
Reference:
- Current bloom filter test:
internal/network/spv_test.go(TestSPVFlow) - BIP 157: https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki
- GCS implementation:
internal/network/gcs.go