bolt2

Lightning peer protocol, per BOLT #2 (docs.ppad.tech/bolt2).
git clone git://git.ppad.tech/bolt2.git
Log | Files | Refs | README | LICENSE

commit 367ebbd8a17c670bc0b249ec4520ebb3ac869c00
parent 9fe981110faec0b53206fcc8ef0496cb54ed848a
Author: Jared Tobin <jared@jtobin.io>
Date:   Sun, 19 Apr 2026 12:01:19 +0800

lib: use shared types from ppad-bolt1

Replace locally-defined types with imports from
Lightning.Protocol.BOLT1.Prim:

  ChannelId, Signature, Point, PaymentHash, PaymentPreimage,
  ChainHash, ShortChannelId, Satoshi, MilliSatoshi

Renames:
  - Satoshis -> Satoshi, MilliSatoshis -> MilliSatoshi
  - satoshisToMsat -> satToMsat, msatToSatoshis -> msatToSat
  - Secret -> PerCommitmentSecret
  - secretLen -> perCommitmentSecretLen

Types.hs re-exports all shared types for downstream
compatibility. OnionPacket, ScriptPubKey, FeatureBits remain
bolt2-local (genuinely different from other bolts).

Diffstat:
Mbench/Main.hs | 24++++++++++++------------
Mbench/Weight.hs | 24++++++++++++------------
Mflake.lock | 8++++----
Mlib/Lightning/Protocol/BOLT2/Codec.hs | 160++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mlib/Lightning/Protocol/BOLT2/Messages.hs | 50+++++++++++++++++++++++++-------------------------
Mlib/Lightning/Protocol/BOLT2/Types.hs | 346++++++++++---------------------------------------------------------------------
Mtest/Main.hs | 111++++++++++++++++++++++++++++++++++++++++---------------------------------------
7 files changed, 232 insertions(+), 491 deletions(-)

diff --git a/bench/Main.hs b/bench/Main.hs @@ -84,12 +84,12 @@ testOpenChannel :: OpenChannel testOpenChannel = OpenChannel { openChannelChainHash = testChainHash , openChannelTempChannelId = testChannelId - , openChannelFundingSatoshis = Satoshis 1000000 - , openChannelPushMsat = MilliSatoshis 0 - , openChannelDustLimitSatoshis = Satoshis 546 - , openChannelMaxHtlcValueInFlight = MilliSatoshis 1000000000 - , openChannelChannelReserveSat = Satoshis 10000 - , openChannelHtlcMinimumMsat = MilliSatoshis 1000 + , openChannelFundingSatoshi = Satoshi 1000000 + , openChannelPushMsat = MilliSatoshi 0 + , openChannelDustLimitSatoshi = Satoshi 546 + , openChannelMaxHtlcValueInFlight = MilliSatoshi 1000000000 + , openChannelChannelReserveSat = Satoshi 10000 + , openChannelHtlcMinimumMsat = MilliSatoshi 1000 , openChannelFeeratePerKw = 250 , openChannelToSelfDelay = 144 , openChannelMaxAcceptedHtlcs = 30 @@ -118,10 +118,10 @@ testOpenChannel2 = OpenChannel2 , openChannel2TempChannelId = testChannelId , openChannel2FundingFeeratePerkw = 2500 , openChannel2CommitFeeratePerkw = 250 - , openChannel2FundingSatoshis = Satoshis 1000000 - , openChannel2DustLimitSatoshis = Satoshis 546 - , openChannel2MaxHtlcValueInFlight = MilliSatoshis 1000000000 - , openChannel2HtlcMinimumMsat = MilliSatoshis 1000 + , openChannel2FundingSatoshi = Satoshi 1000000 + , openChannel2DustLimitSatoshi = Satoshi 546 + , openChannel2MaxHtlcValueInFlight = MilliSatoshi 1000000000 + , openChannel2HtlcMinimumMsat = MilliSatoshi 1000 , openChannel2ToSelfDelay = 144 , openChannel2MaxAcceptedHtlcs = 30 , openChannel2Locktime = 0 @@ -169,7 +169,7 @@ encodedTxSignatures = case encodeTxSignatures testTxSignatures of testClosingSigned :: ClosingSigned testClosingSigned = ClosingSigned { closingSignedChannelId = testChannelId - , closingSignedFeeSatoshis = Satoshis 1000 + , closingSignedFeeSatoshi = Satoshi 1000 , closingSignedSignature = testSignature , closingSignedTlvs = emptyTlvs } @@ -187,7 +187,7 @@ testUpdateAddHtlc :: UpdateAddHtlc testUpdateAddHtlc = UpdateAddHtlc { updateAddHtlcChannelId = testChannelId , updateAddHtlcId = 0 - , updateAddHtlcAmountMsat = MilliSatoshis 10000000 + , updateAddHtlcAmountMsat = MilliSatoshi 10000000 , updateAddHtlcPaymentHash = testPaymentHash , updateAddHtlcCltvExpiry = 800000 , updateAddHtlcOnionPacket = testOnionPacket diff --git a/bench/Weight.hs b/bench/Weight.hs @@ -90,12 +90,12 @@ mkOpenChannel :: ChainHash -> ChannelId -> Point -> TlvStream -> OpenChannel mkOpenChannel !ch !cid !pt !tlvs = OpenChannel { openChannelChainHash = ch , openChannelTempChannelId = cid - , openChannelFundingSatoshis = Satoshis 1000000 - , openChannelPushMsat = MilliSatoshis 0 - , openChannelDustLimitSatoshis = Satoshis 546 - , openChannelMaxHtlcValueInFlight = MilliSatoshis 1000000000 - , openChannelChannelReserveSat = Satoshis 10000 - , openChannelHtlcMinimumMsat = MilliSatoshis 1000 + , openChannelFundingSatoshi = Satoshi 1000000 + , openChannelPushMsat = MilliSatoshi 0 + , openChannelDustLimitSatoshi = Satoshi 546 + , openChannelMaxHtlcValueInFlight = MilliSatoshi 1000000000 + , openChannelChannelReserveSat = Satoshi 10000 + , openChannelHtlcMinimumMsat = MilliSatoshi 1000 , openChannelFeeratePerKw = 250 , openChannelToSelfDelay = 144 , openChannelMaxAcceptedHtlcs = 30 @@ -116,10 +116,10 @@ mkOpenChannel2 !ch !cid !pt !tlvs = OpenChannel2 , openChannel2TempChannelId = cid , openChannel2FundingFeeratePerkw = 2500 , openChannel2CommitFeeratePerkw = 250 - , openChannel2FundingSatoshis = Satoshis 1000000 - , openChannel2DustLimitSatoshis = Satoshis 546 - , openChannel2MaxHtlcValueInFlight = MilliSatoshis 1000000000 - , openChannel2HtlcMinimumMsat = MilliSatoshis 1000 + , openChannel2FundingSatoshi = Satoshi 1000000 + , openChannel2DustLimitSatoshi = Satoshi 546 + , openChannel2MaxHtlcValueInFlight = MilliSatoshi 1000000000 + , openChannel2HtlcMinimumMsat = MilliSatoshi 1000 , openChannel2ToSelfDelay = 144 , openChannel2MaxAcceptedHtlcs = 30 , openChannel2Locktime = 0 @@ -146,7 +146,7 @@ mkTxSignatures !cid !tid !ws = TxSignatures mkClosingSigned :: ChannelId -> Signature -> TlvStream -> ClosingSigned mkClosingSigned !cid !sig !tlvs = ClosingSigned { closingSignedChannelId = cid - , closingSignedFeeSatoshis = Satoshis 1000 + , closingSignedFeeSatoshi = Satoshi 1000 , closingSignedSignature = sig , closingSignedTlvs = tlvs } @@ -157,7 +157,7 @@ mkUpdateAddHtlc mkUpdateAddHtlc !cid !ph !onion !tlvs = UpdateAddHtlc { updateAddHtlcChannelId = cid , updateAddHtlcId = 0 - , updateAddHtlcAmountMsat = MilliSatoshis 10000000 + , updateAddHtlcAmountMsat = MilliSatoshi 10000000 , updateAddHtlcPaymentHash = ph , updateAddHtlcCltvExpiry = 800000 , updateAddHtlcOnionPacket = onion diff --git a/flake.lock b/flake.lock @@ -157,11 +157,11 @@ ] }, "locked": { - "lastModified": 1776481687, - "narHash": "sha256-1oT11gu84v1wEmOrigp6FTP1DIG7JkD1OVdgOCCPQFs=", + "lastModified": 1776570879, + "narHash": "sha256-XsgGBvYWL+sD7pDZoPPi4l39DE7GH7maNnhm8iUeB/E=", "ref": "master", - "rev": "0a19559d878ad6701d9d10fd08a32b736bcee662", - "revCount": 26, + "rev": "20ea43188d781368e5e64c7c646285a6b0aaeb94", + "revCount": 27, "type": "git", "url": "git://git.ppad.tech/bolt1.git" }, diff --git a/lib/Lightning/Protocol/BOLT2/Codec.hs b/lib/Lightning/Protocol/BOLT2/Codec.hs @@ -209,21 +209,21 @@ decodeU32E :: BS.ByteString -> Either DecodeError (Word32, BS.ByteString) decodeU32E !bs = maybe (Left DecodeInsufficientBytes) Right (decodeU32 bs) {-# INLINE decodeU32E #-} --- | Decode a u64 as Satoshis. -decodeSatoshis - :: BS.ByteString -> Either DecodeError (Satoshis, BS.ByteString) -decodeSatoshis !bs = do +-- | Decode a u64 as Satoshi. +decodeSatoshi + :: BS.ByteString -> Either DecodeError (Satoshi, BS.ByteString) +decodeSatoshi !bs = do (val, rest) <- maybe (Left DecodeInsufficientBytes) Right (decodeU64 bs) - Right (Satoshis val, rest) -{-# INLINE decodeSatoshis #-} + Right (Satoshi val, rest) +{-# INLINE decodeSatoshi #-} --- | Decode a u64 as MilliSatoshis. -decodeMilliSatoshis - :: BS.ByteString -> Either DecodeError (MilliSatoshis, BS.ByteString) -decodeMilliSatoshis !bs = do +-- | Decode a u64 as MilliSatoshi. +decodeMilliSatoshi + :: BS.ByteString -> Either DecodeError (MilliSatoshi, BS.ByteString) +decodeMilliSatoshi !bs = do (val, rest) <- maybe (Left DecodeInsufficientBytes) Right (decodeU64 bs) - Right (MilliSatoshis val, rest) -{-# INLINE decodeMilliSatoshis #-} + Right (MilliSatoshi val, rest) +{-# INLINE decodeMilliSatoshi #-} -- | Decode optional TLV stream from remaining bytes. decodeTlvs :: BS.ByteString -> Either DecodeError TlvStream @@ -274,15 +274,17 @@ decodeOnionPacketBytes !bs = do Right (op, rest) {-# INLINE decodeOnionPacketBytes #-} --- | Decode a Secret (32 bytes). -decodeSecretBytes - :: BS.ByteString -> Either DecodeError (Secret, BS.ByteString) -decodeSecretBytes !bs = do +-- | Decode a PerCommitmentSecret (32 bytes). +decodePerCommitmentSecretBytes + :: BS.ByteString + -> Either DecodeError (PerCommitmentSecret, BS.ByteString) +decodePerCommitmentSecretBytes !bs = do (raw, rest) <- maybe (Left DecodeInsufficientBytes) Right - (decodeBytes secretLen bs) - sec <- maybe (Left DecodeInvalidSecret) Right (secret raw) + (decodeBytes perCommitmentSecretLen bs) + sec <- maybe (Left DecodeInvalidSecret) Right + (perCommitmentSecret raw) Right (sec, rest) -{-# INLINE decodeSecretBytes #-} +{-# INLINE decodePerCommitmentSecretBytes #-} -- | Encode a u16-prefixed byte string with bounds checking. encodeU16BytesE :: BS.ByteString -> Either EncodeError BS.ByteString @@ -346,12 +348,12 @@ encodeOpenChannel :: OpenChannel -> BS.ByteString encodeOpenChannel !msg = mconcat [ unChainHash (openChannelChainHash msg) , unChannelId (openChannelTempChannelId msg) - , encodeU64 (unSatoshis (openChannelFundingSatoshis msg)) - , encodeU64 (unMilliSatoshis (openChannelPushMsat msg)) - , encodeU64 (unSatoshis (openChannelDustLimitSatoshis msg)) - , encodeU64 (unMilliSatoshis (openChannelMaxHtlcValueInFlight msg)) - , encodeU64 (unSatoshis (openChannelChannelReserveSat msg)) - , encodeU64 (unMilliSatoshis (openChannelHtlcMinimumMsat msg)) + , encodeU64 (unSatoshi (openChannelFundingSatoshi msg)) + , encodeU64 (unMilliSatoshi (openChannelPushMsat msg)) + , encodeU64 (unSatoshi (openChannelDustLimitSatoshi msg)) + , encodeU64 (unMilliSatoshi (openChannelMaxHtlcValueInFlight msg)) + , encodeU64 (unSatoshi (openChannelChannelReserveSat msg)) + , encodeU64 (unMilliSatoshi (openChannelHtlcMinimumMsat msg)) , encodeU32 (openChannelFeeratePerKw msg) , encodeU16 (openChannelToSelfDelay msg) , encodeU16 (openChannelMaxAcceptedHtlcs msg) @@ -371,12 +373,12 @@ decodeOpenChannel decodeOpenChannel !bs = do (chainHash', rest1) <- decodeChainHashBytes bs (tempChanId, rest2) <- decodeChannelIdBytes rest1 - (fundingSats, rest3) <- decodeSatoshis rest2 - (pushMsat, rest4) <- decodeMilliSatoshis rest3 - (dustLimit, rest5) <- decodeSatoshis rest4 - (maxHtlcVal, rest6) <- decodeMilliSatoshis rest5 - (chanReserve, rest7) <- decodeSatoshis rest6 - (htlcMin, rest8) <- decodeMilliSatoshis rest7 + (fundingSats, rest3) <- decodeSatoshi rest2 + (pushMsat, rest4) <- decodeMilliSatoshi rest3 + (dustLimit, rest5) <- decodeSatoshi rest4 + (maxHtlcVal, rest6) <- decodeMilliSatoshi rest5 + (chanReserve, rest7) <- decodeSatoshi rest6 + (htlcMin, rest8) <- decodeMilliSatoshi rest7 (feerate, rest9) <- decodeU32E rest8 (toSelfDelay, rest10) <- decodeU16E rest9 (maxHtlcs, rest11) <- decodeU16E rest10 @@ -392,9 +394,9 @@ decodeOpenChannel !bs = do let !msg = OpenChannel { openChannelChainHash = chainHash' , openChannelTempChannelId = tempChanId - , openChannelFundingSatoshis = fundingSats + , openChannelFundingSatoshi = fundingSats , openChannelPushMsat = pushMsat - , openChannelDustLimitSatoshis = dustLimit + , openChannelDustLimitSatoshi = dustLimit , openChannelMaxHtlcValueInFlight = maxHtlcVal , openChannelChannelReserveSat = chanReserve , openChannelHtlcMinimumMsat = htlcMin @@ -433,10 +435,10 @@ decodeOpenChannel !bs = do encodeAcceptChannel :: AcceptChannel -> BS.ByteString encodeAcceptChannel !msg = mconcat [ unChannelId (acceptChannelTempChannelId msg) - , encodeU64 (unSatoshis (acceptChannelDustLimitSatoshis msg)) - , encodeU64 (unMilliSatoshis (acceptChannelMaxHtlcValueInFlight msg)) - , encodeU64 (unSatoshis (acceptChannelChannelReserveSat msg)) - , encodeU64 (unMilliSatoshis (acceptChannelHtlcMinimumMsat msg)) + , encodeU64 (unSatoshi (acceptChannelDustLimitSatoshi msg)) + , encodeU64 (unMilliSatoshi (acceptChannelMaxHtlcValueInFlight msg)) + , encodeU64 (unSatoshi (acceptChannelChannelReserveSat msg)) + , encodeU64 (unMilliSatoshi (acceptChannelHtlcMinimumMsat msg)) , encodeU32 (acceptChannelMinimumDepth msg) , encodeU16 (acceptChannelToSelfDelay msg) , encodeU16 (acceptChannelMaxAcceptedHtlcs msg) @@ -454,10 +456,10 @@ decodeAcceptChannel :: BS.ByteString -> Either DecodeError (AcceptChannel, BS.ByteString) decodeAcceptChannel !bs = do (tempChanId, rest1) <- decodeChannelIdBytes bs - (dustLimit, rest2) <- decodeSatoshis rest1 - (maxHtlcVal, rest3) <- decodeMilliSatoshis rest2 - (chanReserve, rest4) <- decodeSatoshis rest3 - (htlcMin, rest5) <- decodeMilliSatoshis rest4 + (dustLimit, rest2) <- decodeSatoshi rest1 + (maxHtlcVal, rest3) <- decodeMilliSatoshi rest2 + (chanReserve, rest4) <- decodeSatoshi rest3 + (htlcMin, rest5) <- decodeMilliSatoshi rest4 (minDepth, rest6) <- decodeU32E rest5 (toSelfDelay, rest7) <- decodeU16E rest6 (maxHtlcs, rest8) <- decodeU16E rest7 @@ -470,7 +472,7 @@ decodeAcceptChannel !bs = do tlvs <- decodeTlvs rest14 let !msg = AcceptChannel { acceptChannelTempChannelId = tempChanId - , acceptChannelDustLimitSatoshis = dustLimit + , acceptChannelDustLimitSatoshi = dustLimit , acceptChannelMaxHtlcValueInFlight = maxHtlcVal , acceptChannelChannelReserveSat = chanReserve , acceptChannelHtlcMinimumMsat = htlcMin @@ -633,7 +635,7 @@ decodeShutdown !bs = do encodeClosingSigned :: ClosingSigned -> BS.ByteString encodeClosingSigned !msg = mconcat [ unChannelId (closingSignedChannelId msg) - , encodeU64 (unSatoshis (closingSignedFeeSatoshis msg)) + , encodeU64 (unSatoshi (closingSignedFeeSatoshi msg)) , unSignature (closingSignedSignature msg) , encodeTlvStream (closingSignedTlvs msg) ] @@ -643,12 +645,12 @@ decodeClosingSigned :: BS.ByteString -> Either DecodeError (ClosingSigned, BS.ByteString) decodeClosingSigned !bs = do (chanId, rest1) <- decodeChannelIdBytes bs - (feeSats, rest2) <- decodeSatoshis rest1 + (feeSats, rest2) <- decodeSatoshi rest1 (sig, rest3) <- decodeSignatureBytes rest2 tlvs <- decodeTlvs rest3 let !msg = ClosingSigned { closingSignedChannelId = chanId - , closingSignedFeeSatoshis = feeSats + , closingSignedFeeSatoshi = feeSats , closingSignedSignature = sig , closingSignedTlvs = tlvs } @@ -679,7 +681,7 @@ encodeClosingComplete !msg = do , closerScript , encodeU16 (fromIntegral closeeLen) , closeeScript - , encodeU64 (unSatoshis (closingCompleteFeeSatoshis msg)) + , encodeU64 (unSatoshi (closingCompleteFeeSatoshi msg)) , encodeU32 (closingCompleteLocktime msg) , encodeTlvStream (closingCompleteTlvs msg) ] @@ -691,14 +693,14 @@ decodeClosingComplete !bs = do (chanId, rest1) <- decodeChannelIdBytes bs (closerScript, rest2) <- decodeScriptPubKey rest1 (closeeScript, rest3) <- decodeScriptPubKey rest2 - (feeSats, rest4) <- decodeSatoshis rest3 + (feeSats, rest4) <- decodeSatoshi rest3 (locktime, rest5) <- decodeU32E rest4 tlvs <- decodeTlvs rest5 let !msg = ClosingComplete { closingCompleteChannelId = chanId , closingCompleteCloserScript = closerScript , closingCompleteCloseeScript = closeeScript - , closingCompleteFeeSatoshis = feeSats + , closingCompleteFeeSatoshi = feeSats , closingCompleteLocktime = locktime , closingCompleteTlvs = tlvs } @@ -729,7 +731,7 @@ encodeClosingSig !msg = do , closerScript , encodeU16 (fromIntegral closeeLen) , closeeScript - , encodeU64 (unSatoshis (closingSigFeeSatoshis msg)) + , encodeU64 (unSatoshi (closingSigFeeSatoshi msg)) , encodeU32 (closingSigLocktime msg) , encodeTlvStream (closingSigTlvs msg) ] @@ -741,14 +743,14 @@ decodeClosingSig !bs = do (chanId, rest1) <- decodeChannelIdBytes bs (closerScript, rest2) <- decodeScriptPubKey rest1 (closeeScript, rest3) <- decodeScriptPubKey rest2 - (feeSats, rest4) <- decodeSatoshis rest3 + (feeSats, rest4) <- decodeSatoshi rest3 (locktime, rest5) <- decodeU32E rest4 tlvs <- decodeTlvs rest5 let !msg = ClosingSig { closingSigChannelId = chanId , closingSigCloserScript = closerScript , closingSigCloseeScript = closeeScript - , closingSigFeeSatoshis = feeSats + , closingSigFeeSatoshi = feeSats , closingSigLocktime = locktime , closingSigTlvs = tlvs } @@ -763,10 +765,10 @@ encodeOpenChannel2 !msg = mconcat , unChannelId (openChannel2TempChannelId msg) , encodeU32 (openChannel2FundingFeeratePerkw msg) , encodeU32 (openChannel2CommitFeeratePerkw msg) - , encodeU64 (unSatoshis (openChannel2FundingSatoshis msg)) - , encodeU64 (unSatoshis (openChannel2DustLimitSatoshis msg)) - , encodeU64 (unMilliSatoshis (openChannel2MaxHtlcValueInFlight msg)) - , encodeU64 (unMilliSatoshis (openChannel2HtlcMinimumMsat msg)) + , encodeU64 (unSatoshi (openChannel2FundingSatoshi msg)) + , encodeU64 (unSatoshi (openChannel2DustLimitSatoshi msg)) + , encodeU64 (unMilliSatoshi (openChannel2MaxHtlcValueInFlight msg)) + , encodeU64 (unMilliSatoshi (openChannel2HtlcMinimumMsat msg)) , encodeU16 (openChannel2ToSelfDelay msg) , encodeU16 (openChannel2MaxAcceptedHtlcs msg) , encodeU32 (openChannel2Locktime msg) @@ -789,10 +791,10 @@ decodeOpenChannel2 !bs = do (tempCid, rest2) <- decodeChannelIdBytes rest1 (fundingFeerate, rest3) <- decodeU32E rest2 (commitFeerate, rest4) <- decodeU32E rest3 - (fundingSats, rest5) <- decodeSatoshis rest4 - (dustLimit, rest6) <- decodeSatoshis rest5 - (maxHtlcVal, rest7) <- decodeMilliSatoshis rest6 - (htlcMin, rest8) <- decodeMilliSatoshis rest7 + (fundingSats, rest5) <- decodeSatoshi rest4 + (dustLimit, rest6) <- decodeSatoshi rest5 + (maxHtlcVal, rest7) <- decodeMilliSatoshi rest6 + (htlcMin, rest8) <- decodeMilliSatoshi rest7 (toSelfDelay, rest9) <- decodeU16E rest8 (maxHtlcs, rest10) <- decodeU16E rest9 (locktime, rest11) <- decodeU32E rest10 @@ -810,8 +812,8 @@ decodeOpenChannel2 !bs = do , openChannel2TempChannelId = tempCid , openChannel2FundingFeeratePerkw = fundingFeerate , openChannel2CommitFeeratePerkw = commitFeerate - , openChannel2FundingSatoshis = fundingSats - , openChannel2DustLimitSatoshis = dustLimit + , openChannel2FundingSatoshi = fundingSats + , openChannel2DustLimitSatoshi = dustLimit , openChannel2MaxHtlcValueInFlight = maxHtlcVal , openChannel2HtlcMinimumMsat = htlcMin , openChannel2ToSelfDelay = toSelfDelay @@ -833,10 +835,10 @@ decodeOpenChannel2 !bs = do encodeAcceptChannel2 :: AcceptChannel2 -> BS.ByteString encodeAcceptChannel2 !msg = mconcat [ unChannelId (acceptChannel2TempChannelId msg) - , encodeU64 (unSatoshis (acceptChannel2FundingSatoshis msg)) - , encodeU64 (unSatoshis (acceptChannel2DustLimitSatoshis msg)) - , encodeU64 (unMilliSatoshis (acceptChannel2MaxHtlcValueInFlight msg)) - , encodeU64 (unMilliSatoshis (acceptChannel2HtlcMinimumMsat msg)) + , encodeU64 (unSatoshi (acceptChannel2FundingSatoshi msg)) + , encodeU64 (unSatoshi (acceptChannel2DustLimitSatoshi msg)) + , encodeU64 (unMilliSatoshi (acceptChannel2MaxHtlcValueInFlight msg)) + , encodeU64 (unMilliSatoshi (acceptChannel2HtlcMinimumMsat msg)) , encodeU32 (acceptChannel2MinimumDepth msg) , encodeU16 (acceptChannel2ToSelfDelay msg) , encodeU16 (acceptChannel2MaxAcceptedHtlcs msg) @@ -855,10 +857,10 @@ decodeAcceptChannel2 :: BS.ByteString -> Either DecodeError (AcceptChannel2, BS.ByteString) decodeAcceptChannel2 !bs = do (tempCid, rest1) <- decodeChannelIdBytes bs - (fundingSats, rest2) <- decodeSatoshis rest1 - (dustLimit, rest3) <- decodeSatoshis rest2 - (maxHtlcVal, rest4) <- decodeMilliSatoshis rest3 - (htlcMin, rest5) <- decodeMilliSatoshis rest4 + (fundingSats, rest2) <- decodeSatoshi rest1 + (dustLimit, rest3) <- decodeSatoshi rest2 + (maxHtlcVal, rest4) <- decodeMilliSatoshi rest3 + (htlcMin, rest5) <- decodeMilliSatoshi rest4 (minDepth, rest6) <- decodeU32E rest5 (toSelfDelay, rest7) <- decodeU16E rest6 (maxHtlcs, rest8) <- decodeU16E rest7 @@ -872,8 +874,8 @@ decodeAcceptChannel2 !bs = do tlvs <- decodeTlvs rest15 let !msg = AcceptChannel2 { acceptChannel2TempChannelId = tempCid - , acceptChannel2FundingSatoshis = fundingSats - , acceptChannel2DustLimitSatoshis = dustLimit + , acceptChannel2FundingSatoshi = fundingSats + , acceptChannel2DustLimitSatoshi = dustLimit , acceptChannel2MaxHtlcValueInFlight = maxHtlcVal , acceptChannel2HtlcMinimumMsat = htlcMin , acceptChannel2MinimumDepth = minDepth @@ -928,7 +930,7 @@ encodeTxAddOutput !msg = do Right $! mconcat [ unChannelId (txAddOutputChannelId msg) , encodeU64 (txAddOutputSerialId msg) - , encodeU64 (unSatoshis (txAddOutputSats msg)) + , encodeU64 (unSatoshi (txAddOutputSats msg)) , scriptEnc ] @@ -939,7 +941,7 @@ decodeTxAddOutput !bs = do (cid, rest1) <- decodeChannelIdBytes bs (serialId, rest2) <- maybe (Left DecodeInsufficientBytes) Right (decodeU64 rest1) - (sats, rest3) <- decodeSatoshis rest2 + (sats, rest3) <- decodeSatoshi rest2 (scriptBs, rest4) <- decodeU16Bytes rest3 let !msg = TxAddOutput { txAddOutputChannelId = cid @@ -1118,7 +1120,7 @@ encodeUpdateAddHtlc :: UpdateAddHtlc -> BS.ByteString encodeUpdateAddHtlc !m = mconcat [ unChannelId (updateAddHtlcChannelId m) , encodeU64 (updateAddHtlcId m) - , encodeU64 (unMilliSatoshis (updateAddHtlcAmountMsat m)) + , encodeU64 (unMilliSatoshi (updateAddHtlcAmountMsat m)) , unPaymentHash (updateAddHtlcPaymentHash m) , encodeU32 (updateAddHtlcCltvExpiry m) , unOnionPacket (updateAddHtlcOnionPacket m) @@ -1142,7 +1144,7 @@ decodeUpdateAddHtlc !bs = do let !msg = UpdateAddHtlc { updateAddHtlcChannelId = cid , updateAddHtlcId = htlcId - , updateAddHtlcAmountMsat = MilliSatoshis amtMsat + , updateAddHtlcAmountMsat = MilliSatoshi amtMsat , updateAddHtlcPaymentHash = pHash , updateAddHtlcCltvExpiry = cltvExp , updateAddHtlcOnionPacket = onion @@ -1274,7 +1276,7 @@ decodeCommitmentSigned !bs = do encodeRevokeAndAck :: RevokeAndAck -> BS.ByteString encodeRevokeAndAck !m = mconcat [ unChannelId (revokeAndAckChannelId m) - , unSecret (revokeAndAckPerCommitmentSecret m) + , unPerCommitmentSecret (revokeAndAckPerCommitmentSecret m) , unPoint (revokeAndAckNextPerCommitPoint m) ] @@ -1283,7 +1285,7 @@ decodeRevokeAndAck :: BS.ByteString -> Either DecodeError (RevokeAndAck, BS.ByteString) decodeRevokeAndAck !bs = do (cid, rest1) <- decodeChannelIdBytes bs - (sec, rest2) <- decodeSecretBytes rest1 + (sec, rest2) <- decodePerCommitmentSecretBytes rest1 (nextPoint, rest3) <- decodePointBytes rest2 let !msg = RevokeAndAck { revokeAndAckChannelId = cid @@ -1319,7 +1321,7 @@ encodeChannelReestablish !m = mconcat [ unChannelId (channelReestablishChannelId m) , encodeU64 (channelReestablishNextCommitNum m) , encodeU64 (channelReestablishNextRevocationNum m) - , unSecret (channelReestablishYourLastCommitSecret m) + , unPerCommitmentSecret (channelReestablishYourLastCommitSecret m) , unPoint (channelReestablishMyCurrentCommitPoint m) , encodeTlvStream (channelReestablishTlvs m) ] @@ -1333,7 +1335,7 @@ decodeChannelReestablish !bs = do (decodeU64 rest1) (nextRevoke, rest3) <- maybe (Left DecodeInsufficientBytes) Right (decodeU64 rest2) - (sec, rest4) <- decodeSecretBytes rest3 + (sec, rest4) <- decodePerCommitmentSecretBytes rest3 (myPoint, rest5) <- decodePointBytes rest4 (tlvs, rest6) <- decodeOptionalTlvs rest5 let !msg = ChannelReestablish diff --git a/lib/Lightning/Protocol/BOLT2/Messages.hs b/lib/Lightning/Protocol/BOLT2/Messages.hs @@ -151,12 +151,12 @@ msgTypeWord MsgChannelReestablish = 136 data OpenChannel = OpenChannel { openChannelChainHash :: !ChainHash , openChannelTempChannelId :: !ChannelId - , openChannelFundingSatoshis :: {-# UNPACK #-} !Satoshis - , openChannelPushMsat :: {-# UNPACK #-} !MilliSatoshis - , openChannelDustLimitSatoshis :: {-# UNPACK #-} !Satoshis - , openChannelMaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshis - , openChannelChannelReserveSat :: {-# UNPACK #-} !Satoshis - , openChannelHtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshis + , openChannelFundingSatoshi :: {-# UNPACK #-} !Satoshi + , openChannelPushMsat :: {-# UNPACK #-} !MilliSatoshi + , openChannelDustLimitSatoshi :: {-# UNPACK #-} !Satoshi + , openChannelMaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshi + , openChannelChannelReserveSat :: {-# UNPACK #-} !Satoshi + , openChannelHtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshi , openChannelFeeratePerKw :: {-# UNPACK #-} !Word32 , openChannelToSelfDelay :: {-# UNPACK #-} !Word16 , openChannelMaxAcceptedHtlcs :: {-# UNPACK #-} !Word16 @@ -178,10 +178,10 @@ instance NFData OpenChannel -- the new channel. data AcceptChannel = AcceptChannel { acceptChannelTempChannelId :: !ChannelId - , acceptChannelDustLimitSatoshis :: {-# UNPACK #-} !Satoshis - , acceptChannelMaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshis - , acceptChannelChannelReserveSat :: {-# UNPACK #-} !Satoshis - , acceptChannelHtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshis + , acceptChannelDustLimitSatoshi :: {-# UNPACK #-} !Satoshi + , acceptChannelMaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshi + , acceptChannelChannelReserveSat :: {-# UNPACK #-} !Satoshi + , acceptChannelHtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshi , acceptChannelMinimumDepth :: {-# UNPACK #-} !Word32 , acceptChannelToSelfDelay :: {-# UNPACK #-} !Word16 , acceptChannelMaxAcceptedHtlcs :: {-# UNPACK #-} !Word16 @@ -241,10 +241,10 @@ data OpenChannel2 = OpenChannel2 , openChannel2TempChannelId :: !ChannelId , openChannel2FundingFeeratePerkw :: {-# UNPACK #-} !Word32 , openChannel2CommitFeeratePerkw :: {-# UNPACK #-} !Word32 - , openChannel2FundingSatoshis :: {-# UNPACK #-} !Satoshis - , openChannel2DustLimitSatoshis :: {-# UNPACK #-} !Satoshis - , openChannel2MaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshis - , openChannel2HtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshis + , openChannel2FundingSatoshi :: {-# UNPACK #-} !Satoshi + , openChannel2DustLimitSatoshi :: {-# UNPACK #-} !Satoshi + , openChannel2MaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshi + , openChannel2HtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshi , openChannel2ToSelfDelay :: {-# UNPACK #-} !Word16 , openChannel2MaxAcceptedHtlcs :: {-# UNPACK #-} !Word16 , openChannel2Locktime :: {-# UNPACK #-} !Word32 @@ -266,10 +266,10 @@ instance NFData OpenChannel2 -- Indicates acceptance of the v2 channel. data AcceptChannel2 = AcceptChannel2 { acceptChannel2TempChannelId :: !ChannelId - , acceptChannel2FundingSatoshis :: {-# UNPACK #-} !Satoshis - , acceptChannel2DustLimitSatoshis :: {-# UNPACK #-} !Satoshis - , acceptChannel2MaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshis - , acceptChannel2HtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshis + , acceptChannel2FundingSatoshi :: {-# UNPACK #-} !Satoshi + , acceptChannel2DustLimitSatoshi :: {-# UNPACK #-} !Satoshi + , acceptChannel2MaxHtlcValueInFlight :: {-# UNPACK #-} !MilliSatoshi + , acceptChannel2HtlcMinimumMsat :: {-# UNPACK #-} !MilliSatoshi , acceptChannel2MinimumDepth :: {-# UNPACK #-} !Word32 , acceptChannel2ToSelfDelay :: {-# UNPACK #-} !Word16 , acceptChannel2MaxAcceptedHtlcs :: {-# UNPACK #-} !Word16 @@ -306,7 +306,7 @@ instance NFData TxAddInput data TxAddOutput = TxAddOutput { txAddOutputChannelId :: !ChannelId , txAddOutputSerialId :: {-# UNPACK #-} !Word64 - , txAddOutputSats :: {-# UNPACK #-} !Satoshis + , txAddOutputSats :: {-# UNPACK #-} !Satoshi , txAddOutputScript :: !ScriptPubKey } deriving stock (Eq, Show, Generic) @@ -419,7 +419,7 @@ instance NFData Shutdown -- Used in legacy closing negotiation. data ClosingSigned = ClosingSigned { closingSignedChannelId :: !ChannelId - , closingSignedFeeSatoshis :: {-# UNPACK #-} !Satoshis + , closingSignedFeeSatoshi :: {-# UNPACK #-} !Satoshi , closingSignedSignature :: !Signature , closingSignedTlvs :: !TlvStream } deriving stock (Eq, Show, Generic) @@ -433,7 +433,7 @@ data ClosingComplete = ClosingComplete { closingCompleteChannelId :: !ChannelId , closingCompleteCloserScript :: !ScriptPubKey , closingCompleteCloseeScript :: !ScriptPubKey - , closingCompleteFeeSatoshis :: {-# UNPACK #-} !Satoshis + , closingCompleteFeeSatoshi :: {-# UNPACK #-} !Satoshi , closingCompleteLocktime :: {-# UNPACK #-} !Word32 , closingCompleteTlvs :: !TlvStream } deriving stock (Eq, Show, Generic) @@ -447,7 +447,7 @@ data ClosingSig = ClosingSig { closingSigChannelId :: !ChannelId , closingSigCloserScript :: !ScriptPubKey , closingSigCloseeScript :: !ScriptPubKey - , closingSigFeeSatoshis :: {-# UNPACK #-} !Satoshis + , closingSigFeeSatoshi :: {-# UNPACK #-} !Satoshi , closingSigLocktime :: {-# UNPACK #-} !Word32 , closingSigTlvs :: !TlvStream } deriving stock (Eq, Show, Generic) @@ -463,7 +463,7 @@ instance NFData ClosingSig data UpdateAddHtlc = UpdateAddHtlc { updateAddHtlcChannelId :: !ChannelId , updateAddHtlcId :: {-# UNPACK #-} !Word64 - , updateAddHtlcAmountMsat :: {-# UNPACK #-} !MilliSatoshis + , updateAddHtlcAmountMsat :: {-# UNPACK #-} !MilliSatoshi , updateAddHtlcPaymentHash :: !PaymentHash , updateAddHtlcCltvExpiry :: {-# UNPACK #-} !Word32 , updateAddHtlcOnionPacket :: !OnionPacket @@ -526,7 +526,7 @@ instance NFData CommitmentSigned -- of the commitment_signed. data RevokeAndAck = RevokeAndAck { revokeAndAckChannelId :: !ChannelId - , revokeAndAckPerCommitmentSecret :: !Secret + , revokeAndAckPerCommitmentSecret :: !PerCommitmentSecret , revokeAndAckNextPerCommitPoint :: !Point } deriving stock (Eq, Show, Generic) @@ -551,7 +551,7 @@ data ChannelReestablish = ChannelReestablish { channelReestablishChannelId :: !ChannelId , channelReestablishNextCommitNum :: {-# UNPACK #-} !Word64 , channelReestablishNextRevocationNum :: {-# UNPACK #-} !Word64 - , channelReestablishYourLastCommitSecret :: !Secret + , channelReestablishYourLastCommitSecret :: !PerCommitmentSecret , channelReestablishMyCurrentCommitPoint :: !Point , channelReestablishTlvs :: !TlvStream } deriving stock (Eq, Show, Generic) diff --git a/lib/Lightning/Protocol/BOLT2/Types.hs b/lib/Lightning/Protocol/BOLT2/Types.hs @@ -16,44 +16,36 @@ -- keys used in the Lightning Network peer protocol. module Lightning.Protocol.BOLT2.Types ( - -- * Identifiers - ChannelId + -- * Identifiers (re-exported from BOLT1) + ChannelId(..) , channelId , unChannelId - -- * Amounts - , Satoshis(..) - , MilliSatoshis(..) - , satoshisToMsat - , msatToSatoshis + -- * Amounts (re-exported from BOLT1) + , Satoshi(..) + , MilliSatoshi(..) + , satToMsat + , msatToSat - -- * Cryptographic types - , Signature + -- * Cryptographic types (re-exported from BOLT1) + , Signature(..) , signature , unSignature - , Point + , Point(..) , point , unPoint - , PaymentHash + , PaymentHash(..) , paymentHash , unPaymentHash - , PaymentPreimage + , PaymentPreimage(..) , paymentPreimage , unPaymentPreimage - , Secret - , secret - , unSecret + , PerCommitmentSecret(..) + , perCommitmentSecret + , unPerCommitmentSecret - -- * Transaction types - , TxId(..) - , mkTxId - , OutPoint(..) - , ScriptPubKey - , scriptPubKey - , unScriptPubKey - - -- * Chain types - , ChainHash + -- * Chain types (re-exported from BOLT1) + , ChainHash(..) , chainHash , unChainHash , ShortChannelId(..) @@ -62,6 +54,14 @@ module Lightning.Protocol.BOLT2.Types ( , scidTxIndex , scidOutputIndex + -- * Transaction types + , TxId(..) + , mkTxId + , OutPoint(..) + , ScriptPubKey + , scriptPubKey + , unScriptPubKey + -- * Protocol types , FeatureBits , featureBits @@ -79,15 +79,26 @@ module Lightning.Protocol.BOLT2.Types ( , paymentHashLen , paymentPreimageLen , onionPacketLen - , secretLen + , perCommitmentSecretLen ) where import Bitcoin.Prim.Tx (TxId(..), mkTxId, OutPoint(..)) import Control.DeepSeq (NFData) -import Data.Bits (unsafeShiftL, unsafeShiftR, (.&.), (.|.)) import qualified Data.ByteString as BS -import Data.Word (Word16, Word32, Word64) import GHC.Generics (Generic) +import Lightning.Protocol.BOLT1.Prim + ( ChannelId(..), channelId, unChannelId + , Satoshi(..), MilliSatoshi(..), satToMsat, msatToSat + , Signature(..), signature, unSignature + , Point(..), point, unPoint + , PaymentHash(..), paymentHash, unPaymentHash + , PaymentPreimage(..), paymentPreimage, unPaymentPreimage + , PerCommitmentSecret(..), perCommitmentSecret + , unPerCommitmentSecret + , ChainHash(..), chainHash, unChainHash + , ShortChannelId(..), shortChannelId + , scidBlockHeight, scidTxIndex, scidOutputIndex + ) -- constants ------------------------------------------------------------------- @@ -132,202 +143,18 @@ onionPacketLen = 1366 {-# INLINE onionPacketLen #-} -- | Length of a per-commitment secret in bytes (32). -secretLen :: Int -secretLen = 32 -{-# INLINE secretLen #-} - --- identifiers ----------------------------------------------------------------- - --- | A 32-byte channel identifier. --- --- Derived from the funding transaction by XORing @funding_txid@ with --- @funding_output_index@ (big-endian, altering the last 2 bytes). --- --- For v2 channels, derived as @SHA256(lesser-revocation-basepoint || --- greater-revocation-basepoint)@. -newtype ChannelId = ChannelId BS.ByteString - deriving stock (Eq, Ord, Show, Generic) - deriving newtype NFData - --- | Construct a 'ChannelId' from a 32-byte 'BS.ByteString'. --- --- Returns 'Nothing' if the input is not exactly 32 bytes. --- --- >>> channelId (BS.replicate 32 0x00) --- Just (ChannelId ...) --- >>> channelId (BS.replicate 31 0x00) --- Nothing -channelId :: BS.ByteString -> Maybe ChannelId -channelId !bs - | BS.length bs == channelIdLen = Just $! ChannelId bs - | otherwise = Nothing -{-# INLINABLE channelId #-} - --- | Extract the underlying 'BS.ByteString' from a 'ChannelId'. -unChannelId :: ChannelId -> BS.ByteString -unChannelId (ChannelId bs) = bs -{-# INLINE unChannelId #-} - --- amounts --------------------------------------------------------------------- - --- | Amount in satoshis (1/100,000,000 of a bitcoin). --- --- Stored as a 'Word64'. Maximum valid value is 21,000,000 * 100,000,000 --- = 2,100,000,000,000,000 satoshis. -newtype Satoshis = Satoshis { unSatoshis :: Word64 } - deriving stock (Eq, Ord, Show, Generic) - deriving newtype (NFData, Num, Enum, Real, Integral) - --- | Amount in millisatoshis (1/1000 of a satoshi). --- --- Stored as a 'Word64'. Used for HTLC amounts and channel balances. -newtype MilliSatoshis = MilliSatoshis { unMilliSatoshis :: Word64 } - deriving stock (Eq, Ord, Show, Generic) - deriving newtype (NFData, Num, Enum, Real, Integral) - --- | Convert 'Satoshis' to 'MilliSatoshis'. --- --- >>> satoshisToMsat (Satoshis 1) --- MilliSatoshis 1000 -satoshisToMsat :: Satoshis -> MilliSatoshis -satoshisToMsat (Satoshis !s) = MilliSatoshis $! s * 1000 -{-# INLINE satoshisToMsat #-} - --- | Convert 'MilliSatoshis' to 'Satoshis', rounding down. --- --- >>> msatToSatoshis (MilliSatoshis 1500) --- Satoshis 1 -msatToSatoshis :: MilliSatoshis -> Satoshis -msatToSatoshis (MilliSatoshis !m) = Satoshis $! m `div` 1000 -{-# INLINE msatToSatoshis #-} - --- cryptographic types --------------------------------------------------------- - --- | A 64-byte compact ECDSA signature. --- --- Used for commitment transaction signatures, HTLC signatures, and --- closing transaction signatures. -newtype Signature = Signature BS.ByteString - deriving stock (Eq, Ord, Show, Generic) - deriving newtype NFData - --- | Construct a 'Signature' from a 64-byte 'BS.ByteString'. --- --- Returns 'Nothing' if the input is not exactly 64 bytes. -signature :: BS.ByteString -> Maybe Signature -signature !bs - | BS.length bs == signatureLen = Just $! Signature bs - | otherwise = Nothing -{-# INLINABLE signature #-} - --- | Extract the underlying 'BS.ByteString' from a 'Signature'. -unSignature :: Signature -> BS.ByteString -unSignature (Signature bs) = bs -{-# INLINE unSignature #-} - --- | A 33-byte compressed secp256k1 public key. --- --- Used for funding pubkeys, basepoints, and per-commitment points. -newtype Point = Point BS.ByteString - deriving stock (Eq, Ord, Show, Generic) - deriving newtype NFData - --- | Construct a 'Point' from a 33-byte 'BS.ByteString'. --- --- Returns 'Nothing' if the input is not exactly 33 bytes. --- --- Note: This only validates the length. Use secp256k1 libraries for --- full point validation. -point :: BS.ByteString -> Maybe Point -point !bs - | BS.length bs == pointLen = Just $! Point bs - | otherwise = Nothing -{-# INLINABLE point #-} - --- | Extract the underlying 'BS.ByteString' from a 'Point'. -unPoint :: Point -> BS.ByteString -unPoint (Point bs) = bs -{-# INLINE unPoint #-} - --- | A 32-byte SHA256 payment hash. --- --- Used to identify HTLCs. The preimage that hashes to this value is --- required to claim the HTLC. -newtype PaymentHash = PaymentHash BS.ByteString - deriving stock (Eq, Ord, Show, Generic) - deriving newtype NFData - --- | Construct a 'PaymentHash' from a 32-byte 'BS.ByteString'. --- --- Returns 'Nothing' if the input is not exactly 32 bytes. -paymentHash :: BS.ByteString -> Maybe PaymentHash -paymentHash !bs - | BS.length bs == paymentHashLen = Just $! PaymentHash bs - | otherwise = Nothing -{-# INLINABLE paymentHash #-} - --- | Extract the underlying 'BS.ByteString' from a 'PaymentHash'. -unPaymentHash :: PaymentHash -> BS.ByteString -unPaymentHash (PaymentHash bs) = bs -{-# INLINE unPaymentHash #-} - --- | A 32-byte payment preimage. --- --- The SHA256 hash of this value produces the corresponding 'PaymentHash'. --- Knowledge of the preimage allows claiming an HTLC. -newtype PaymentPreimage = PaymentPreimage BS.ByteString - deriving stock (Eq, Ord, Show, Generic) - deriving newtype NFData - --- | Construct a 'PaymentPreimage' from a 32-byte 'BS.ByteString'. --- --- Returns 'Nothing' if the input is not exactly 32 bytes. -paymentPreimage :: BS.ByteString -> Maybe PaymentPreimage -paymentPreimage !bs - | BS.length bs == paymentPreimageLen = Just $! PaymentPreimage bs - | otherwise = Nothing -{-# INLINABLE paymentPreimage #-} - --- | Extract the underlying 'BS.ByteString' from a 'PaymentPreimage'. -unPaymentPreimage :: PaymentPreimage -> BS.ByteString -unPaymentPreimage (PaymentPreimage bs) = bs -{-# INLINE unPaymentPreimage #-} - --- | A 32-byte per-commitment secret. --- --- Used in revoke_and_ack and channel_reestablish messages to revoke --- old commitment transactions. -newtype Secret = Secret BS.ByteString - deriving stock (Eq, Ord, Show, Generic) - deriving newtype NFData - --- | Construct a 'Secret' from a 32-byte 'BS.ByteString'. --- --- Returns 'Nothing' if the input is not exactly 32 bytes. -secret :: BS.ByteString -> Maybe Secret -secret !bs - | BS.length bs == secretLen = Just $! Secret bs - | otherwise = Nothing -{-# INLINABLE secret #-} - --- | Extract the underlying 'BS.ByteString' from a 'Secret'. -unSecret :: Secret -> BS.ByteString -unSecret (Secret bs) = bs -{-# INLINE unSecret #-} +perCommitmentSecretLen :: Int +perCommitmentSecretLen = 32 +{-# INLINE perCommitmentSecretLen #-} -- transaction types ----------------------------------------------------------- -- | A script pubkey (output script). --- --- Variable length; used in shutdown messages, closing transactions, etc. newtype ScriptPubKey = ScriptPubKey BS.ByteString deriving stock (Eq, Ord, Show, Generic) deriving newtype NFData -- | Construct a 'ScriptPubKey' from a 'BS.ByteString'. --- --- Accepts any length; validation of script structure is left to higher --- layers. scriptPubKey :: BS.ByteString -> ScriptPubKey scriptPubKey = ScriptPubKey {-# INLINE scriptPubKey #-} @@ -337,100 +164,14 @@ unScriptPubKey :: ScriptPubKey -> BS.ByteString unScriptPubKey (ScriptPubKey bs) = bs {-# INLINE unScriptPubKey #-} --- chain types ----------------------------------------------------------------- - --- | A 32-byte chain hash. --- --- Identifies the blockchain (typically the genesis block hash). --- Used in @open_channel@ to specify which chain the channel will reside on. -newtype ChainHash = ChainHash BS.ByteString - deriving stock (Eq, Ord, Show, Generic) - deriving newtype NFData - --- | Construct a 'ChainHash' from a 32-byte 'BS.ByteString'. --- --- Returns 'Nothing' if the input is not exactly 32 bytes. -chainHash :: BS.ByteString -> Maybe ChainHash -chainHash !bs - | BS.length bs == chainHashLen = Just $! ChainHash bs - | otherwise = Nothing -{-# INLINABLE chainHash #-} - --- | Extract the underlying 'BS.ByteString' from a 'ChainHash'. -unChainHash :: ChainHash -> BS.ByteString -unChainHash (ChainHash bs) = bs -{-# INLINE unChainHash #-} - --- | A short channel identifier (8 bytes). --- --- Encodes the block height (3 bytes), transaction index (3 bytes), and --- output index (2 bytes) of the funding transaction output. --- --- This is a compact representation for referencing channels in gossip --- and routing. -data ShortChannelId = ShortChannelId - { scidBytes :: {-# UNPACK #-} !Word64 - } - deriving stock (Eq, Ord, Show, Generic) - -instance NFData ShortChannelId - --- | Construct a 'ShortChannelId' from block height, tx index, and --- output index. --- --- Returns 'Nothing' if any component exceeds its maximum value: --- --- * block height: max 16,777,215 (2^24 - 1) --- * tx index: max 16,777,215 (2^24 - 1) --- * output index: max 65,535 (2^16 - 1) --- --- >>> shortChannelId 800000 1234 0 --- Just (ShortChannelId ...) -shortChannelId - :: Word32 -- ^ Block height (24 bits max) - -> Word32 -- ^ Transaction index (24 bits max) - -> Word16 -- ^ Output index - -> Maybe ShortChannelId -shortChannelId !blockHeight !txIndex !outputIndex - | blockHeight > 0xFFFFFF = Nothing - | txIndex > 0xFFFFFF = Nothing - | otherwise = Just $! ShortChannelId scid - where - !scid = (fromIntegral blockHeight `unsafeShiftL` 40) - .|. (fromIntegral txIndex `unsafeShiftL` 16) - .|. fromIntegral outputIndex -{-# INLINABLE shortChannelId #-} - --- | Extract the block height from a 'ShortChannelId'. -scidBlockHeight :: ShortChannelId -> Word32 -scidBlockHeight (ShortChannelId !w) = - fromIntegral $! (w `unsafeShiftR` 40) .&. 0xFFFFFF -{-# INLINE scidBlockHeight #-} - --- | Extract the transaction index from a 'ShortChannelId'. -scidTxIndex :: ShortChannelId -> Word32 -scidTxIndex (ShortChannelId !w) = - fromIntegral $! (w `unsafeShiftR` 16) .&. 0xFFFFFF -{-# INLINE scidTxIndex #-} - --- | Extract the output index from a 'ShortChannelId'. -scidOutputIndex :: ShortChannelId -> Word16 -scidOutputIndex (ShortChannelId !w) = fromIntegral $! w .&. 0xFFFF -{-# INLINE scidOutputIndex #-} - -- protocol types -------------------------------------------------------------- -- | Feature bits (variable length). --- --- Encodes supported/required features. Even bits indicate required --- features; odd bits indicate optional features. newtype FeatureBits = FeatureBits BS.ByteString deriving stock (Eq, Ord, Show, Generic) deriving newtype NFData -- | Construct 'FeatureBits' from a 'BS.ByteString'. --- --- Accepts any length; feature bit parsing is left to higher layers. featureBits :: BS.ByteString -> FeatureBits featureBits = FeatureBits {-# INLINE featureBits #-} @@ -441,9 +182,6 @@ unFeatureBits (FeatureBits bs) = bs {-# INLINE unFeatureBits #-} -- | A 1366-byte onion routing packet. --- --- Contains encrypted routing information for HTLC forwarding, as --- specified in BOLT #4. newtype OnionPacket = OnionPacket BS.ByteString deriving stock (Eq, Ord, Show, Generic) deriving newtype NFData diff --git a/test/Main.hs b/test/Main.hs @@ -61,9 +61,10 @@ testPaymentPreimage = fromJust $ paymentPreimage (BS.replicate 32 0xbb) testOnionPacket :: OnionPacket testOnionPacket = fromJust $ onionPacket (BS.replicate 1366 0x00) --- | Create a valid Secret (32 bytes). -testSecret :: Secret -testSecret = fromJust $ secret (BS.replicate 32 0x11) +-- | Create a valid PerCommitmentSecret (32 bytes). +testSecret :: PerCommitmentSecret +testSecret = fromJust $ + perCommitmentSecret (BS.replicate 32 0x11) -- | Empty TLV stream for messages. emptyTlvs :: TlvStream @@ -78,12 +79,12 @@ v1_establishment_tests = testGroup "V1 Channel Establishment" [ let msg = OpenChannel { openChannelChainHash = testChainHash , openChannelTempChannelId = testChannelId - , openChannelFundingSatoshis = Satoshis 1000000 - , openChannelPushMsat = MilliSatoshis 500000 - , openChannelDustLimitSatoshis = Satoshis 546 - , openChannelMaxHtlcValueInFlight = MilliSatoshis 100000000 - , openChannelChannelReserveSat = Satoshis 10000 - , openChannelHtlcMinimumMsat = MilliSatoshis 1000 + , openChannelFundingSatoshi = Satoshi 1000000 + , openChannelPushMsat = MilliSatoshi 500000 + , openChannelDustLimitSatoshi = Satoshi 546 + , openChannelMaxHtlcValueInFlight = MilliSatoshi 100000000 + , openChannelChannelReserveSat = Satoshi 10000 + , openChannelHtlcMinimumMsat = MilliSatoshi 1000 , openChannelFeeratePerKw = 2500 , openChannelToSelfDelay = 144 , openChannelMaxAcceptedHtlcs = 483 @@ -105,10 +106,10 @@ v1_establishment_tests = testGroup "V1 Channel Establishment" [ testCase "encode/decode roundtrip" $ do let msg = AcceptChannel { acceptChannelTempChannelId = testChannelId - , acceptChannelDustLimitSatoshis = Satoshis 546 - , acceptChannelMaxHtlcValueInFlight = MilliSatoshis 100000000 - , acceptChannelChannelReserveSat = Satoshis 10000 - , acceptChannelHtlcMinimumMsat = MilliSatoshis 1000 + , acceptChannelDustLimitSatoshi = Satoshi 546 + , acceptChannelMaxHtlcValueInFlight = MilliSatoshi 100000000 + , acceptChannelChannelReserveSat = Satoshi 10000 + , acceptChannelHtlcMinimumMsat = MilliSatoshi 1000 , acceptChannelMinimumDepth = 3 , acceptChannelToSelfDelay = 144 , acceptChannelMaxAcceptedHtlcs = 483 @@ -185,10 +186,10 @@ v2_establishment_tests = testGroup "V2 Channel Establishment" [ , openChannel2TempChannelId = testChannelId , openChannel2FundingFeeratePerkw = 2500 , openChannel2CommitFeeratePerkw = 2000 - , openChannel2FundingSatoshis = Satoshis 1000000 - , openChannel2DustLimitSatoshis = Satoshis 546 - , openChannel2MaxHtlcValueInFlight = MilliSatoshis 100000000 - , openChannel2HtlcMinimumMsat = MilliSatoshis 1000 + , openChannel2FundingSatoshi = Satoshi 1000000 + , openChannel2DustLimitSatoshi = Satoshi 546 + , openChannel2MaxHtlcValueInFlight = MilliSatoshi 100000000 + , openChannel2HtlcMinimumMsat = MilliSatoshi 1000 , openChannel2ToSelfDelay = 144 , openChannel2MaxAcceptedHtlcs = 483 , openChannel2Locktime = 0 @@ -211,10 +212,10 @@ v2_establishment_tests = testGroup "V2 Channel Establishment" [ testCase "encode/decode roundtrip" $ do let msg = AcceptChannel2 { acceptChannel2TempChannelId = testChannelId - , acceptChannel2FundingSatoshis = Satoshis 500000 - , acceptChannel2DustLimitSatoshis = Satoshis 546 - , acceptChannel2MaxHtlcValueInFlight = MilliSatoshis 100000000 - , acceptChannel2HtlcMinimumMsat = MilliSatoshis 1000 + , acceptChannel2FundingSatoshi = Satoshi 500000 + , acceptChannel2DustLimitSatoshi = Satoshi 546 + , acceptChannel2MaxHtlcValueInFlight = MilliSatoshi 100000000 + , acceptChannel2HtlcMinimumMsat = MilliSatoshi 1000 , acceptChannel2MinimumDepth = 3 , acceptChannel2ToSelfDelay = 144 , acceptChannel2MaxAcceptedHtlcs = 483 @@ -265,7 +266,7 @@ v2_establishment_tests = testGroup "V2 Channel Establishment" [ let msg = TxAddOutput { txAddOutputChannelId = testChannelId , txAddOutputSerialId = 54321 - , txAddOutputSats = Satoshis 100000 + , txAddOutputSats = Satoshi 100000 , txAddOutputScript = scriptPubKey (BS.pack [0x00, 0x14] <> BS.replicate 20 0xaa) } @@ -433,7 +434,7 @@ close_tests = testGroup "Channel Close" [ testCase "encode/decode roundtrip" $ do let msg = ClosingSigned { closingSignedChannelId = testChannelId - , closingSignedFeeSatoshis = Satoshis 1000 + , closingSignedFeeSatoshi = Satoshi 1000 , closingSignedSignature = testSignature , closingSignedTlvs = emptyTlvs } @@ -452,7 +453,7 @@ close_tests = testGroup "Channel Close" [ { closingCompleteChannelId = testChannelId , closingCompleteCloserScript = closerScript , closingCompleteCloseeScript = closeeScript - , closingCompleteFeeSatoshis = Satoshis 500 + , closingCompleteFeeSatoshi = Satoshi 500 , closingCompleteLocktime = 0 , closingCompleteTlvs = emptyTlvs } @@ -472,7 +473,7 @@ close_tests = testGroup "Channel Close" [ { closingSigChannelId = testChannelId , closingSigCloserScript = closerScript , closingSigCloseeScript = closeeScript - , closingSigFeeSatoshis = Satoshis 500 + , closingSigFeeSatoshi = Satoshi 500 , closingSigLocktime = 100 , closingSigTlvs = emptyTlvs } @@ -493,7 +494,7 @@ normal_operation_tests = testGroup "Normal Operation" [ let msg = UpdateAddHtlc { updateAddHtlcChannelId = testChannelId , updateAddHtlcId = 0 - , updateAddHtlcAmountMsat = MilliSatoshis 10000000 + , updateAddHtlcAmountMsat = MilliSatoshi 10000000 , updateAddHtlcPaymentHash = testPaymentHash , updateAddHtlcCltvExpiry = 800144 , updateAddHtlcOnionPacket = testOnionPacket @@ -612,7 +613,7 @@ normal_operation_tests = testGroup "Normal Operation" [ reestablish_tests :: TestTree reestablish_tests = testGroup "Channel Reestablish" [ testCase "encode/decode roundtrip" $ do - let sec = fromJust $ secret (BS.replicate 32 0x22) + let sec = fromJust $ perCommitmentSecret (BS.replicate 32 0x22) msg = ChannelReestablish { channelReestablishChannelId = testChannelId , channelReestablishNextCommitNum = 5 @@ -626,7 +627,7 @@ reestablish_tests = testGroup "Channel Reestablish" [ Right (decoded, _) -> decoded @?= msg Left e -> assertFailure $ "decode failed: " ++ show e , testCase "roundtrip with zero counters" $ do - let sec = fromJust $ secret (BS.replicate 32 0x00) + let sec = fromJust $ perCommitmentSecret (BS.replicate 32 0x00) msg = ChannelReestablish { channelReestablishChannelId = testChannelId , channelReestablishNextCommitNum = 1 @@ -712,7 +713,7 @@ error_tests = testGroup "Error Conditions" [ { closingCompleteChannelId = testChannelId , closingCompleteCloserScript = oversizedScript , closingCompleteCloseeScript = normalScript - , closingCompleteFeeSatoshis = Satoshis 500 + , closingCompleteFeeSatoshi = Satoshi 500 , closingCompleteLocktime = 0 , closingCompleteTlvs = emptyTlvs } @@ -726,7 +727,7 @@ error_tests = testGroup "Error Conditions" [ { closingCompleteChannelId = testChannelId , closingCompleteCloserScript = normalScript , closingCompleteCloseeScript = oversizedScript - , closingCompleteFeeSatoshis = Satoshis 500 + , closingCompleteFeeSatoshi = Satoshi 500 , closingCompleteLocktime = 0 , closingCompleteTlvs = emptyTlvs } @@ -740,7 +741,7 @@ error_tests = testGroup "Error Conditions" [ { closingSigChannelId = testChannelId , closingSigCloserScript = oversizedScript , closingSigCloseeScript = normalScript - , closingSigFeeSatoshis = Satoshis 500 + , closingSigFeeSatoshi = Satoshi 500 , closingSigLocktime = 0 , closingSigTlvs = emptyTlvs } @@ -820,12 +821,12 @@ propOpenChannelRoundtrip = property $ do let msg = OpenChannel { openChannelChainHash = testChainHash , openChannelTempChannelId = testChannelId - , openChannelFundingSatoshis = Satoshis 1000000 - , openChannelPushMsat = MilliSatoshis 500000 - , openChannelDustLimitSatoshis = Satoshis 546 - , openChannelMaxHtlcValueInFlight = MilliSatoshis 100000000 - , openChannelChannelReserveSat = Satoshis 10000 - , openChannelHtlcMinimumMsat = MilliSatoshis 1000 + , openChannelFundingSatoshi = Satoshi 1000000 + , openChannelPushMsat = MilliSatoshi 500000 + , openChannelDustLimitSatoshi = Satoshi 546 + , openChannelMaxHtlcValueInFlight = MilliSatoshi 100000000 + , openChannelChannelReserveSat = Satoshi 10000 + , openChannelHtlcMinimumMsat = MilliSatoshi 1000 , openChannelFeeratePerKw = 2500 , openChannelToSelfDelay = 144 , openChannelMaxAcceptedHtlcs = 483 @@ -848,10 +849,10 @@ propAcceptChannelRoundtrip :: Property propAcceptChannelRoundtrip = property $ do let msg = AcceptChannel { acceptChannelTempChannelId = testChannelId - , acceptChannelDustLimitSatoshis = Satoshis 546 - , acceptChannelMaxHtlcValueInFlight = MilliSatoshis 100000000 - , acceptChannelChannelReserveSat = Satoshis 10000 - , acceptChannelHtlcMinimumMsat = MilliSatoshis 1000 + , acceptChannelDustLimitSatoshi = Satoshi 546 + , acceptChannelMaxHtlcValueInFlight = MilliSatoshi 100000000 + , acceptChannelChannelReserveSat = Satoshi 10000 + , acceptChannelHtlcMinimumMsat = MilliSatoshi 1000 , acceptChannelMinimumDepth = 3 , acceptChannelToSelfDelay = 144 , acceptChannelMaxAcceptedHtlcs = 483 @@ -915,10 +916,10 @@ propOpenChannel2Roundtrip = property $ do , openChannel2TempChannelId = testChannelId , openChannel2FundingFeeratePerkw = 2500 , openChannel2CommitFeeratePerkw = 2000 - , openChannel2FundingSatoshis = Satoshis 1000000 - , openChannel2DustLimitSatoshis = Satoshis 546 - , openChannel2MaxHtlcValueInFlight = MilliSatoshis 100000000 - , openChannel2HtlcMinimumMsat = MilliSatoshis 1000 + , openChannel2FundingSatoshi = Satoshi 1000000 + , openChannel2DustLimitSatoshi = Satoshi 546 + , openChannel2MaxHtlcValueInFlight = MilliSatoshi 100000000 + , openChannel2HtlcMinimumMsat = MilliSatoshi 1000 , openChannel2ToSelfDelay = 144 , openChannel2MaxAcceptedHtlcs = 483 , openChannel2Locktime = 0 @@ -942,10 +943,10 @@ propAcceptChannel2Roundtrip :: Property propAcceptChannel2Roundtrip = property $ do let msg = AcceptChannel2 { acceptChannel2TempChannelId = testChannelId - , acceptChannel2FundingSatoshis = Satoshis 500000 - , acceptChannel2DustLimitSatoshis = Satoshis 546 - , acceptChannel2MaxHtlcValueInFlight = MilliSatoshis 100000000 - , acceptChannel2HtlcMinimumMsat = MilliSatoshis 1000 + , acceptChannel2FundingSatoshi = Satoshi 500000 + , acceptChannel2DustLimitSatoshi = Satoshi 546 + , acceptChannel2MaxHtlcValueInFlight = MilliSatoshi 100000000 + , acceptChannel2HtlcMinimumMsat = MilliSatoshi 1000 , acceptChannel2MinimumDepth = 3 , acceptChannel2ToSelfDelay = 144 , acceptChannel2MaxAcceptedHtlcs = 483 @@ -987,7 +988,7 @@ propTxAddOutputRoundtrip sats scriptBytes = property $ do msg = TxAddOutput { txAddOutputChannelId = testChannelId , txAddOutputSerialId = 54321 - , txAddOutputSats = Satoshis sats + , txAddOutputSats = Satoshi sats , txAddOutputScript = script } case encodeTxAddOutput msg of @@ -1115,7 +1116,7 @@ propClosingSignedRoundtrip :: Word64 -> Property propClosingSignedRoundtrip feeSats = property $ do let msg = ClosingSigned { closingSignedChannelId = testChannelId - , closingSignedFeeSatoshis = Satoshis feeSats + , closingSignedFeeSatoshi = Satoshi feeSats , closingSignedSignature = testSignature , closingSignedTlvs = emptyTlvs } @@ -1135,7 +1136,7 @@ propClosingCompleteRoundtrip feeSats locktime = property $ do { closingCompleteChannelId = testChannelId , closingCompleteCloserScript = closerScript , closingCompleteCloseeScript = closeeScript - , closingCompleteFeeSatoshis = Satoshis feeSats + , closingCompleteFeeSatoshi = Satoshi feeSats , closingCompleteLocktime = locktime , closingCompleteTlvs = emptyTlvs } @@ -1156,7 +1157,7 @@ propClosingSigRoundtrip feeSats locktime = property $ do { closingSigChannelId = testChannelId , closingSigCloserScript = closerScript , closingSigCloseeScript = closeeScript - , closingSigFeeSatoshis = Satoshis feeSats + , closingSigFeeSatoshi = Satoshi feeSats , closingSigLocktime = locktime , closingSigTlvs = emptyTlvs } @@ -1172,7 +1173,7 @@ propUpdateAddHtlcRoundtrip htlcId amountMsat cltvExpiry = property $ do let msg = UpdateAddHtlc { updateAddHtlcChannelId = testChannelId , updateAddHtlcId = htlcId - , updateAddHtlcAmountMsat = MilliSatoshis amountMsat + , updateAddHtlcAmountMsat = MilliSatoshi amountMsat , updateAddHtlcPaymentHash = testPaymentHash , updateAddHtlcCltvExpiry = cltvExpiry , updateAddHtlcOnionPacket = testOnionPacket @@ -1271,7 +1272,7 @@ propUpdateFeeRoundtrip feerate = property $ do -- Property: ChannelReestablish roundtrip propChannelReestablishRoundtrip :: Word64 -> Word64 -> Property propChannelReestablishRoundtrip nextCommit nextRevoke = property $ do - let sec = fromJust $ secret (BS.replicate 32 0x22) + let sec = fromJust $ perCommitmentSecret (BS.replicate 32 0x22) msg = ChannelReestablish { channelReestablishChannelId = testChannelId , channelReestablishNextCommitNum = nextCommit