packages feed

haskoin-core 0.9.5 → 0.9.6

raw patch · 6 files changed

+146/−8 lines, 6 files

Files

CHANGELOG.md view
@@ -4,6 +4,11 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## 0.9.6+### Added+- `bloomRelevantUpdate` implementation for Bloom filters (thanks to @IlyasRidhuan).+- Fix for Bech32 encoding (thanks to @pavel-main).+ ## 0.9.5 ### Added - Expose functions added in 0.9.4.
haskoin-core.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 5f5401cf4317b9dec2a9b9aa52cf78893d599e2b45dc74a8f2bce1653c8a83ad+-- hash: 263bc514478d37e2471bbc351ea84b803c76e518c55d7143d1e7927cd5f49e68  name:           haskoin-core-version:        0.9.5+version:        0.9.6 synopsis:       Bitcoin & Bitcoin Cash library for Haskell description:    Haskoin Core is a complete Bitcoin and Bitcoin Cash library of functions and data types for Haskell developers. category:       Bitcoin, Finance, Network
src/Network/Haskoin/Address/Bech32.hs view
@@ -131,7 +131,7 @@ bech32Encode :: HRP -> [Word5] -> Maybe Bech32 bech32Encode hrp dat = do     guard $ checkHRP hrp-    let dat' = dat ++ bech32CreateChecksum hrp dat+    let dat' = dat ++ bech32CreateChecksum (T.toLower hrp) dat         rest = map (charset !) dat'         result = T.concat [T.toLower hrp, T.pack "1", T.pack rest]     guard $ T.length result <= maxBech32Length
src/Network/Haskoin/Network/Bloom.hs view
@@ -24,6 +24,7 @@     , isBloomEmpty     , isBloomFull     , acceptsFilters+    , bloomRelevantUpdate     ) where  import           Control.Monad                  (forM_, replicateM)@@ -33,14 +34,16 @@ import qualified Data.Foldable                  as F import           Data.Hash.Murmur               (murmur3) import qualified Data.Sequence                  as S-import           Data.Serialize                 (Serialize, get, put)+import           Data.Serialize                 (Serialize, get, put,encode) import           Data.Serialize.Get             (getByteString, getWord32le,                                                  getWord8) import           Data.Serialize.Put             (putByteString, putWord32le,                                                  putWord8) import           Data.Word import           Network.Haskoin.Network.Common-+import           Network.Haskoin.Script.Common+import           Network.Haskoin.Transaction.Common+import           Data.List                      (foldl') -- | 20,000 items with fp rate < 0.1% or 10,000 items and <0.0001% maxBloomSize :: Int maxBloomSize = 36000@@ -193,8 +196,47 @@     isSet i = S.index s (fromIntegral $ i `shiftR` 3)           .&. (bitMask !! fromIntegral (7 .&. i)) /= 0 --- TODO: Write bloomRelevantUpdate--- bloomRelevantUpdate :: BloomFilter -> Tx -> Hash256 -> Maybe BloomFilter+-- | Checks if any of the outputs of a tx is in the current bloom filter.+-- If it is, add the txid and vout as an outpoint (i.e. so that +-- a future tx that spends the output won't be missed).+bloomRelevantUpdate :: BloomFilter       +                    -- ^ Bloom filter+                    -> Tx                +                    -- ^ Tx that may (or may not) have relevant outputs+                    -> Maybe BloomFilter +                    -- ^ Returns an updated bloom filter adding relevant output+bloomRelevantUpdate bfilter tx+    | isBloomFull bfilter || isBloomEmpty bfilter = Nothing+    | bloomFlags bfilter == BloomUpdateNone = Nothing+    | length matchOuts > 0 = Just $ foldl' (addRelevant) bfilter matchOuts+    | otherwise = Nothing+    where+        -- TxHash if we end up inserting an outpoint+        h = txHash tx+        -- Decode the scriptOutpus and add vOuts in case we make them outpoints+        decodedOutputScripts = traverse (decodeOutputBS . scriptOutput) $ txOut tx+        err = error $ "Error Decoding output script"+        idxOutputScripts = either (const err) (zip [0..]) decodedOutputScripts+        -- Check if any txOuts were contained in the bloom filter+        matchFilter = filter (\(_,op) -> bloomContains bfilter $ encodeScriptOut op)+        matchOuts = matchFilter idxOutputScripts++        addRelevant :: BloomFilter -> (Word32,ScriptOutput) -> BloomFilter+        addRelevant bfilter (id,scriptOut) = case (bloomFlags bfilter,scriptType) of+            -- We filtered out BloomUpdateNone so we insert any PayPk or PayMulSig+            (_, True) -> bloomInsert bfilter outpoint+            (BloomUpdateAll, _ ) -> bloomInsert bfilter outpoint+            _ ->  error "Error Updating Bloom Filter with relevant outpoint"+            where+                outpoint = encode $ OutPoint{ outPointHash = h, outPointIndex = id}+                scriptType = (\s -> isPayPK s ||isPayMulSig s) scriptOut++        -- Encodes a scriptOutput so it can be checked agains the Bloom Filter+        encodeScriptOut :: ScriptOutput -> ByteString+        encodeScriptOut (PayMulSig outputMuSig _) = encode outputMuSig+        encodeScriptOut (PayWitnessScriptHash scriptHash) = encode scriptHash+        encodeScriptOut (DataCarrier getOutputData) = encode getOutputData+        encodeScriptOut outputHash = (encode . getOutputHash) outputHash  -- | Returns True if the filter is empty (all bytes set to 0x00) isBloomEmpty :: BloomFilter -> Bool
test/Network/Haskoin/Address/Bech32Spec.hs view
@@ -28,6 +28,8 @@         it "should be a valid address" $ forM_ validAddresses testValidAddress         it "should be an invalid address" $             forM_ invalidAddresses testInvalidAddress+        it "should be same for the input in different case" $+            all (== Just "test12hrzfj") . map (flip bech32Encode []) $ hrpCaseVariants     describe "more encoding/decoding cases" $ do         it "length > 90" $             assert $@@ -141,3 +143,14 @@     , "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv"     , "bc1gmk9yu"     ]++hrpCaseVariants:: [Text]+hrpCaseVariants = map T.pack hrpTestPermutations++hrpTestPermutations :: [String]+hrpTestPermutations = do+    a <- ['t', 'T']+    b <- ['e', 'E']+    c <- ['s', 'S']+    d <- ['t', 'T']+    return [a, b, c, d]
test/Network/Haskoin/NetworkSpec.hs view
@@ -11,8 +11,10 @@ import           Network.Haskoin.Network import           Network.Haskoin.Test import           Network.Haskoin.Util+import           Network.Haskoin.Transaction.Common import           Test.Hspec-import           Test.HUnit                (Assertion, assertBool)+import           Test.HUnit                (Assertion, assertBool,+                                            assertEqual) import           Test.QuickCheck  spec :: Spec@@ -22,6 +24,9 @@         it "bloom filter vector 1" bloomFilter1         it "bloom filter vector 2" bloomFilter2         it "bloom filter vector 3" bloomFilter3+    describe "relevant bloom filter update" $ do+        it "Relevant Update" relevantOutputUpdated+        it "Irrelevant Update" irrelevantOutputNotUpdated     describe "serialization of protocol types" $ do         it "encodes and decodes varint" $             property $ forAll arbitraryVarInt cerealID@@ -107,3 +112,76 @@  testPutGet :: Eq a => Get a -> Putter a -> a -> Bool testPutGet g p a = runGet g (runPut (p a)) == Right a++relevantOutputUpdated :: Assertion+relevantOutputUpdated = assertBool "Bloom filter output updated" $+    any (bloomContains bf2) spendTxInput+    where+        bf0 = bloomCreate 10 0.000001 0 BloomUpdateAll+        relevantOutputHash = fromJust $ decodeHex"03f47604ea2736334151081e13265b4fe38e6fa8"+        bf1 = bloomInsert bf0 relevantOutputHash+        bf2 = fromJust $ bloomRelevantUpdate bf1 relevantTx+        spendTxInput = (encode .prevOutput) <$> txIn spendRelevantTx ++irrelevantOutputNotUpdated :: Assertion+irrelevantOutputNotUpdated = assertEqual "Bloom filter not updated" Nothing bf2 +    where+        bf0 = bloomCreate 10 0.000001 0 BloomUpdateAll+        relevantOutputHash = fromJust $ decodeHex"03f47604ea2736334151081e13265b4fe38e6fa8"+        bf1 = bloomInsert bf0 relevantOutputHash+        bf2 = bloomRelevantUpdate bf1 unrelatedTx+        spendTxInput = (encode .prevOutput) <$> txIn spendRelevantTx ++-- Random transaction (57dc904f32ad4daab7b321dd469e8791ad09df784cdd273a73985150a4f225e9)+relevantTx :: Tx+relevantTx = Tx+        { txVersion = 1+        , txIn = [ TxIn+            { prevOutput = OutPoint "35fe9017b7e3af592920b56fa06ac02faf0c52cdb19dcb416129ac71c95d060e" 1+            , scriptInput = fromJust $ decodeHex "473044022032fc8eef299b7e94b9a986a6aa2dcb9733ab804bef80df995e443b9c1f8c604202203335df7a2e2b4789451cdb4b2b05a786a81c51519eb6a567fd6fe8cd7b2d33fe014104272502dc63a512dad1473cb82a71be9baf4f4303abd1ff6028fc8a78e1f3aec1218907119dec14f07354850758ff0948e88a904fa411c4df7d5444414ec64ad6"+            , txInSequence = 4294967295+            } ]+        , txOut =+            [ TxOut { outValue = 100000000, scriptOutput = fromJust $ decodeHex "76a91403f47604ea2736334151081e13265b4fe38e6fa888ac" }+            , TxOut { outValue = 107980000, scriptOutput = fromJust $ decodeHex "76a91481cc186a2f4a69f633ed4bf10ef4a78be13effdd88ac" }+            ]+        , txWitness = []+        , txLockTime = 0+        }++-- Transaction that spends above (fd6e3b693b844aa431fad46765c1aa019a6b13aebfa9dae916b3ffa43283a300)+spendRelevantTx :: Tx+spendRelevantTx = Tx+        { txVersion = 1+        , txIn = [ TxIn+            { prevOutput = OutPoint "57dc904f32ad4daab7b321dd469e8791ad09df784cdd273a73985150a4f225e9" 0+            , scriptInput = fromJust $ decodeHex "483045022100ecc334821e4e94cc2fdc841d5ad147d5bb942b993ba81460cc446e0410afa811022015fcbc542b734dbb61a05ec06012095096de5839c50808fe56f2b315e877c20d012103fb64e5792fa586172339b776b7017d3d529358cb73be6406a1fc994228d14f88"+            , txInSequence = 4294967295+            }, TxIn+            { prevOutput = OutPoint "cfee6a8d6e68e8fd16df6fff010afffcd19d7e075aa7b707dd1bae6adc420042" 0+            , scriptInput = fromJust $ decodeHex "47304402200e6bb95fa606f254d17089d83c4ceeb19c5d1699b4faddcd4f1f1568286e6b650220087fb8439f31e1b30e47710d095422405f601d6151f2f93e125e1a08a6e29ad4012103b49252e8fc6d5b49c8d14ee71fab45591df4a126a6c453c724f3d356e38f0cee"+            , txInSequence = 4294967295+            } ]+        , txOut =+            [ TxOut { outValue = 3851100, scriptOutput = fromJust $ decodeHex "76a914a297cae82a9a3b932bf023ae274fe2585295c9ca88ac" }+            , TxOut { outValue = 111000000, scriptOutput = fromJust $ decodeHex "76a9148f952c38600a61385974acc30a64f74407f9801488ac" }+            ]+        , txWitness = []+        , txLockTime = 0+        }++-- This random transaction is unrelated to the others+unrelatedTx :: Tx+unrelatedTx = Tx+        { txVersion = 1+        , txIn = [ TxIn+            { prevOutput = OutPoint "3ec3a71431c68e5d978a5fb4a0a1081d8bee8384d8aa4c06b1fbaf9413e2214f" 20+            , scriptInput = fromJust $ decodeHex "483045022100ec9c202c9d3140b973aca9d7f21a82138aa4cfa43fddc5419098ac5e26a6f152022010848fd688f290ae010fb5cb493410caa03145fc12445900ec1ad2bde33aecd9012102c7445e72d723f99a0064526c28269d07f47c8fd81531a94a8d3bf5ebd5e23ef1"+            , txInSequence = 4294967295+            }]+        , txOut =+            [ TxOut { outValue = 12600000, scriptOutput = fromJust $ decodeHex "76a9148fef3b7051de8cc44e966159e7ea37f4520187e888ac" }+            ]+        , txWitness = []+        , txLockTime = 0+        }