commit cecfa8c7a01795ebd39916a4c0b3e03e33b00c6c
parent 5931fdd136928ba8eb85af4a5a71579dc0a62189
Author: Jared Tobin <jared@jtobin.io>
Date: Sun, 25 Jan 2026 16:08:21 +0400
Flesh out README with overview and usage examples
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat:
| M | README.md | | | 60 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
1 file changed, 58 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
@@ -1,14 +1,70 @@
# ppad-bolt9
-A Haskell implementation of Lightning Network feature flags (BOLT #9).
+A Haskell implementation of Lightning Network feature flags (BOLT #9),
+providing type-safe feature vectors with validation and wire format
+encoding.
+
+## Overview
+
+BOLT #9 defines feature flags that Lightning nodes advertise to indicate
+support for optional protocol features. Features are represented as bit
+positions in a variable-length bit vector:
+
+- **Even bits** (0, 2, 4, ...) indicate *required* support
+- **Odd bits** (1, 3, 5, ...) indicate *optional* support
+
+For example, `basic_mpp` (multi-part payments) uses bits 16/17. A node
+setting bit 16 requires peers to support it; bit 17 indicates optional
+support.
## Usage
A sample GHCi session:
```
+ > :set -XOverloadedStrings
> import Lightning.Protocol.BOLT9
- > -- TODO
+ > import Data.Maybe (fromJust)
+ >
+ > -- Look up features by name
+ > let mpp = fromJust $ featureByName "basic_mpp"
+ > featureBaseBit mpp
+ 16
+ > featureDependencies mpp
+ ["payment_secret"]
+ >
+ > -- Build a feature vector with optional basic_mpp support
+ > let fv = setFeature mpp False empty
+ > hasFeature mpp fv
+ Just False
+ >
+ > -- Validation catches missing dependencies
+ > validateLocal Init fv
+ Left [MissingDependency "basic_mpp" "payment_secret"]
+ >
+ > -- Add the dependency
+ > let ps = fromJust $ featureByName "payment_secret"
+ > let fv' = setFeature ps False $ setFeature mpp False empty
+ > validateLocal Init fv'
+ Right ()
+ >
+ > -- Render to wire format (compact, no leading zeros)
+ > render fv'
+ "\STX\128"
+ >
+ > -- Parse from wire format
+ > let fv'' = parse "\STX\128"
+ > listFeatures fv''
+ [(Feature {featureName = "payment_secret", ...},False),
+ (Feature {featureName = "basic_mpp", ...},False)]
+ >
+ > -- Remote validation: unknown optional bits are OK
+ > validateRemote Init (setBit 201 empty)
+ Right ()
+ >
+ > -- But unknown required bits are rejected
+ > validateRemote Init (setBit 200 empty)
+ Left [UnknownRequiredBit 200]
```
## Documentation