MIT licensed by JP Rupp
Maintained by [email protected]
This version can be pinned in stack with:haskoin-node-2.3.1@sha256:717cd15daa660737407c591e0d4b8169c72bba850ea9253adb5232403a004d71,2261

Module documentation for 2.3.1

Haskoin Node

Hackage License: MIT

Haskoin Node is a peer-to-peer networking library for Bitcoin (BTC) and Bitcoin Cash (BCH), written in Haskell. It connects to the network, keeps a pool of healthy peers, and syncs block headers into a RocksDB database.

It does not download or validate blocks and transactions by itself. It publishes everything that happens as events, and gives you the peers to ask for the data you need. It is the networking layer of Haskoin Store.

Contents

Why Haskoin Node

A program that wants Bitcoin data has two usual options. It can run a full node such as Bitcoin Core next to it and talk to its RPC interface, which means operating a second large piece of software. Or it can speak the peer-to-peer protocol itself, which means solving the same problems every node solves: finding peers, keeping good ones, dropping bad ones, parsing untrusted messages safely, and following the header chain through reorganisations.

Haskoin Node solves those problems once, as a library. It gives a Haskell program a direct, well-behaved presence on the network, and stops there: what to download, what to validate and what to store is up to the program. It is the networking layer of Haskoin Store, which indexes the whole Bitcoin and Bitcoin Cash block chains this way without a full node.

Design principles

  • Do one job. Keep connected and keep the header chain current. Blocks, transactions, validation and storage of anything but headers belong to the application, because every application wants something different.
  • Headers are the source of truth. Headers are small (80 bytes) and carry the proof of work. With them, the node knows which chain is real without downloading blocks, and can tell the application which blocks to fetch.
  • Tell, don’t ask. Everything the node learns becomes an event on a publisher. The application subscribes and reacts; the node never needs to know who is listening.
  • Peers are strangers. Message sizes are checked before payloads are read, anything invalid ends the connection, relayed addresses are filtered, and a peer cannot push data faster than the node can handle it.
  • Prefer good peers, but keep moving. Peers are ranked by measured latency so the fastest are used first, and every connection is eventually replaced so the node never depends on the same few peers forever.
  • Small, isolated components. The peer manager, the header chain and each connection are separate NQE processes with their own state. One misbehaving peer dies alone.

Features

Area What you get
Networks Every network of haskoin-core: Bitcoin and Bitcoin Cash mainnet, testnets and regtest
Peer discovery DNS seeds and addresses relayed by peers, or a static list of peers
Peer management Version handshake, ping-based latency, peers sorted by median ping, rotation after a maximum age
Header sync Headers downloaded from one peer at a time, connected to the chain with the most work, stored in RocksDB
Events Best header changes, sync completion, peer connections and every message received
Data requests Fetch blocks and transactions from a peer, with a timeout
Protection Strict parsing, per-command size limits, back-pressure, bounded address pool

What is not included

  • No block or transaction validation, and no mempool. Haskoin Store does this on top of the events.
  • No inbound connections: the node only connects out.
  • No compact blocks, Bloom filters (BIP-37) or compact block filters (BIP-157).

Installation

System libraries

Haskoin Node needs RocksDB and libsecp256k1 0.2.0 or later, with pkg-config to find them.

# Debian and Ubuntu
sudo apt-get install librocksdb-dev libsecp256k1-dev pkg-config

# Fedora
sudo dnf install rocksdb-devel libsecp256k1-devel pkgconf

# macOS with Homebrew
brew install rocksdb secp256k1 pkg-config

# Nix
nix-shell -p rocksdb secp256k1 pkg-config

Some older distributions ship a libsecp256k1 below 0.2.0. See the haskoin-core installation notes for how to build it.

Check the libraries are found

pkg-config --modversion libsecp256k1   # 0.2.0 or later
ls /usr/include/rocksdb/c.h            # or $(brew --prefix)/include/rocksdb/c.h

Compiler

It needs GHC 9.2 or later, because it uses OverloadedRecordDot. It is built and tested with the GHC of the Stackage nightly in stack.yaml.

With Cabal

build-depends:
    base
  , data-default
  , haskoin-core
  , haskoin-node
  , nqe
  , rocksdb-haskell-jprupp

You open the database with rocksdb-haskell-jprupp and create the event publisher with nqe.

With Stack

Recent Stackage nightly snapshots include Haskoin Node. With an older resolver, add it and its dependencies to stack.yaml:

extra-deps:
  - haskoin-node-2.3.1
  - haskoin-core-1.6.1
  - secp256k1-haskell-2.0.0
  - base16-2.0
  - rocksdb-haskell-jprupp-2.6.1
  - rocksdb-query-0.6.1
  - nqe-0.6.9

Step by step with Stack

  1. Install Stack and the libraries above.

  2. Create a project:

    stack new node-demo simple
    cd node-demo
    
  3. Add the packages listed under With Cabal to build-depends in node-demo.cabal, plus network.

  4. If your resolver is older than the packages, add the extra-deps shown under With Stack to stack.yaml.

  5. Put the quick start program in src/Main.hs and run it:

    stack run
    

    Within a few seconds it logs connections and starts printing header heights. A full header sync of Bitcoin usually takes minutes and on the order of a hundred megabytes of disk; it resumes where it stopped if you interrupt it.

Quick start

This program connects to Bitcoin, syncs headers, and prints what happens:

{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedRecordDot #-}

import Control.Monad (forever)
import Data.Default (def)
import Database.RocksDB (Config (..), withDB)
import Haskoin (NetworkAddress (..), btc, sockToHostAddress)
import Haskoin.Node
import NQE (receive, withPublisher, withSubscription)
import Network.Socket (SockAddr (..))

main :: IO ()
main =
  withLogger LevelInfo $ \logger ->
    withDB "/tmp/haskoin-node" def {createIfMissing = True} $ \db ->
      withPublisher $ \pub ->
        withSubscription pub $ \events -> do
          let cfg =
                NodeConfig
                  { maxPeers = 8,
                    db = db,
                    cf = Nothing,
                    peers = [],
                    discover = True,
                    address = NetworkAddress 0 (sockToHostAddress (SockAddrInet 0 0)),
                    net = btc,
                    pub = pub,
                    timeout = 120,
                    maxPeerLife = 48 * 3600,
                    connect = withConnection,
                    logger = logger
                  }
          withNode cfg $ \_node -> forever $
            receive events >>= \case
              ChainEvent (ChainBestBlock bn) ->
                putStrLn ("Best header: " <> show bn.height)
              ChainEvent (ChainSynced _) ->
                putStrLn "Headers in sync"
              PeerEvent (PeerConnected p) ->
                putStrLn ("Connected: " <> show p)
              _ -> return ()

Subscribe to the publisher before calling withNode, as here, or you may miss the first events.

Tutorial: a block watcher

This builds a program that prints every new Bitcoin block with its number of transactions. It shows the intended division of labour: the node follows headers and tells you about them, and you fetch what you need.

1. Wait until the headers are synced

At start-up the node downloads hundreds of thousands of headers, each one a ChainBestBlock event. Reacting to each of those would mean fetching every historical block. Wait for ChainSynced first:

waitSynced :: Inbox NodeEvent -> IO ()
waitSynced events =
  receive events >>= \case
    ChainEvent (ChainSynced _) -> return ()
    _ -> waitSynced events

2. React to new best headers

After that, each ChainBestBlock is a new block at the tip, or the new tip after a reorganisation:

watch :: Network -> Node -> Inbox NodeEvent -> IO ()
watch net node events = forever $
  receive events >>= \case
    ChainEvent (ChainBestBlock bn) -> fetch net node bn
    _ -> return ()

3. Fetch the block from the fastest peer

getPeers lists online peers, fastest first. Ask one, and try the next if it fails or times out:

fetch :: Network -> Node -> BlockNode -> IO ()
fetch net node bn = getPeers node.peerMgr >>= go
  where
    hash = headerHash bn.header
    go [] = putStrLn ("No peer could send block " <> show bn.height)
    go (op : ops) =
      getBlocks net 30 op.mailbox [hash] >>= \case
        Just [b] ->
          putStrLn (show bn.height <> ": " <> show (length b.txs) <> " transactions")
        _ -> go ops

4. Put it together

Use the configuration from the quick start, and run the watcher inside withNode:

withNode cfg $ \node -> do
  waitSynced events
  watch btc node events

What the node did for you

While this runs, the node keeps eight connections, measures and ranks them, drops silent or misbehaving peers and finds replacements, stores headers so a restart is quick, and switches to a heavier chain if one appears. The watcher is only twenty lines because none of that is its concern.

Concepts

Components

withNode starts two processes, built with NQE:

  • The peer manager (Haskoin.Node.PeerMgr) finds peer addresses, connects to them, does the version handshake, pings them, and drops those that are slow, silent, misbehaving or too old.
  • The chain (Haskoin.Node.Chain) asks one peer at a time for headers, connects them to the headers it has, follows the chain with the most work, and stores the headers in RocksDB.

Each peer connection is its own process (Haskoin.Node.Peer), run by a supervisor inside the peer manager.

Events

Everything is published to the Publisher NodeEvent in the configuration:

Event When
ChainEvent (ChainBestBlock node) The best header changed, including on start
ChainEvent (ChainSynced node) Headers caught up with the network (once)
PeerEvent (PeerConnected peer) A peer finished the handshake
PeerEvent (PeerDisconnected peer) An online peer went away
PeerEvent (PeerMessage peer msg) A peer sent a message: MInv, MBlock, MTx and so on

“In sync” means the best header is less than two hours old, has at least the minimum chain work of the network, and no peer is left to sync from.

Back-pressure

A peer may have at most 16 messages published and not yet handled by the node. Past that, the node stops reading its socket, so a fast peer fills its own TCP window instead of the node’s memory. Your subscriber should keep reading events; a subscription that falls far behind holds memory.

Database layout

Headers are stored in the column family you configure, or the default one:

Key prefix Value
0x90 header (BlockNode) by hash
0x91 best header
0x92 data version

You can keep your own data in the same database, as Haskoin Store does, as long as your keys do not start with these bytes.

Usage guide

Picking a peer and requesting data

ps <- getPeers node.peerMgr -- online peers, fastest first
case ps of
  op : _ -> do
    let p = op.mailbox
    mblocks <- getBlocks btc 30 p [blockHash] -- Maybe [Block]
    mtxs <- getTxs btc 30 p [txHash] -- Maybe [Tx]
    sendMessage MMempool p
  [] -> return ()

getBlocks, getTxs and getData return Nothing if the peer does not send everything, in order, before the timeout in seconds. pingPeer measures a round trip.

Querying headers

best <- chainGetBest node.chain
mnode <- chainGetBlock node.chain someHash
isMain <- chainBlockMain node.chain someHash
fork <- chainGetSplitBlock node.chain nodeA nodeB
parents <- chainGetParents node.chain height top
synced <- chainIsSynced node.chain

runChainT runs the header functions of haskoin-core, such as getAncestor, against the database of the chain.

Static peers

cfg {peers = ["node1.example.com", "10.0.0.5:8333", "[2001:db8::1]:8333"], discover = False}

A peer without a port uses the default port of the network.

Custom connections

connect decides how to open a connection. withConnection opens a plain TCP socket. Replace it to go through a proxy, or to plug in mock peers in tests, as the test suite does.

Logging

withLogger level logs to standard error, one line per message, such as [Info#Chain] Best block header at height 870000. Build a Logger with your own push function to log elsewhere.

Configuration

Field Meaning
maxPeers Maximum number of peers to connect to
db RocksDB handle for the headers
cf Column family for the headers, or Nothing for the default one
peers Static peers, as host, host:port or [ipv6]:port
discover Use DNS seeds and addresses relayed by peers
address This node’s address, sent in version messages
net Network constants from haskoin-core (btc, bch, btcTest, …)
pub Publisher that receives every NodeEvent
timeout Seconds of silence, or without a pong, before a peer is dropped
maxPeerLife Seconds after which a peer is dropped, so that connections rotate
connect How to open a connection; usually withConnection
logger Where to log; see withLogger

Module overview

Haskoin.Node is the only exposed module. It re-exports:

Part Contents
Node NodeConfig, NodeEvent, Node, withNode, withConnection
Peers Peer, PeerEvent, sendMessage, getBlocks, getTxs, getData, pingPeer, killPeer
Peer manager PeerMgr, OnlinePeer, getPeers, getOnlinePeer, toSockAddr, isRoutable
Chain Chain, ChainEvent, chainGetBest, chainGetBlock, chainGetAncestor, chainGetParents, chainGetSplitBlock, chainBlockMain, chainIsSynced, runChainT
Logging Logger, LogLevel, withLogger, withSource, logDebug … logError

The lower-level functions that feed messages to the peer manager and the chain are exported too, for programs that wire the components themselves.

Security notes

  • Every message header is checked before its payload is read. The payload limit is the maxPayloadSize of the command on the network: on Bitcoin Cash, 2 MiB for everything but block messages.
  • List messages are refused as soon as their count is over the limit, such as 2000 headers, 1000 addresses or 50000 inventory entries.
  • A peer that sends anything invalid is disconnected.
  • Addresses relayed by peers are only used if they are public unicast addresses, so a peer cannot make the node connect to services on its own host or network. Static peers are not checked.
  • At most 4096 relayed addresses are kept.
  • Headers are not reported as synced until they have the minimum chain work of the network. Above that work, forks from far below the tip on a chain with less work are refused.
  • The node trusts the chain with the most work. It does not validate blocks: check the data you get from peers before relying on it.

Development

git clone https://github.com/jprupp/haskoin-node.git
cd haskoin-node

stack build                        # build the library
stack test                         # run the tests
stack haddock --no-haddock-deps    # build the API documentation

On NixOS, or with stack --nix, the nix section of stack.yaml provides RocksDB and libsecp256k1.

package.yaml is the source of the package description. Change it rather than haskoin-node.cabal, which hpack generates.

The tests are in test/ and use hspec. They run against mock peers on the Bitcoin Cash regression test network, so they need no Internet access.

Contributing

Pull requests are welcome.

Related projects

  • haskoin-core has the Bitcoin data types and protocol that this library speaks.
  • haskoin-store indexes blocks and transactions on top of this node and serves them over a REST API.
  • nqe provides the processes, supervisors and publishers.
  • rocksdb-query stores the headers.

License

Haskoin Node is released under the MIT License.

Changes

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog and this project adheres to Semantic Versioning.

[2.3.1] - 2026-11-07

Changed

  • Documentation: the README explains the purpose and design of the node, with installation steps, configuration, security notes and a tutorial, and the Haddock of every module and function says why it works the way it does.
  • Build against nqe 0.6.9, rocksdb-haskell-jprupp 2.6.1, rocksdb-query 0.6.1 and Stackage nightly-2026-11-07.

[2.3.0] - 2026-11-06

Changed

  • This package requires haskoin-core 1.6.0, the release with the fixes of the November 2026 security review.
  • Breaking: the version, timestamp and startHeight fields of the Version of an OnlinePeer are signed numbers, as haskoin-core 1.6.0 reads them. buildVersion takes the same arguments as before.
  • The headers are not reported as synced before the best header has the minimumChainWork of the network. This holds for the ChainSynced event and for chainIsSynced. A recent header on a chain with less work used to be enough.
  • Once the best header has the minimumChainWork of the network, a peer whose headers fork from far below the tip, on a chain with less work, is disconnected. haskoin-core 1.6.0 refuses such headers.
  • A peer that sends a header the node already has at or below a checkpoint is no longer disconnected. haskoin-core 1.6.0 returns the stored header.
  • Transactions from Bitcoin Cash peers are read in the format without witness only, as haskoin-core 1.6.0 reads them on a network without SegWit.
  • The log line for an invalid payload gives the reason the parser refused it.
  • The payload size limit is the maxPayloadSize of the command on the network instead of the network’s maxMessageSize. On Bitcoin Cash that is 2 MiB for every message but block, cmpctblock and blocktxn, which may be twice the block size.

Fixed

  • Peers that send more than 50000 entries in an inv or getdata message, or a block locator of more than 101 hashes, are disconnected. haskoin-core 1.6.0 refuses such a message as soon as it reads the count.

[2.2.0] - 2026-11-04

Changed

  • Breaking: Peer has a pending field, wrapPeer takes its TVar Int, and peer takes the Peer that wrapPeer built instead of the busy TVar.
  • Messages from a peer apply backpressure. A peer may have at most maxPendingMessages messages waiting for the node; after that the node stops reading its socket until it catches up. Address, header, version, verack, ping and pong messages are handled to completion before the next one is taken. A fast peer could fill the node’s unbounded queues before.
  • Outgoing messages are logged by command at debug level, not in full.

Fixed

  • Bitcoin Cash headers sync again. This package now requires haskoin-core 1.5.1, which evaluates the ASERT difficulty rule at the parent block. With haskoin-core 1.5.0 the node stopped at mainnet block 975899 with Incorrect difficulty bits, because that release checked the bits of each header with a formula that used the header’s own timestamp.
  • Network magic and payload size are checked right after the message header, before the payload is read. The size limit is the network’s maxMessageSize instead of a fixed 32 MiB. An oversized message used to be logged and its payload then parsed as the next header.
  • Peers that send more than 2000 headers or more than 1000 addresses in one message are disconnected before the message is decoded.
  • Address and header messages from a peer are ignored until it completes the handshake.
  • A second version or verack from a peer disconnects it. Each one used to announce the peer as connected again.
  • Relayed addresses that are not public unicast addresses (loopback, private, link-local, multicast, documentation and similar ranges, or port 0) are not added to the address pool. isRoutable is exported.
  • A peer that does not answer a ping within the timeout is disconnected, even if it keeps sending other messages.
  • Only headers from the syncing peer reset its sync timeout. Another peer’s headers could keep a silent syncing peer from ever timing out.
  • The peer manager rechecks maxPeers when it handles a queued connection, so the connect loop can no longer go over the limit while the manager is busy.
  • Purging an old chain database with a column family deleted the same keys from the default column family too. The purge now deletes keys as it walks them instead of building a list of all of them in memory.

[2.1.2] - 2026-11-04

Fixed

  • An empty headers message from the syncing peer ends the header sync. The node used to take it as a reason to ask the same peer again, and kept sending getheaders in a tight loop, thousands per second, whenever its best header was the peer’s tip after a full batch of 2000.

[2.1.1] - 2026-11-04

Changed

  • The loop that parses messages from a peer uses loopForever too, like every other long-running loop.
  • Tests use IPv4 only: the mock peer is at 127.0.0.1 instead of [::1], and the address property test generates IPv4 addresses. On a host without IPv6 the mock peer could not be resolved and the peer and chain tests hung.

[2.1.0] - 2026-11-03

  • Update to haskoin-core-1.5.0.

[2.0.0] - 2026-10-31

Changed

  • Replace monad-logger with fast-logger. Configuration records take a Logger, and functions need only MonadIO or MonadUnliftIO.
  • Require haskoin-core 1.5.0, whose buildMerkleRoot returns Either String MerkleRoot.

[1.4.4] - 2026-08-31

Added

  • Log connectBlocks error message.

Changed

  • Peer connection logged incorrectly as warn is now logged as info.

Fixed

  • Correct documentation for importHeaders function.

[1.4.3] - 2026-08-13

Fixed

  • Fix regression with peer disconnection.

[1.4.2] - 2026-08-13

Fixed

  • Fix regression with peer selection.

[1.4.1] - 2026-08-13

Removed

  • Remove PeerException type which is no longer used.

[1.4.0] - 2026-08-13

Changed

  • Add monad transformers and monad-logger again because logging is too slow.

[1.3.1] - 2026-08-12

Added

  • Add monad transformers to support haskoin-store.

[1.3.0] - 2026-08-12

Changed

  • Simplify modules to make compatible with upstream changes.

[1.2.0] - 2026-08-12

Changed

  • Upstream changes on multiple libraries.

[1.1.4] - 2025-05-08

Changed

  • Move to personal repository.

[1.1.3] - 2024-05-23

Fixed

  • Tickle a peer whenever a message is received.

[1.1.2] - 2024-05-23

Fixed

  • Correct log messages from peer manager.

[1.1.1] - 2024-05-23

Fixed

  • Peers timeout more aggressively.

[1.1.0] - 2024-03-14

Changed

  • Update LTS Haskell & upstream dependencies.

[1.0.1] - 2023-08-03

Changed

  • Add compatibility with latest LTS Haskell.

[1.0.0] - 2023-07-28

Changed

  • Make compatible with latest haskoin-core.
  • Use DuplicateRecordFields and OverloadedRecordDot.
  • Simplify pub/sub queues.
  • Multiple refactoring passes.

[0.18.1] - 2022-07-27

Fixed

  • Set default port for peers where it is unset.

[0.18.0] - 2022-07-27

Added

  • Support setting up and connecting to IPv6 peers.

[0.17.14] - 2021-08-14

Fixed

  • Reduce verbosity on incoming header decode test.
  • Show appropriate error message upon receiving empty headers.

[0.17.13] - 2021-08-14

Added

  • Display more details about invalid incoming headers.

[0.17.12] - 2021-05-17

Fixed

  • Do not connect to more than the maximum number of peers.

[0.17.11] - 2021-05-17

Added

  • Display message command that disconnects a peer.

[0.17.10] - 2021-05-17

Fixed

  • Correct disconnect timeout algorithm bug.

[0.17.9] - 2021-05-17

Fixed

  • Add randomised timeouts to avoid disconnecting all peers.

[0.17.2] - 2021-03-09

Fixed

  • Do not start chain actor until database initialized.

[0.17.1] - 2021-01-08

Changed

  • Depend on haskoin-core-0.17.3.

[0.17.0] - 2020-10-21

Added

  • Support for Bitcoin Cash November 2020 hard fork.
  • BlockHeaders instance for ReaderT Chain.

[0.16.0] - 2020-07-23

Changed

  • Add support for column families.

[0.15.0] - 2020-07-20

Changed

  • Use new Haskell bindings for RocksDB.

[0.14.1] - 2020-06-19

Fixed

  • Correct flawed peer locking logic in Chain actor.

[0.14.0] - 2020-06-18

Changed

  • Massively refactor everything in a non-backwards-compatible way.
  • Use MIT license.
  • Bump haskoin-core.
  • Bump secp256k1-haskell.

Fixed

  • Fix getting stuck on a single peer.

[0.13.0] - 2020-05-08

Changed

  • Depend on Haskoin Store 0.13.3.
  • Better code organisation.

[0.12.0] - 2020-05-06

Changed

  • Add a test suite that simulates network instead of connecting to real one.

[0.11.3] - 2020-05-03

Changed

  • Revert including multiline decoding error text in logs.

[0.11.2] - 2020-05-03

Changed

  • Include header decoding error text in logs.

[0.11.1] - 2020-05-03

Changed

  • Improve logging.

[0.11.0] - 2020-05-03

Changed

  • Set peer too old time

[0.10.1] - 2020-05-03

Changed

  • Disconnect old peers after 48 hours instead of 30 minutes.

[0.10.0] - 2020-05-03

Changed

  • Move modules out of Network.Haskoin namespace.
  • Add better and more logging.
  • Change Manager module name and related values to PeerManager.

[0.9.21] - 2020-04-07

Removed

  • Remove unnecessary logging.

[0.9.20] - 2020-04-07

Changed

  • Better log messages.
  • Less verbose debug logging.

[0.9.19] - 2020-04-07

Changed

  • Better log messages.

[0.9.18] - 2020-04-07

Added

  • More aggressive peer discovery.

[0.9.17] - 2020-04-07

Added

  • Peers are disconnected automatically after awhile.

[0.9.16] - 2020-02-08

Added

  • Lower bound versions for some dependencies.

[0.9.15] - 2020-01-15

Changed

  • Update to support new NetworkAddress data structure from haskoin-core.

[0.9.14] - 2019-12-10

Removed

  • No longer support storing peers in db as performance tradeoff doesn’t justify it.

[0.9.13] - 2019-10-08

Changed

  • Really store peers in db.

[0.9.12] - 2019-10-08

Changed

  • Demote some logging to debug level.

[0.9.11] - 2019-10-02

Added

  • Add -O2 optimisations to GHC.

[0.9.10] - 2019-04-19

Added

  • Increase debugging information where application freezes.

[0.9.9] - 2019-04-12

Added

  • Increase debugging information.

[0.9.8] - 2019-04-12

Changed

  • Increase version of haskoin-core to 0.9.0.
  • Fix some tests.

[0.9.7] - 2019-04-12

Added

  • More debugging.

Changed

  • Be defensive against duplicate peers.
  • Increase interval between housekeeping pings.
  • Replace peers in database atomically.

[0.9.6] - 2019-04-01

Changed

  • Randomize known peers instead of keeping scores.
  • Simplify peer management code to avoid freezes.
  • Merge logic for chain and manager.

[0.9.5] - 2018-11-14

Changed

  • Do not record new peers in database when peer discovery is disabled.

[0.9.4] - 2018-11-01

Changed

  • Don’t spam best block events.

[0.9.3] - 2018-10-22

Changed

  • Correct display of milliseconds in log.
  • Correct bug when receiving headers from unknown peer.
  • Simplify chain syncing code.

[0.9.2] - 2018-10-18

Changed

  • Peer dies immediately when receiving a bad message.

[0.9.1] - 2018-10-18

Changed

  • Keep track of last synced header from a peer to avoid endless loops on large reorgs.

[0.9.0] - 2018-10-17

Changed

  • Use an STM listener instead of a publisher for the node API.

[0.8.2] - 2018-10-17

Added

  • Expose ChainMessage and ManagerMessage types from Haskoin.Node module.

[0.8.1] - 2018-10-11

Changed

  • Corrected documentation for killPeer function.
  • Leave time out of logic code.

[0.8.0] - 2018-10-09

Changed

  • Peers are now killed directly instead of through peer manager.

Removed

  • Chain no longer needs peer manager.

[0.7.2] - 2018-10-09

Added

  • Compatibility with base 4.12.

Changed

  • Update base to 4.9.

[0.7.1] - 2018-10-09

Added

  • Allow to easily obtain a peer’s publisher.

[0.7.0] - 2018-10-09

Added

  • Versioning for chain and peer database.
  • Automatic purging of chain and peer database when version changes.
  • Add extra timers.
  • Add publishers to every peer.

Changed

  • Full reimplementation of node API.
  • Simplify peer selection and management.
  • Merge manager and peer events.
  • Rename configuration variables for node.
  • Separate logic from actors for peer manager and chain.

Removed

  • Remove irrelevant fields from peer information.
  • Remove unreliable peer block head tracking.
  • Remove dependency on deprecated binary conduits.
  • Remove Bloom filter support from manager.
  • Remove unreliable peer request tracking code.
  • Remove separate manager events.

[0.6.1] - 2018-09-14

Changed

  • Fix bug where peer height did not update in certain cases.

[0.6.0] - 2018-09-14

Added

  • Documentation everywhere.

Changed

  • Make compatible with NQE 0.5.
  • Use supervisor only in peer manager.
  • API quality of life changes.
  • Exposed module is now only Haskoin.Node.

Removed

  • No more direct access to internals.

[0.5.2] - 2018-09-10

Changed

  • Improve dependency definitions.

[0.5.1] - 2018-09-10

Changed

  • Dependency sec256k1 changes to secp256k1-haskell.

[0.5.0] - 2018-09-09

Added

  • New CHANGELOG.md file.
  • Use nqe for concurrency.
  • Peer discovery.
  • RocksDB peer and block header storage.
  • Support for Merkle blocks.

Changed

  • Split out of former haskoin repository.
  • Use hpack and package.yaml.
  • Old haskoin-node package now renamed to old-haskoin-node and deprecated.

Removed

  • Removed Old Haskoin Node package completely.
  • Removed Stylish Haskell configuration file.
  • Remvoed haskoin-core and haskoin-wallet packages from this repository.