|
| 1 | +# SPV Wallet with Compact Filters (BIP 157/158) |
| 2 | + |
| 3 | +This guide explains how the filter-based SPV wallet implementation works and how to use it. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The system implements a lightweight SPV (Simplified Payment Verification) wallet using compact block filters as specified in BIP 157 and BIP 158. This approach provides: |
| 8 | + |
| 9 | +- **95% bandwidth savings** compared to downloading full blocks |
| 10 | +- **Privacy**: Servers don't learn which addresses belong to the wallet |
| 11 | +- **Efficiency**: Only download blocks containing relevant transactions |
| 12 | +- **Security**: Full SPV validation with merkle proofs |
| 13 | + |
| 14 | +## Architecture |
| 15 | + |
| 16 | +``` |
| 17 | +┌─────────────────────────────────────────────────────┐ |
| 18 | +│ FilterSPVClient │ |
| 19 | +│ │ |
| 20 | +│ ┌─────────────────┐ ┌──────────────────┐ │ |
| 21 | +│ │ FilterClient │◄──────►│ WalletManager │ │ |
| 22 | +│ │ │ │ │ │ |
| 23 | +│ │ - Check filters │ │ - Manage wallets │ │ |
| 24 | +│ │ - Fetch blocks │ │ - Track UTXOs │ │ |
| 25 | +│ │ - Process txs │ │ - Update balances │ │ |
| 26 | +│ └────────┬────────┘ └──────────────────┘ │ |
| 27 | +│ │ │ |
| 28 | +│ ▼ │ |
| 29 | +│ ┌─────────────────┐ │ |
| 30 | +│ │ Network Layer │ │ |
| 31 | +│ │ │ │ |
| 32 | +│ │ - P2P Protocol │ │ |
| 33 | +│ │ - Fetch filters │ │ |
| 34 | +│ │ - Fetch blocks │ │ |
| 35 | +│ └─────────────────┘ │ |
| 36 | +└─────────────────────────────────────────────────────┘ |
| 37 | +``` |
| 38 | + |
| 39 | +## Workflow |
| 40 | + |
| 41 | +### 1. Initial Setup |
| 42 | + |
| 43 | +```rust |
| 44 | +use key_wallet_manager::{FilterSPVClient, Network}; |
| 45 | + |
| 46 | +// Create SPV client |
| 47 | +let mut spv_client = FilterSPVClient::new(Network::Testnet); |
| 48 | + |
| 49 | +// Add wallet from mnemonic |
| 50 | +spv_client.add_wallet( |
| 51 | + "main_wallet".to_string(), |
| 52 | + "My Wallet".to_string(), |
| 53 | + mnemonic, |
| 54 | + passphrase, |
| 55 | + Some(birth_height), // Start scanning from this height |
| 56 | +)?; |
| 57 | +``` |
| 58 | + |
| 59 | +### 2. Filter Processing Flow |
| 60 | + |
| 61 | +``` |
| 62 | +For each new block: |
| 63 | + 1. Receive compact filter from network |
| 64 | + 2. Check if filter matches any of: |
| 65 | + - Our addresses (watched scripts) |
| 66 | + - Our UTXOs (watched outpoints) |
| 67 | + 3. If match found: |
| 68 | + - Fetch full block |
| 69 | + - Process transactions |
| 70 | + - Update wallet state |
| 71 | + 4. If no match: |
| 72 | + - Skip block (save bandwidth) |
| 73 | +``` |
| 74 | + |
| 75 | +### 3. Filter Matching |
| 76 | + |
| 77 | +The system watches two types of data: |
| 78 | + |
| 79 | +#### Watched Scripts (Addresses) |
| 80 | +- All addresses generated for the wallet |
| 81 | +- Automatically updated when new addresses are created |
| 82 | +- Matched against transaction outputs |
| 83 | + |
| 84 | +#### Watched Outpoints (UTXOs) |
| 85 | +- All unspent transaction outputs owned by the wallet |
| 86 | +- Automatically updated when receiving/spending |
| 87 | +- Matched against transaction inputs (spending detection) |
| 88 | + |
| 89 | +### 4. Processing Matched Blocks |
| 90 | + |
| 91 | +When a filter matches, the system: |
| 92 | + |
| 93 | +1. **Fetches the full block** from the network |
| 94 | +2. **Processes each transaction**: |
| 95 | + - Check outputs for payments to our addresses |
| 96 | + - Check inputs for spending of our UTXOs |
| 97 | +3. **Updates wallet state**: |
| 98 | + - Add new UTXOs |
| 99 | + - Remove spent UTXOs |
| 100 | + - Update balances |
| 101 | + - Record transaction history |
| 102 | + |
| 103 | +## Implementation Details |
| 104 | + |
| 105 | +### Compact Filters (BIP 158) |
| 106 | + |
| 107 | +Compact filters use Golomb-Rice coding to create a probabilistic data structure: |
| 108 | + |
| 109 | +- **Size**: ~1/20th of the full block |
| 110 | +- **False positive rate**: 1 in 784,931 |
| 111 | +- **No false negatives**: If your transaction is in the block, the filter will match |
| 112 | + |
| 113 | +### Filter Chain Validation |
| 114 | + |
| 115 | +The system maintains a chain of filter headers for validation: |
| 116 | + |
| 117 | +```rust |
| 118 | +FilterHeader { |
| 119 | + filter_type: FilterType::Basic, |
| 120 | + block_hash: [u8; 32], |
| 121 | + prev_header: [u8; 32], // Hash of previous filter header |
| 122 | + filter_hash: [u8; 32], // Hash of this block's filter |
| 123 | +} |
| 124 | +``` |
| 125 | + |
| 126 | +### Address Gap Limit |
| 127 | + |
| 128 | +The wallet implements BIP 44 gap limit handling: |
| 129 | + |
| 130 | +- Default gap limit: 20 addresses |
| 131 | +- Automatically generates new addresses when used |
| 132 | +- Tracks both receive and change addresses separately |
| 133 | + |
| 134 | +## Usage Example |
| 135 | + |
| 136 | +```rust |
| 137 | +// Process incoming filter |
| 138 | +let filter = receive_filter_from_network(); |
| 139 | +let block_hash = BlockHash::from_slice(&filter.block_hash)?; |
| 140 | + |
| 141 | +// Check if we need this block |
| 142 | +match spv_client.process_new_filter(height, block_hash, filter)? { |
| 143 | + Some(result) => { |
| 144 | + println!("Found {} relevant transactions", result.relevant_txs.len()); |
| 145 | + println!("New UTXOs: {}", result.new_outpoints.len()); |
| 146 | + println!("Spent UTXOs: {}", result.spent_outpoints.len()); |
| 147 | + } |
| 148 | + None => { |
| 149 | + println!("Block not relevant, skipping"); |
| 150 | + } |
| 151 | +} |
| 152 | + |
| 153 | +// Check balance |
| 154 | +let (confirmed, unconfirmed) = spv_client.get_balance("main_wallet")?; |
| 155 | +println!("Balance: {} confirmed, {} unconfirmed", confirmed, unconfirmed); |
| 156 | +``` |
| 157 | + |
| 158 | +## Network Integration |
| 159 | + |
| 160 | +To integrate with a P2P network, implement the trait interfaces: |
| 161 | + |
| 162 | +```rust |
| 163 | +impl BlockFetcher for YourNetworkClient { |
| 164 | + fn fetch_block(&mut self, block_hash: &BlockHash) -> Result<Block, FetchError> { |
| 165 | + // Send getdata message |
| 166 | + // Wait for block response |
| 167 | + // Return parsed block |
| 168 | + } |
| 169 | +} |
| 170 | + |
| 171 | +impl FilterFetcher for YourNetworkClient { |
| 172 | + fn fetch_filter(&mut self, block_hash: &BlockHash) -> Result<CompactFilter, FetchError> { |
| 173 | + // Send getcfilters message |
| 174 | + // Wait for cfilter response |
| 175 | + // Return parsed filter |
| 176 | + } |
| 177 | +} |
| 178 | +``` |
| 179 | + |
| 180 | +## Performance Characteristics |
| 181 | + |
| 182 | +### Bandwidth Usage |
| 183 | + |
| 184 | +| Method | Data Downloaded | Privacy | Speed | |
| 185 | +|--------|----------------|---------|-------| |
| 186 | +| Full Node | 100% of blocks | Full | Slow | |
| 187 | +| Traditional SPV | 100% of blocks with txs | Low | Medium | |
| 188 | +| **Compact Filters** | ~5% of blocks | High | Fast | |
| 189 | + |
| 190 | +### Storage Requirements |
| 191 | + |
| 192 | +- **Headers**: ~4 MB per year |
| 193 | +- **Filters**: ~50 MB per year |
| 194 | +- **Relevant blocks**: Only blocks with your transactions |
| 195 | +- **Total**: <100 MB for typical wallet |
| 196 | + |
| 197 | +## Security Considerations |
| 198 | + |
| 199 | +1. **SPV Security**: Validates proof-of-work and merkle proofs |
| 200 | +2. **Privacy**: Server doesn't know which addresses are yours |
| 201 | +3. **Filter Validation**: Validates filter chain to prevent omission attacks |
| 202 | +4. **Multiple Peers**: Should connect to multiple peers for security |
| 203 | + |
| 204 | +## Testing |
| 205 | + |
| 206 | +Run the example: |
| 207 | + |
| 208 | +```bash |
| 209 | +cargo run --example spv_wallet |
| 210 | +``` |
| 211 | + |
| 212 | +Run tests: |
| 213 | + |
| 214 | +```bash |
| 215 | +cargo test -p key-wallet-manager |
| 216 | +``` |
| 217 | + |
| 218 | +## Future Enhancements |
| 219 | + |
| 220 | +- [ ] Batch filter requests for efficiency |
| 221 | +- [ ] Filter caching and persistence |
| 222 | +- [ ] Peer rotation for privacy |
| 223 | +- [ ] Tor/proxy support |
| 224 | +- [ ] Lightning Network integration |
| 225 | +- [ ] Hardware wallet support |
| 226 | + |
| 227 | +## References |
| 228 | + |
| 229 | +- [BIP 157: Client Side Block Filtering](https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki) |
| 230 | +- [BIP 158: Compact Block Filters](https://github.com/bitcoin/bips/blob/master/bip-0158.mediawiki) |
| 231 | +- [Neutrino Protocol](https://github.com/lightninglabs/neutrino) |
0 commit comments