Skip to content

Commit 92c2405

Browse files
Removes dependence on bitstream package
1 parent f036b91 commit 92c2405

3 files changed

Lines changed: 46 additions & 17 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
dist-newstyle/
22
/.stack-work/
3+
TAGS

bitcoin-compact-filters.cabal

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 2.2
22
name: bitcoin-compact-filters
3-
version: 0.1.0.2
3+
version: 0.1.1
44
synopsis: BIP 158 compact block filters
55

66
copyright: 2020 Bitnomial, Inc.
@@ -15,9 +15,9 @@ data-files:
1515
examples/*.json
1616

1717
tested-with:
18-
GHC == 8.10.4
19-
, GHC == 8.10.5
20-
, GHC == 9.0.1
18+
GHC == 8.10.7
19+
, GHC == 9.0.2
20+
, GHC == 9.2.2
2121

2222
common core
2323
default-language: Haskell2010
@@ -38,8 +38,7 @@ library
3838
Bitcoin.CompactFilter
3939

4040
build-depends:
41-
bitstream ^>=0.3.0.1
42-
, transformers >=0.5 && <0.7
41+
transformers >=0.5 && <0.7
4342
, memory >=0.15 && <0.18
4443

4544

src/Bitcoin/CompactFilter.hs

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ import Control.Monad (replicateM, (>=>))
1919
import Control.Monad.Trans.Class (lift)
2020
import Control.Monad.Trans.State.Strict (StateT, evalStateT)
2121
import qualified Control.Monad.Trans.State.Strict as St
22-
import Data.Bits (shiftL, shiftR, testBit)
23-
import Data.Bitstream (Bitstream, Right)
24-
import qualified Data.Bitstream as BiS
22+
import Data.Bits (clearBit, setBit, shiftL, shiftR, testBit)
2523
import Data.Bool (bool)
2624
import Data.ByteArray.Hash (
2725
SipHash (..),
@@ -30,6 +28,7 @@ import Data.ByteArray.Hash (
3028
)
3129
import Data.ByteString (ByteString)
3230
import qualified Data.ByteString as BS
31+
import qualified Data.ByteString.Lazy as BSL
3332
import Data.Foldable (foldl')
3433
import Data.List (sort)
3534
import Data.Serialize (
@@ -72,8 +71,8 @@ paramM = 784931
7271

7372
-- | Hashes of scripts in the block
7473
newtype BlockFilter = BlockFilter
75-
{ -- | Get the list of hashes in increasing order
76-
blockFilter :: [Word64]
74+
{ blockFilter :: [Word64]
75+
-- ^ Get the list of hashes in increasing order
7776
}
7877
deriving (Eq, Show)
7978

@@ -221,15 +220,45 @@ toSet = dedup . sort
221220
| otherwise -> x0 : dedup xs
222221
xs -> xs
223222

223+
{- | Golomb coded sets are not naturally expressed in bytes, but rather as a bit
224+
stream
225+
-}
226+
data Bitstream
227+
= Bitstream
228+
BSL.ByteString
229+
-- ^ Complete bytes written so far, in reverse order
230+
{-# UNPACK #-} !Word8
231+
-- ^ The current work byte
232+
{-# UNPACK #-} !Int
233+
-- ^ Pointer to the first open bit
234+
235+
emptyB :: Bitstream
236+
emptyB = Bitstream mempty 0 7
237+
238+
appendBit :: Bool -> Bitstream -> Bitstream
239+
appendBit b (Bitstream bytes inFlight cursor)
240+
| cursor == 0 = Bitstream (BSL.cons nextInFlight bytes) 0 7
241+
| otherwise = Bitstream bytes nextInFlight (cursor - 1)
242+
where
243+
nextInFlight = bool clearBit setBit b inFlight cursor
244+
245+
asByteString :: Bitstream -> ByteString
246+
asByteString (Bitstream bytes inFlight cursor) =
247+
BSL.toStrict $ BSL.reverse paddedBytes
248+
where
249+
paddedBytes
250+
| cursor == 7 = bytes
251+
| otherwise = BSL.cons inFlight bytes
252+
224253
constructGCS ::
225254
-- | modulus
226255
Int ->
227256
-- | sorted list of input values
228257
[Word64] ->
229258
ByteString
230259
constructGCS p =
231-
BiS.toByteString
232-
. foldMap (golombRiceEncode p)
260+
asByteString
261+
. foldl' (golombRiceEncode p) emptyB
233262
. diffs
234263

235264
diffs :: Num a => [a] -> [a]
@@ -239,12 +268,12 @@ unDiffs :: Num a => [a] -> [a]
239268
unDiffs (x : xs) = scanl (+) x xs
240269
unDiffs [] = []
241270

242-
golombRiceEncode :: Int -> Word64 -> Bitstream Right
243-
golombRiceEncode p v = x <> BiS.singleton False <> y
271+
golombRiceEncode :: Int -> Bitstream -> Word64 -> Bitstream
272+
golombRiceEncode p b v = foldl' (flip nextBit) prefix [p - i | i <- [1 .. p]]
244273
where
245274
q = fromIntegral $ v `shiftR` p
246-
x = BiS.replicate q True
247-
y = BiS.fromNBits p v
275+
prefix = appendBit False $ iterate (appendBit True) b !! q
276+
nextBit = appendBit . testBit v
248277

249278
fromBits :: Num a => [Bool] -> a
250279
fromBits = foldl' onBit 0

0 commit comments

Comments
 (0)