packages feed

haskoin-core 1.5.0 → 1.5.1

raw patch · 4 files changed

+53/−12 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

Files

CHANGELOG.md view
@@ -5,6 +5,12 @@ 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). +## [1.5.1] - 2026-11-04++### Fixed++- `nextAsertWorkRequired` evaluates the aserti3-2d formula at the parent of the new block, with the parent's timestamp and height, as `GetNextASERTWorkRequired` does in Bitcoin Cash Node. It used the new block's own timestamp and height, so the bits it required were wrong for every block that did not come exactly ten minutes after its parent. The bits check that 1.5.0 added to `connectBlocks` turned this into a rejected block on Bitcoin Cash mainnet at height 975899.+ ## [1.5.0] - 2026-11-03  ### Added
haskoin-core.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           haskoin-core-version:        1.5.0+version:        1.5.1 synopsis:       Bitcoin & Bitcoin Cash library for Haskell description:    Please see the README on GitHub at <https://github.com/jprupp/haskoin-core#readme> category:       Bitcoin, Finance, Network
src/Haskoin/Block/Headers.hs view
@@ -780,8 +780,12 @@         if isGenesis anchor           then return anchor.header.timestamp           else (.header.timestamp) . fromMaybe e <$> getBlockHeader anchor.header.prev-      let timeDiff = toInteger bh.timestamp - toInteger anchorParentTime-          heightDiff = toInteger par.height + 1 - toInteger anchor.height+      -- The formula is evaluated at the parent, as GetNextASERTWorkRequired+      -- does: the time and the height are the parent's. A block's own+      -- timestamp never changes its own difficulty. The minimum-difficulty+      -- rule above is the only use of the new header.+      let timeDiff = toInteger par.header.timestamp - toInteger anchorParentTime+          heightDiff = toInteger par.height - toInteger anchor.height       return $         computeAsertBits net.powLimit net.asertHalfLife anchor.header.bits timeDiff heightDiff   where@@ -807,9 +811,9 @@   Integer ->   -- | bits of the anchor block   Word32 ->-  -- | seconds from the anchor's parent to the new block+  -- | seconds from the anchor's parent to the parent of the new block   Integer ->-  -- | blocks from the anchor to the new block+  -- | blocks from the anchor to the parent of the new block   Integer ->   Word32 computeAsertBits powLimit halflife anchorBits timeDiff heightDiff
test/Haskoin/BlockSpec.hs view
@@ -856,6 +856,7 @@   let t0 = asertNet.genesisHeader.timestamp       halfLife = 2 * 24 * 60 * 60       regtestLimit = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff+      mainnetLimit = 0x00000000ffff0000000000000000000000000000000000000000000000000000       -- thirty blocks ten minutes apart; block 15 is the first whose median       -- time past reaches the activation time       steady = evenlySpaced asertNet 600 30 0x1f400000@@ -868,13 +869,30 @@     requiredOn asertNet (take 15 steady) (t0 + 600 * 16) `shouldBe` 0x1f400000   it "keeps the target later on the schedule" $     requiredOn asertNet steady (t0 + 600 * 31) `shouldBe` 0x1f400000-  it "doubles the target when the chain is a half-life behind" $-    -- 2^246 * 2 = 2^247 = 0x80 * 2^240, whose sign bit moves the mantissa down one byte-    requiredOn asertNet (take 15 steady) (t0 + 600 * 16 + halfLife) `shouldBe` 0x20008000-  it "halves the target when the chain is a half-life ahead" $-    requiredOn asertNet (take 15 steady) (t0 + 600 * 16 - halfLife) `shouldBe` 0x1f200000-  it "ignores the gap to the parent on mainnet" $-    requiredOn asertNet steady (t0 + 600 * 31 + halfLife) `shouldBe` 0x20008000+  it "ignores the timestamp of the block itself" $ do+    -- The chain up to the parent is on schedule. A block that is a half-life+    -- late or early still carries the unchanged bits; only its children see+    -- the delay.+    requiredOn asertNet steady (t0 + 600 * 31 + halfLife) `shouldBe` 0x1f400000+    requiredOn asertNet steady (t0 + 600 * 31 - halfLife) `shouldBe` 0x1f400000+  it "connects a block that is not exactly ten minutes after its parent" $+    -- Block 31 comes 428 seconds after block 30, as mainnet block 975899+    -- came after its parent, with the unchanged bits of the chain.+    withChain asertNet (storeChain steady >>= connectLate) `shouldBe` Right 31+  it "doubles the target after a parent that is a half-life late" $+    -- Block 16 is 172800 seconds late. From the anchor's parent, block 14,+    -- to block 16 the chain took 1200 + 172800 seconds for two blocks, one+    -- half-life behind schedule. 2^246 * 2 = 2^247 = 0x80 * 2^240, whose sign+    -- bit moves the mantissa down one byte.+    let late = (t0 + 600 * 16 + halfLife, 0x1f400000)+     in requiredOn asertNet (take 15 steady ++ [late]) (t0 + 600 * 17 + halfLife) `shouldBe` 0x20008000+  it "halves the target after a chain that is a half-life ahead" $+    -- 300 blocks 24 seconds apart follow the anchor, block 15. From the+    -- anchor's parent to block 315 the chain took 600 + 300 * 24 = 7800+    -- seconds for 301 blocks instead of 301 * 600 = 180600, which is one+    -- half-life (172800 seconds) ahead of schedule.+    let fast = [(t0 + 600 * 15 + 24 * i, 0x1f400000) | i <- [1 .. 300]]+     in requiredOn asertNet (take 15 steady ++ fast) (t0 + 600 * 15 + 24 * 301) `shouldBe` 0x1f200000   it "allows the minimum difficulty after twice the target spacing on test networks" $     let testNet = (asertNet :: Network) {minDiffBlocks = True}      in requiredOn testNet steady (t0 + 600 * 31 + halfLife) `shouldBe` 0x207fffff@@ -892,6 +910,12 @@   it "does not lower the target below one" $     -- a target of one halved ten times     computeAsertBits regtestLimit 172800 0x01010000 (1200 - 10 * 172800) 1 `shouldBe` 0x01010000+  it "computes the bits of Bitcoin Cash mainnet block 975899" $+    -- The anchor is block 661647 with bits 0x1804dafe and its parent is dated+    -- 1605447844. Block 975898, the parent of 975899, is dated 1793800487:+    -- 1793800487 - 1605447844 = 188352643 seconds and 975898 - 661647 =+    -- 314251 blocks after the anchor.+    computeAsertBits mainnetLimit 172800 0x1804dafe 188352643 314251 `shouldBe` 0x1802308e   describe "aserti3-2d test vectors" $     mapM_       ( \x ->@@ -900,6 +924,13 @@       )       [(1 :: Int) .. 12]   where+    -- Mine block 31 with the chain's bits 428 seconds after block 30 and+    -- connect it with every rule checked.+    connectLate :: [BlockNode] -> State HeaderMemory (Either String BlockHeight)+    connectLate nodes =+      let parent = (last nodes).header+          t0 = asertNet.genesisHeader.timestamp+       in connectHeight asertNet myTime (mineOn asertNet parent (t0 + 600 * 30 + 428) 0x1f400000)     anchorHeights = withChain asertNet $ do       nodes <- storeChain (evenlySpaced asertNet 600 30 0x1f400000)       forM [nodes !! 13, nodes !! 14, nodes !! 19, last nodes] $ \n ->