{
  "schema_version": "sg_node_software_series.v1",
  "dataset": "sg-node-software",
  "methodology_version": "1.1.0",
  "headline_population": "connected",
  "populations": {
    "connected": "Reachable clearnet nodes in KIT's daily snapshot: the IPv4 and IPv6 peers its monitor was connected to when the snapshot was taken, by self-reported user agent.",
    "opened_24h": "Of those, the peers whose current connection to KIT's monitor began within 24 hours of the snapshot."
  },
  "source": {
    "name": "KIT KASTEL DSN Bitcoin Network Monitor",
    "publisher": "Decentralized Systems and Network Services Research Group, KASTEL, Karlsruhe Institute of Technology",
    "data_page": "https://www.dsn.kastel.kit.edu/bitcoin/data.html",
    "listing": "https://www.dsn.kastel.kit.edu/bitcoin/snapshots/?curl",
    "snapshot_url_template": "https://www.dsn.kastel.kit.edu/bitcoin/snapshots/{snapshot}_dossier.json",
    "licence": "CC BY 4.0",
    "licence_url": "https://creativecommons.org/licenses/by/4.0/",
    "doi": "10.5281/zenodo.14627525",
    "citation": "Neudecker, Till; Grundmann, Matthias; Hartenstein, Hannes. Bitcoin Peer-To-Peer Network Monitoring. Zenodo. doi:10.5281/zenodo.14627525",
    "changes": "Per-peer records reduced to daily counts by implementation, IP version, Bitcoin Core release line and two announced service flags, and aggregated by Satoshi Gazette; the opened_24h population is additionally filtered to connections that began within 24 hours of the snapshot. No per-peer data is republished."
  },
  "lifecycle_file": "content/data/core-lifecycle.json",
  "ua_rules": [
    {
      "implementation": "unknown",
      "rule": "No user agent, or one not in the BIP 14 form /name:version/."
    },
    {
      "implementation": "btcd",
      "rule": "A btcd:<version> token anywhere, e.g. /btcwire:0.5.0/btcd:0.26.2/."
    },
    {
      "implementation": "knots",
      "rule": "First token Satoshi:<version> with a Knots:<version> token after it, e.g. /Satoshi:29.4.2/Knots:20260508/. Comments in parentheses and later tokens are ignored."
    },
    {
      "implementation": "core",
      "rule": "Satoshi:<version> as the only name:version token. Comments in parentheses, which Core's -uacomment option adds, are ignored."
    },
    {
      "implementation": "other",
      "rule": "Any other well-formed user agent: Satoshi-led strings with a further name:version token (modified builds such as /Satoshi:29.4/Purity:1.0.0/), look-alikes such as /OracleKnots:29.4.2/, and other software."
    }
  ],
  "method": {
    "population": "Each KIT snapshot lists the peers its monitor was connected to when the snapshot was taken, over IPv4 and IPv6 only (no Tor or I2P). KIT documents lastConnect as the beginning of the last connection to the peer, so an old lastConnect marks a long-held connection, not a stale record: peers leave the snapshot when their connection ends, and the protocol latency and relay counts of long-held connections keep changing from one daily snapshot to the next. The connected population is every peer in the snapshot. The opened_24h population keeps only peers whose current connection began within 24 hours of the snapshot; it is recorded beside the connected population, not instead of it, because it over-weights peers that reconnect often.",
    "clock": "KIT names each snapshot by its time in UTC (YYYYMMDD_HHMMSS) but writes lastConnect in its local clock with no zone. The offset is derived from each file as the whole-hour gap between its latest lastConnect and the snapshot time; that gap must leave the latest connection within the 15 minutes before the snapshot and must equal Europe/Berlin's UTC offset at that instant (KIT is in Karlsruhe). Every row records the offset it used.",
    "classification": "Each peer is classified by the user agent it advertised, using the rules in ua_rules, first match wins. User agents are self-reported and a node can advertise any string, so the shares count what nodes say they run.",
    "lifecycle": "Core peers are counted by release line and classified against content/data/core-lifecycle.json (bitcoincore.org/en/lifecycle) as at the snapshot date: maintained, end of life, unreleased (a line not yet released on that date, or an x.99 development build) or not listed (a line the table does not carry, or a version that does not parse). Knots and other implementations are not classified, because bitcoincore.org's lifecycle covers Bitcoin Core only.",
    "service_flags": "Each connected peer is also sorted by two service flags in the version message it sent, which KIT records as one services number: NODE_BLAKE2B (bit 28), which Bitcoin Knots' source defines as a node enforcing its BLAKE2b hard-fork rules (BLAKE2b proof of work and the reduced-data rules), and NODE_REDUCED_DATA (bit 27), a node enforcing the reduced-data rules of BIP 110 (src/protocol.h at tag v29.4.2.knots20260508). Bitcoin Core's protocol.h defines neither bit. A peer announces the BLAKE2b flag only, the reduced-data flag only, both or neither; a peer whose services number is missing or unreadable is unknown, never neither. The split is counted over all connected peers and over the Knots peers among them. A flag, like a user agent, is the node's own claim: a node can set any bit, and KIT's file records no chain tip for a peer, so the split counts what peers announce, not which chain they follow. A row recorded before this rule (method 1.1.0) carries the split only when the same KIT snapshot, re-read, matches the row's sha256 and re-derives every count the row holds; otherwise its service_flags is null.",
    "precision": "Rows store counts only. A share is printed to one decimal place when its population holds at least 1,000 nodes and to a whole percent below that, so the last printed digit never stands for less than one node.",
    "decision": "Headline population, set on 1 Oct 2026: all connected peers, with the subset whose connection opened within 24 hours beside it.",
    "holds": "A day is held and nothing is written when: the newest snapshot is more than 48 hours old by KIT's clock; the file is under 1 MB or is not JSON; any record lacks a readable lastConnect or has one after the snapshot; the clock offset cannot be derived; the snapshot holds fewer than 1,000 peers; a population's count is outside ±25% of the median of the previous seven rows (once three rows exist); or peers with no identifiable user agent are 2% or more of either population."
  },
  "rows": [
    {"day":"2026-09-28","snapshot":"20260928_121014","snapshot_at":"2026-09-28T12:10:14Z","clock_offset_minutes":120,"lifecycle_as_of":"2026-10-01","sha256":"2cfb1d62800183710905b25b8de8ffa8d45ad17c4e44d006494b0b575f526d6d","connected":{"nodes":8951,"ipv4":7114,"ipv6":1837,"ip_unknown":0,"implementation":{"core":7790,"knots":1010,"btcd":19,"other":74,"unknown":58},"core_lifecycle":{"maintained":4399,"end_of_life":3244,"unreleased":143,"not_listed":4},"core_lines":{"32.x":11,"31.x":2992,"30.x":755,"29.x":652,"28.x":1033,"27.x":510,"26.x":186,"25.x":943,"24.x":105,"23.x":52,"22.x":157,"1.x":4,"0.21.x":71,"0.20.x":98,"0.19.x":10,"0.18.x":30,"0.17.x":18,"0.16.x":6,"0.15.x":4,"0.14.x":5,"0.13.x":6,"0.12.x":6,"0.11.x":1,"0.8.x":3,"development":132}},"opened_24h":{"nodes":1879,"ipv4":1316,"ipv6":563,"ip_unknown":0,"implementation":{"core":1604,"knots":246,"btcd":3,"other":18,"unknown":8},"core_lifecycle":{"maintained":668,"end_of_life":928,"unreleased":8,"not_listed":0}},"service_flags":{"connected":{"blake2b_only":398,"reduced_data_only":156,"both":0,"neither":8339,"unknown":58},"knots":{"blake2b_only":396,"reduced_data_only":148,"both":0,"neither":466,"unknown":0}}},
    {"day":"2026-09-29","snapshot":"20260929_121145","snapshot_at":"2026-09-29T12:11:45Z","clock_offset_minutes":120,"lifecycle_as_of":"2026-10-01","sha256":"d5e5eb135bf4f4eeec102a4fc9e3ce7aa49714b5401912801ff14d3a793eb0d6","possible_cap":true,"connected":{"nodes":9000,"ipv4":7150,"ipv6":1850,"ip_unknown":0,"implementation":{"core":7819,"knots":1032,"btcd":19,"other":75,"unknown":55},"core_lifecycle":{"maintained":4427,"end_of_life":3244,"unreleased":144,"not_listed":4},"core_lines":{"32.x":11,"31.x":3024,"30.x":755,"29.x":648,"28.x":1033,"27.x":516,"26.x":188,"25.x":942,"24.x":99,"23.x":54,"22.x":152,"1.x":4,"0.21.x":71,"0.20.x":97,"0.19.x":12,"0.18.x":30,"0.17.x":19,"0.16.x":6,"0.15.x":4,"0.14.x":5,"0.13.x":5,"0.12.x":5,"0.11.x":3,"0.8.x":3,"development":133}},"opened_24h":{"nodes":2004,"ipv4":1434,"ipv6":570,"ip_unknown":0,"implementation":{"core":1713,"knots":268,"btcd":1,"other":16,"unknown":6},"core_lifecycle":{"maintained":728,"end_of_life":971,"unreleased":14,"not_listed":0}},"service_flags":{"connected":{"blake2b_only":416,"reduced_data_only":155,"both":0,"neither":8374,"unknown":55},"knots":{"blake2b_only":414,"reduced_data_only":146,"both":0,"neither":472,"unknown":0}}},
    {"day":"2026-09-30","snapshot":"20260930_121329","snapshot_at":"2026-09-30T12:13:29Z","clock_offset_minutes":120,"lifecycle_as_of":"2026-10-01","sha256":"c73cbef5c4c2a6300f249151c1929aa5f4fd6b534d3418fd68437599c80e3234","connected":{"nodes":8946,"ipv4":7102,"ipv6":1844,"ip_unknown":0,"implementation":{"core":7798,"knots":1003,"btcd":19,"other":73,"unknown":53},"core_lifecycle":{"maintained":4398,"end_of_life":3257,"unreleased":139,"not_listed":4},"core_lines":{"32.x":10,"31.x":3000,"30.x":748,"29.x":650,"28.x":1045,"27.x":513,"26.x":184,"25.x":951,"24.x":99,"23.x":53,"22.x":156,"1.x":4,"0.21.x":71,"0.20.x":96,"0.19.x":11,"0.18.x":30,"0.17.x":18,"0.16.x":6,"0.15.x":4,"0.14.x":5,"0.13.x":5,"0.12.x":5,"0.11.x":3,"0.8.x":2,"development":129}},"opened_24h":{"nodes":2045,"ipv4":1439,"ipv6":606,"ip_unknown":0,"implementation":{"core":1789,"knots":235,"btcd":0,"other":16,"unknown":5},"core_lifecycle":{"maintained":804,"end_of_life":973,"unreleased":12,"not_listed":0}},"service_flags":{"connected":{"blake2b_only":410,"reduced_data_only":142,"both":0,"neither":8341,"unknown":53},"knots":{"blake2b_only":408,"reduced_data_only":133,"both":0,"neither":462,"unknown":0}}}
  ]
}
