diff --git a/.github/workflows/sanitycheck.yml b/.github/workflows/sanitycheck.yml new file mode 100644 index 0000000..d5fff70 --- /dev/null +++ b/.github/workflows/sanitycheck.yml @@ -0,0 +1,48 @@ +name: invalid-blocks sanity-check + +on: + pull_request: + push: + branches: [ main ] + workflow_dispatch: + # Revalidate the default-branch cache daily before its inactivity expiry. + # Keep away from the start of the hour, when scheduled runs are busiest. + schedule: + - cron: '23 3 * * *' + +permissions: + contents: read + +jobs: + sanity-check: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: '3.12' + - name: restore verified previous transactions + id: prevouts-cache + uses: actions/cache/restore@v6 + with: + path: .cache/prevouts + key: prevouts-v1-${{ hashFiles('blocks/*.bin') }} + restore-keys: prevouts-v1- + - name: validate data and test validator + run: | + python -m venv .venv + . .venv/bin/activate + python -m pip install -r requirements.txt + python ci/sanity-check.py --fetch-prevouts + python -m unittest discover -s ci -p 'test_*.py' + # Save once per block set, after validation and tests pass on the default branch. + - name: save verified previous transactions + if: >- + ${{ success() && github.event_name != 'pull_request' + && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) + && steps.prevouts-cache.outputs.cache-hit != 'true' }} + uses: actions/cache/save@v6 + with: + path: .cache/prevouts + key: ${{ steps.prevouts-cache.outputs.cache-primary-key }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e8f5bc7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +.venv/ +__pycache__/ +.cache/prevouts/ diff --git a/README.md b/README.md index d769818..f0973a5 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,76 @@ -# invalid-blocks +# Bitcoin invalid blocks -Dataset of invalid headers and blocks observed on the Bitcoin network. +Dataset of invalid headers and blocks observed on the Bitcoin network or recovered from other sources, including chains that merge-mine with Bitcoin and archived block explorers. +Each record has valid proof of work and evidence of a named consensus failure. -## License +Split from [stale-blocks](https://github.com/bitcoin-data/stale-blocks); see [stale-blocks#128](https://github.com/bitcoin-data/stale-blocks/pull/128). +A stale block passes the applicable consensus rules but is outside the active chain. +This dataset covers blocks that fail those rules, including failures that can be established from their headers alone. + +## Files + +- [`data/invalid-blocks.jsonl`](data/invalid-blocks.jsonl): one JSON object per Bitcoin header hash, with optional context and an array of observations. +- [`docs/schema.md`](docs/schema.md): fields and admission rules. +- [`docs/notes.md`](docs/notes.md): replay behaviour and incident notes. +- `blocks/{height}-{hash}.bin`: full block, when available. + +Merge-mined recoveries generally provide a header and coinbase rather than a full Bitcoin block. + +## Contributing + +Add one record to [`data/invalid-blocks.jsonl`](data/invalid-blocks.jsonl), sorted by height then hash. +Include the 80-byte header, its decoded hash, parent hash and timestamp, height `prev + 1`, and a named consensus failure (`core_reject_reason` and `rule`). +The header must meet the PoW target encoded in its `nBits`. + +Include `context` fields needed to establish the failure: BIP34 coinbase height and scriptSig, `parent_mtp` for `time_below_mtp`, or `expected_nbits` for `nbits_retarget_not_applied`. +Omit unknown optional fields. +The related [mining-pools](https://github.com/bitcoin-data/mining-pools) dataset may help identify a coinbase tag. + +Include all available `observations`, with a source and provenance URL for each. +Distinct child-chain blocks and independent observers remain separate observations. +Use `merge_mining` for child-chain commitments, `p2p` for direct Bitcoin network reception, and `scrape` for website or API archives where direct reception is not established. +Prefer immutable evidence URLs. + +For header rules, observations and full block files are optional. +Body failures require a complete `.bin` that demonstrates the named failure. +For sigops, CI fetches the referenced previous transactions from public APIs, verifies their transaction IDs, and calculates the cost using their output scripts. +The [schema](docs/schema.md#evidence-enforced-by-ci) specifies each rule's evidence contract; observation labels cannot substitute for these checks. -This repository contains both code and data, which are licensed separately: +Replaying a `.bin` with `bitcoin-cli submitblock` reproduces context-free failures such as 74638's `bad-txns-vout-toolarge`; connect-level failures such as `bad-blk-sigops` need the historical chain context. +See [`docs/notes.md`](docs/notes.md). + +## CI + +```sh +python3 -m venv .venv +source .venv/bin/activate +python -m pip install -r requirements.txt +python ci/sanity-check.py --fetch-prevouts +python -m unittest discover -s ci -p 'test_*.py' +``` + +The validator uses `python-bitcoinlib` for Bitcoin parsing and serialization, with the version pinned in `requirements.txt`. +It checks JSONL structure, types, ordering, uniqueness, header hash, PoW and decoded header fields. +It enforces the rule/reject-string mapping, required context and rule-specific predicates. +Validation reports the first error in each record, with its file and line number, then continues to the next record. +Available block files must parse completely and match their transaction merkle roots and applicable witness commitments. +CI checks output-value overflow, forward transaction spends and excessive sigop cost directly. + +Sigops checks use a verified cache in `.cache/prevouts/`, restored between GitHub Actions runs. +Missing entries are fetched from public Esplora-compatible APIs when `--fetch-prevouts` is supplied. +API failures, missing evidence and corrupt cached transactions fail validation. +After filling the cache, omit the flag for an offline run; `--prevouts-dir` selects another cache and `--api-url` selects an API base. +The [schema](docs/schema.md#sigops-evidence-and-public-apis) explains the authentication and counting checks. + +These checks establish the named failures; they do not execute scripts, authenticate all supplied chain context or replay every consensus check against historical chain state. + +A daily run on the default branch revalidates the evidence and keeps the cache warm. +Only successful non-PR runs on the default branch save cache updates; pull requests restore the cache without uploading archives. +Cache retention is not guaranteed; the [schema](docs/schema.md#sigops-evidence-and-public-apis) covers eviction, scheduled-workflow inactivity and recovery. + +## License -- **Code** is licensed under the MIT License. See `LICENSE`. -- **Data** is dedicated to the public domain under CC0 1.0. See `LICENSE-DATA`. +- **Code** is licensed under the MIT License. + See `LICENSE`. +- **Data** (in `data/invalid-blocks.jsonl` and `blocks/*`) is dedicated to the public domain under CC0 1.0. + See `LICENSE-DATA`. diff --git a/blocks/477115-0000000000000000013ee4a86822d37a061732e04ee5f41fb77168f193363d1b.bin b/blocks/477115-0000000000000000013ee4a86822d37a061732e04ee5f41fb77168f193363d1b.bin new file mode 100644 index 0000000..516ac68 Binary files /dev/null and b/blocks/477115-0000000000000000013ee4a86822d37a061732e04ee5f41fb77168f193363d1b.bin differ diff --git a/blocks/74638-0000000000790ab3f22ec756ad43b6ab569abf0bddeb97c67a6f7b1470a7ec1c.bin b/blocks/74638-0000000000790ab3f22ec756ad43b6ab569abf0bddeb97c67a6f7b1470a7ec1c.bin new file mode 100644 index 0000000..a6acd2d Binary files /dev/null and b/blocks/74638-0000000000790ab3f22ec756ad43b6ab569abf0bddeb97c67a6f7b1470a7ec1c.bin differ diff --git a/blocks/783426-00000000000000000002ec935e245f8ae70fc68cc828f05bf4cfa002668599e4.bin b/blocks/783426-00000000000000000002ec935e245f8ae70fc68cc828f05bf4cfa002668599e4.bin new file mode 100644 index 0000000..1b628dc Binary files /dev/null and b/blocks/783426-00000000000000000002ec935e245f8ae70fc68cc828f05bf4cfa002668599e4.bin differ diff --git a/blocks/784121-000000000000000000046a2698233ed93bb5e74ba7d2146a68ddb0c2504c980d.bin b/blocks/784121-000000000000000000046a2698233ed93bb5e74ba7d2146a68ddb0c2504c980d.bin new file mode 100644 index 0000000..5197436 Binary files /dev/null and b/blocks/784121-000000000000000000046a2698233ed93bb5e74ba7d2146a68ddb0c2504c980d.bin differ diff --git a/blocks/809478-000000000000000000006840568a01091022093a176d12a1e8e5e261e4f11853.bin b/blocks/809478-000000000000000000006840568a01091022093a176d12a1e8e5e261e4f11853.bin new file mode 100644 index 0000000..5402e5b Binary files /dev/null and b/blocks/809478-000000000000000000006840568a01091022093a176d12a1e8e5e261e4f11853.bin differ diff --git a/ci/block_evidence.py b/ci/block_evidence.py new file mode 100644 index 0000000..1a6e3b5 --- /dev/null +++ b/ci/block_evidence.py @@ -0,0 +1,185 @@ +"""Read committed transactions for narrow, offline evidence checks. + +This is not a consensus validator: no script execution, UTXO lookup or +historical chain reconstruction takes place here. +Transaction IDs and the merkle root bind the checked non-witness data to the +Bitcoin header. Parsing consumes the entire file so truncation cannot satisfy +a rule's requirement for a complete block body. + +Sigop counting mirrors Core's CScript::GetSigOpCount, GetTransactionSigOpCost +and CountWitnessSigOps for mainnet after SegWit activation. It counts operations, +not signature executions: branches are counted even if they would not execute. +Taproot does not contribute to the legacy block sigop cost (it has a separate +per-input validation budget). +""" + +from collections.abc import Mapping, Sequence +from typing import TypeVar + +from bitcoin.core import CBlock, CoreMainParams, CTransaction, Hash as sha256d, b2lx +from bitcoin.core.script import ( + CScript, CScriptInvalidError, CScriptOp, OP_1, OP_16, + OP_CHECKSIG, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY, +) +from bitcoin.core.serialize import SerializationError + +T = TypeVar("T", CBlock, CTransaction) + +MAX_MONEY = CoreMainParams.MAX_MONEY +MAX_BLOCK_SIGOPS_COST = 80_000 + + +def deserialize(data: bytes, cls: type[T]) -> T: + """Parse wire bytes without consensus validation, rejecting normalized encodings.""" + try: + value = cls.deserialize(data) + if value.serialize() != data: + raise ValueError("non-canonical or superfluous wire encoding") + except SerializationError as exc: + raise ValueError(f"invalid or truncated wire data: {exc}") from exc + transactions = value.vtx if isinstance(value, CBlock) else (value,) + if any(not tx.vin or not tx.vout for tx in transactions): + raise ValueError("transaction has no inputs or outputs") + return value + + +def read_transaction(data: bytes) -> CTransaction: + """Read a complete transaction, retaining its original txid and witness bytes.""" + return deserialize(data, CTransaction) + + +def verify_witness_commitment(block: CBlock) -> None: + """Bind witness scripts used in sigop counting to the coinbase commitment. + + The highest matching output wins (BIP141). The coinbase wtxid is zero; + its witness must supply exactly one 32-byte reserved value. The caller + must already have verified the transaction merkle root against the header. + """ + try: + output = block.vtx[0].vout[block.get_witness_commitment_index()] + except ValueError: + if any(tx.has_witness() for tx in block.vtx): + raise ValueError("witness data without a coinbase commitment") + return + coinbase = block.vtx[0] + reserved = coinbase.wit.vtxinwit[0].scriptWitness.stack if coinbase.has_witness() else () + if len(reserved) != 1 or len(reserved[0]) != 32: + raise ValueError("coinbase witness must contain one 32-byte reserved value") + if sha256d(block.calc_witness_merkle_root() + reserved[0]) != output.scriptPubKey[6:38]: + raise ValueError("witness merkle commitment mismatch") + + +def read_block(data: bytes) -> CBlock: + """Parse a complete body and verify its transaction merkle commitment. + + Duplicate txids are excluded from this evidence path: they make an + in-block outpoint lookup ambiguous and can produce a mutated merkle tree. + Such incidents need a separate rule and evidence checker if added later. + """ + block = deserialize(data, CBlock) + transactions = block.vtx + if not transactions or not transactions[0].is_coinbase(): + raise ValueError("first transaction is not a coinbase") + hashes = [tx.GetTxid() for tx in transactions] + if len(set(hashes)) != len(hashes): + raise ValueError("duplicate transaction IDs in block evidence") + if block.calc_merkle_root() != block.hashMerkleRoot: + raise ValueError("transaction merkle root does not match header") + return block + + +def establishes_rule(block: CBlock, rule: str) -> bool: + """Recognize only failures provable from these committed transactions. + + A forward spend must name an existing output of a later transaction. + Missing external inputs and sigop costs need historical prevout data and + deliberately do not count as proofs here. + """ + transactions = block.vtx + if rule == "bad-txns-vout-toolarge": + return any(output.nValue > MAX_MONEY for tx in transactions for output in tx.vout) + if rule == "bad-txns-inputs-missingorspent": + positions = {tx.GetTxid(): i for i, tx in enumerate(transactions)} + for index, tx in enumerate(transactions): + for txin in tx.vin: + later = positions.get(txin.prevout.hash) + if later is not None and later > index and txin.prevout.n < len(transactions[later].vout): + return True + return False + + +def sigop_count(script: bytes, accurate: bool = False) -> int: + """Count CHECKSIG as one and CHECKMULTISIG as 20 or preceding OP_N. + + As in Core, a malformed push ends counting at that point. Bytes inside + pushed data are not opcodes. Accurate counting is for redeem/witness + scripts; the legacy input/output count always uses 20 for multisig. + """ + # python-bitcoinlib 0.12.2's GetSigOpCount(True) raises on OP_N MULTISIG; + # its iterator also raises on malformed pushes instead of keeping the count. + count = 0 + previous = None + try: + for opcode, _, _ in CScript(script).raw_iter(): + if opcode in (OP_CHECKSIG, OP_CHECKSIGVERIFY): + count += 1 + elif opcode in (OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY): + count += CScriptOp(previous).decode_op_n() if accurate and previous is not None and OP_1 <= previous <= OP_16 else 20 + previous = opcode + except CScriptInvalidError: + pass + return count + + +def last_push(script: bytes) -> bytes | None: + """Return Core's last pushed byte vector, or None for non-push-only input.""" + script = CScript(script) + if not script.is_push_only(): + return None + data = None + for _, data, _ in script.raw_iter(): + pass + return data or b"" + + +def witness_sigops(program_script: bytes, witness: Sequence[bytes]) -> int: + """Count version-0 witness programs; other versions add no block cost.""" + script = CScript(program_script) + if script.is_witness_v0_keyhash(): + return 1 + if script.is_witness_v0_scripthash() and witness: + return sigop_count(witness[-1], accurate=True) + return 0 + + +def sigop_cost(block: CBlock, previous_transactions: Mapping[bytes, CTransaction]) -> dict[str, int]: + """Calculate legacy, P2SH and witness costs, requiring every prevout. + + previous_transactions is keyed by raw txid, verified when loading its + stripped bytes. Only earlier in-block outputs are made available while + walking the block. The witness commitment is checked before using witness + scripts, which are not covered by the transaction IDs alone. + This guard also protects callers outside the dataset validation pipeline. + """ + verify_witness_commitment(block) + available = dict(previous_transactions) + totals = {"legacy": 0, "p2sh": 0, "witness": 0} + for index, tx in enumerate(block.vtx): + totals["legacy"] += 4 * sum(sigop_count(txin.scriptSig) for txin in tx.vin) + totals["legacy"] += 4 * sum(sigop_count(output.scriptPubKey) for output in tx.vout) + if index: + for input_index, txin in enumerate(tx.vin): + txid, vout = txin.prevout.hash, txin.prevout.n + witness = tx.wit.vtxinwit[input_index].scriptWitness.stack if tx.has_witness() else () + previous = available.get(txid) + if previous is None or vout >= len(previous.vout): + raise ValueError(f"missing previous output {b2lx(txid)}:{vout}") + script_pubkey = previous.vout[vout].scriptPubKey + redeem = last_push(txin.scriptSig) if script_pubkey.is_p2sh() else None + if redeem is not None: + totals["p2sh"] += 4 * sigop_count(redeem, accurate=True) + program = redeem if redeem is not None else script_pubkey + totals["witness"] += witness_sigops(program, witness) + available[tx.GetTxid()] = tx + totals["total"] = sum(totals.values()) + return totals diff --git a/ci/prevouts.py b/ci/prevouts.py new file mode 100644 index 0000000..0473a47 --- /dev/null +++ b/ci/prevouts.py @@ -0,0 +1,115 @@ +"""Acquire previous transactions through Esplora-compatible public APIs. + +Cache entries contain stripped transaction bytes, sufficient to authenticate +output scripts against the txid committed in a spending input. Every cache hit +is verified too. Downloads and cache corruption fail explicitly; there is no +fallback to a claimed reject string or an unauthenticated scriptPubKey. +""" + +from collections.abc import Sequence +from concurrent.futures import ThreadPoolExecutor, as_completed +from http.client import HTTPException, IncompleteRead +from pathlib import Path +import time +import tempfile +from urllib.request import Request, urlopen + +from bitcoin.core import CTransaction, b2lx + +from block_evidence import read_transaction + +DEFAULT_APIS = ("https://mempool.space/api", "https://blockstream.info/api") +PREVOUTS_DIR = Path(".cache/prevouts") + + +def decode_previous(data: bytes, txid: str) -> CTransaction: + """Authenticate a complete transaction against the requested display txid.""" + transaction = read_transaction(data) + if b2lx(transaction.GetTxid()) != txid: + raise ValueError(f"previous transaction identity mismatch: {txid}") + return transaction + + +def fetch_previous(txid: str, apis: Sequence[str] = DEFAULT_APIS) -> CTransaction: + """Fetch raw hex with bounded retries, provider fallback and HTTP timeouts. + + Two workers call this function in parallel. Successful downloads are paced + and rate-limit/transient failures back off. Identity failures are terminal: + trying another provider must not conceal a wrong transaction response. + """ + failures = [] + for api in apis: + url = f"{api.rstrip('/')}/tx/{txid}/hex" + for attempt in range(2): + request = Request(url, headers={"User-Agent": "invalid-blocks-evidence-check/1"}) + try: + with urlopen(request, timeout=30) as response: + # Raw transaction size is bounded for this evidence path; + # the limit also catches oversized error responses. + raw = response.read(8_000_001) + if len(raw) > 8_000_000: + raise ValueError(f"oversized previous transaction response: {txid}") + # read(amt) can return early without raising on a truncated + # Content-Length response. HTTPResponse tracks bytes still due. + remaining = getattr(response, "length", None) + if remaining: + raise IncompleteRead(raw, remaining) + transaction = decode_previous(bytes.fromhex(raw.decode("ascii").strip()), txid) + time.sleep(0.25) + return transaction + except (OSError, HTTPException) as exc: + # urllib wraps connection setup errors, but resets and short + # HTTP reads can escape unwrapped after the response starts. + failures.append(f"{url}: {exc}") + if attempt == 0: + time.sleep(2) + raise ValueError(f"could not download previous transaction {txid}: " + "; ".join(failures)) + + +def load_previous(transactions: Sequence[CTransaction], cache_dir: Path | str = PREVOUTS_DIR, + fetch: bool = False, apis: Sequence[str] = DEFAULT_APIS) -> dict[bytes, CTransaction]: + """Resolve external txids; earlier in-block outputs are handled by sigops. + + The complete requested set is required for an exact count. Offline mode + reports missing evidence. Online mode writes only verified stripped bytes + using atomic replacement, so interrupted downloads cannot poison the cache. + """ + own = {tx.GetTxid() for tx in transactions} + needed = sorted({b2lx(txin.prevout.hash) for tx in transactions[1:] + for txin in tx.vin if txin.prevout.hash not in own}) + cache_dir = Path(cache_dir) + + def load(txid: str) -> CTransaction: + path = cache_dir / f"{txid}.bin" + if path.exists(): + return decode_previous(path.read_bytes(), txid) + if not fetch: + raise ValueError(f"missing cached previous transaction {txid}; run with --fetch-prevouts") + transaction = fetch_previous(txid, apis) + cache_dir.mkdir(parents=True, exist_ok=True) + with tempfile.NamedTemporaryFile(dir=cache_dir, delete=False) as handle: + temporary = Path(handle.name) + try: + handle.write(transaction.serialize({"include_witness": False})) + handle.close() + temporary.replace(path) + finally: + temporary.unlink(missing_ok=True) + return transaction + + if fetch: + missing = sum(not (cache_dir / f"{txid}.bin").exists() for txid in needed) + print(f"Previous transactions: {len(needed)} required, {missing} to download", flush=True) + pool = ThreadPoolExecutor(max_workers=2) + futures = [pool.submit(load, txid) for txid in needed] + result = {} + try: + for future in as_completed(futures): + tx = future.result() + result[tx.GetTxid()] = tx + if fetch and missing and len(result) % 500 == 0: + print(f"Previous transactions verified: {len(result)}/{len(needed)}", flush=True) + finally: + # Do not keep downloading the remaining catalogue after an error. + pool.shutdown(wait=True, cancel_futures=True) + return result diff --git a/ci/sanity-check.py b/ci/sanity-check.py new file mode 100644 index 0000000..e0895cd --- /dev/null +++ b/ci/sanity-check.py @@ -0,0 +1,384 @@ +#!/usr/bin/env python3 +"""Enforce the dataset's structure and rule-specific evidence contract offline. + +RULES is the admission registry: adding a rule requires an explicit reject +string, required context and evidence path, plus tests and schema documentation. +External provenance and the origin of supplied chain context remain reviewed +claims; a syntactically valid URL is never treated as a proof by itself. +""" + +from collections.abc import Sequence, Set +import argparse +import json +from pathlib import Path +import re +import sys +from typing import Any +from urllib.parse import urlparse + +from bitcoin.core import CBlock, CBlockHeader, b2lx +from bitcoin.core._bignum import vch2bn +from bitcoin.core.script import CScript, CScriptInvalidError, OP_1NEGATE +from bitcoin.core.serialize import uint256_from_compact + +from block_evidence import ( + MAX_BLOCK_SIGOPS_COST, establishes_rule, read_block, + sigop_cost, verify_witness_commitment, +) +from prevouts import DEFAULT_APIS, PREVOUTS_DIR, load_previous + +DATA_PATH = Path("data/invalid-blocks.jsonl") +BLOCKS_DIR = Path("blocks") +REQUIRED = {"height", "hash", "header", "prev_hash", "nTime", "core_reject_reason", "rule"} +CONTEXT_FIELDS = { + "expected_nbits", "parent_mtp", "coinbase_height", "coinbase_scriptsig_hex", + "pool", "parent_kind", +} +OBSERVATION_REQUIRED = {"channel", "source", "provenance"} +CHILD_FIELDS = {"child_chain", "child_height", "child_block_hash", "child_block_time", "child_header"} +OBSERVATION_FIELDS = OBSERVATION_REQUIRED | CHILD_FIELDS | {"first_seen"} +CHANNELS = {"merge_mining", "p2p", "scrape"} +PARENT_KINDS = {"canonical", "stale", "invalid"} +POW_LIMIT = 0xFFFF << (8 * (0x1D - 3)) + +# Evidence paths: local = checked header/context predicate; body = a complete, +# merkle-bound body proving the failure; sigops = body plus authenticated prevouts. +# Keep the rule names and reject strings aligned with docs/schema.md. +RULES = { + "bad-txns-vout-toolarge": ("bad-txns-vout-toolarge", (), "body"), + "bad-blk-sigops": ("bad-blk-sigops", (), "sigops"), + "bad-txns-inputs-missingorspent": ("bad-txns-inputs-missingorspent", (), "body"), + "bip34_v2_coinbase_height_mismatch": ( + "bad-cb-height", ("coinbase_height", "coinbase_scriptsig_hex"), "local"), + "bip34_coinbase_height_mismatch": ( + "bad-cb-height", ("coinbase_height", "coinbase_scriptsig_hex"), "local"), + "bip34_coinbase_height_missing": ("bad-cb-height", ("coinbase_scriptsig_hex",), "local"), + "bip66_block_version_below_3": ("bad-version", (), "local"), + "bip65_block_version_below_4": ("bad-version", (), "local"), + "coinbase_scriptsig_length_above_100": ("bad-cb-length", ("coinbase_scriptsig_hex",), "local"), + "time_below_mtp": ("time-too-old", ("parent_mtp",), "local"), + "nbits_retarget_not_applied": ("bad-diffbits", ("expected_nbits",), "local"), +} +# Mainnet activation heights from Core's src/kernel/chainparams.cpp. Earlier +# BIP34 version-2 enforcement depended on rolling version counts, reviewed in +# the historical source rather than reconstructed from this dataset. +BIP34_HEIGHT = 227931 +VERSION_RULES = {"bip66_block_version_below_3": (363725, 3), + "bip65_block_version_below_4": (388381, 4)} + + +def target_from_bits(bits: int) -> int: + target = uint256_from_compact(bits) + return target if not bits & 0x00800000 and 0 < target <= POW_LIMIT else 0 + + +def unique_object(pairs: list[tuple[str, Any]]) -> dict[str, Any]: + result = {} + for key, value in pairs: + if key in result: + raise ValueError(f"duplicate JSON key {key!r}") + result[key] = value + return result + + +def read_jsonl(path: Path, problems: list[str]) -> list[tuple[str, dict[str, Any]]]: + try: + raw = path.read_bytes() + except OSError as exc: + problems.append(f"{path}: {exc}") + return [] + if b"\r" in raw or (raw and not raw.endswith(b"\n")): + problems.append(f"{path}: use LF line endings and a final newline") + try: + lines = raw.decode("utf-8").splitlines() + except UnicodeDecodeError as exc: + problems.append(f"{path}: invalid UTF-8: {exc}") + return [] + rows = [] + if not lines: + problems.append(f"{path}: dataset is empty") + for number, line in enumerate(lines, 1): + context = f"{path}:{number}" + try: + record = json.loads(line, object_pairs_hook=unique_object) + except ValueError as exc: + problems.append(f"{context}: invalid JSON: {exc}") + continue + if not isinstance(record, dict): + problems.append(f"{context}: expected a JSON object") + continue + rows.append((context, record)) + return rows + + +def check_fields(record: dict[str, Any], required: Set[str], allowed: Set[str]) -> None: + missing = required - record.keys() + extra = record.keys() - allowed + if missing: + raise ValueError(f"missing fields {sorted(missing)}") + if extra: + raise ValueError(f"unknown fields {sorted(extra)}") + + +def integer(record: dict[str, Any], name: str, minimum: int = 0) -> int: + value = record.get(name) + if type(value) is not int or value < minimum: + raise ValueError(f"{name} must be an integer >= {minimum}") + return value + + +def hex_value(record: dict[str, Any], name: str, size: int | None) -> bytes: + value = record.get(name) + if not isinstance(value, str) or not re.fullmatch(r"(?:[0-9a-f]{2})+", value): + raise ValueError(f"{name} must be non-empty lowercase hex") + decoded = bytes.fromhex(value) + if size is not None and len(decoded) != size: + raise ValueError(f"{name} must encode {size} bytes") + return decoded + + +def string(record: dict[str, Any], name: str) -> str: + value = record.get(name) + if not isinstance(value, str) or not value.strip(): + raise ValueError(f"{name} must be a non-empty string") + return value + + +def check_context(record: dict[str, Any]) -> None: + """Validate context encoding and the fields required by the rule registry.""" + details = record.get("context", {}) + if not isinstance(details, dict): + raise ValueError("context must be an object") + check_fields(details, set(), CONTEXT_FIELDS) + for name in ("parent_mtp", "coinbase_height"): + if name in details: + integer(details, name) + for name, size in (("expected_nbits", 4), ("coinbase_scriptsig_hex", None)): + if name in details: + hex_value(details, name, size) + if "pool" in details: + string(details, "pool") + if "parent_kind" in details and details["parent_kind"] not in tuple(PARENT_KINDS): + raise ValueError(f"parent_kind must be one of {sorted(PARENT_KINDS)}") + required = set(RULES[record["rule"]][1]) + if required - details.keys(): + raise ValueError(f"rule {record['rule']} requires {sorted(required)}") + + +def check_observations(record: dict[str, Any]) -> int: + """Check acquisition provenance independently of the rule evidence checks.""" + observations = record.get("observations", []) + if not isinstance(observations, list): + raise ValueError("observations must be an array") + seen = set() + for observation in observations: + if not isinstance(observation, dict): + raise ValueError("observation must be an object") + check_fields(observation, OBSERVATION_REQUIRED, OBSERVATION_FIELDS) + for name in OBSERVATION_REQUIRED: + string(observation, name) + channel = observation["channel"] + if channel not in CHANNELS: + raise ValueError(f"channel must be one of {sorted(CHANNELS)}") + if channel == "merge_mining": + string(observation, "child_chain") + elif CHILD_FIELDS & observation.keys(): + raise ValueError("child-chain fields require channel=merge_mining") + for name in ("child_height", "first_seen", "child_block_time"): + if name in observation: + integer(observation, name) + if "child_block_hash" in observation: + hex_value(observation, "child_block_hash", 32) + if "child_header" in observation: + hex_value(observation, "child_header", 80) + url = urlparse(observation["provenance"]) + if url.scheme not in ("http", "https") or not url.hostname: + raise ValueError("provenance must be an HTTP(S) URL") + # A chain can commit the same Bitcoin parent at multiple child heights; + # independent recorders can also observe the same block. Reject only + # exact duplicate observations, without dropping either kind of evidence. + key = json.dumps(observation, sort_keys=True, separators=(",", ":")) + if key in seen: + raise ValueError("duplicate observation") + seen.add(key) + return len(observations) + + +def script_height(script: bytes) -> int | None: + """Decode the first script-number push, or None when no height is encoded. + + Decoding is separate from BIP34's exact prefix comparison: a non-minimal + push can encode the right number and still fail the consensus check. + """ + try: + value = next(iter(CScript(script)), None) + except CScriptInvalidError: + return None + if value == OP_1NEGATE: + return -1 + if type(value) is int: + return value + if isinstance(value, bytes) and len(value) <= 5: + return vch2bn(value) + return None + + +def height_prefix(height: int) -> bytes: + """Serialize CScript() << height, including sign padding and small ints.""" + return bytes(CScript([height])) + + +def check_local_evidence(record: dict[str, Any], header: CBlockHeader) -> None: + """Check the claimed failure against already type-checked header/context. + + This proves consistency with supplied height, MTP and expected difficulty; + it does not authenticate those facts against the parent chain or bind an + extracted coinbase script to the header without a complete body. + """ + rule = record["rule"] + context = record.get("context", {}) + height = record["height"] + version = header.nVersion + script = bytes.fromhex(context["coinbase_scriptsig_hex"]) if "coinbase_scriptsig_hex" in context else None + if script is not None and "coinbase_height" in context: + if script_height(script) != context["coinbase_height"]: + raise ValueError("coinbase_height does not match the scriptSig prefix") + if rule == "time_below_mtp" and record["nTime"] > context["parent_mtp"]: + raise ValueError("time_below_mtp requires nTime <= parent_mtp") + if rule == "nbits_retarget_not_applied": + expected = int(context["expected_nbits"], 16) + if not target_from_bits(expected): + raise ValueError("expected_nbits must encode a valid PoW target") + if height % 2016 or expected == header.nBits: + raise ValueError("retarget rule requires a retarget height and different nBits") + if rule in VERSION_RULES: + activation, minimum = VERSION_RULES[rule] + if height < activation or version >= minimum: + raise ValueError(f"{rule} requires height >= {activation} and version < {minimum}") + if rule.startswith("bip34_"): + if rule == "bip34_v2_coinbase_height_mismatch": + if height >= BIP34_HEIGHT or version < 2: + raise ValueError(f"rollout BIP34 rule requires version >= 2 before height {BIP34_HEIGHT}") + elif height < BIP34_HEIGHT: + raise ValueError(f"BIP34 rule requires height >= {BIP34_HEIGHT}") + if script.startswith(height_prefix(height)): + raise ValueError("scriptSig has the correct BIP34 height prefix") + if rule == "bip34_coinbase_height_missing" and script_height(script) is not None: + raise ValueError("missing-height rule requires no decodable height prefix") + if rule == "coinbase_scriptsig_length_above_100" and len(script) <= 100: + raise ValueError("coinbase scriptSig must exceed 100 bytes") + + +def check_failure_evidence(record: dict[str, Any], block: CBlock | None, prevouts_dir: Path | str = PREVOUTS_DIR, + fetch_prevouts: bool = False, apis: Sequence[str] = DEFAULT_APIS) -> None: + """Require a checked failure; observations cannot substitute for bytes.""" + mode = RULES[record["rule"]][2] + if mode == "local": + return + if block is None: + raise ValueError(f"{record['rule']} requires a complete block body") + if mode == "body" and not establishes_rule(block, record["rule"]): + raise ValueError(f"committed body does not demonstrate {record['rule']}") + if mode == "sigops": + # This checker uses BIP16 + BIP141 counting, not pre-SegWit rules. + if record["height"] < 481824: + raise ValueError("sigops evidence checker requires post-SegWit mainnet height") + previous = load_previous(block.vtx, prevouts_dir, fetch_prevouts, apis) + cost = sigop_cost(block, previous) + if cost["total"] <= MAX_BLOCK_SIGOPS_COST: + raise ValueError(f"sigop cost {cost['total']} does not exceed {MAX_BLOCK_SIGOPS_COST}") + elif fetch_prevouts: + print(f"{record['height']}: sigop cost {cost['total']} " + f"(legacy {cost['legacy']}, P2SH {cost['p2sh']}, witness {cost['witness']})", flush=True) + + +def check_dataset(path: Path | str = DATA_PATH, blocks_dir: Path | str = BLOCKS_DIR, + prevouts_dir: Path | str = PREVOUTS_DIR, fetch_prevouts: bool = False, + apis: Sequence[str] = DEFAULT_APIS) -> tuple[list[str], tuple[int, int, int, int]]: + problems = [] + seen = set() + remaining_blocks = {block.name: block for block in Path(blocks_dir).glob("*.bin")} + block_count = 0 + last_key = None + observation_count = 0 + context_count = 0 + for where, record in read_jsonl(Path(path), problems): + try: + check_fields(record, REQUIRED, REQUIRED | {"context", "observations"}) + height = integer(record, "height", minimum=1) + if height > 0x7fffffff: + raise ValueError("height exceeds signed 32-bit range") + timestamp = integer(record, "nTime") + hex_value(record, "hash", 32) + header = hex_value(record, "header", 80) + hex_value(record, "prev_hash", 32) + string(record, "core_reject_reason") + rule = string(record, "rule") + if rule not in RULES: + raise ValueError(f"unknown rule {rule!r}") + if record["core_reject_reason"] != RULES[rule][0]: + raise ValueError(f"rule {rule} requires core_reject_reason={RULES[rule][0]}") + block_hash = record["hash"] + block = remaining_blocks.pop(f"{height}-{block_hash}.bin", None) + block_count += block is not None + key = (height, block_hash) + if last_key is not None and key < last_key: + raise ValueError("records must be ordered by height then hash") + last_key = key + if block_hash in seen: + raise ValueError(f"duplicate block hash {block_hash}") + seen.add(block_hash) + parsed_header = CBlockHeader.deserialize(header) + calculated = b2lx(parsed_header.GetHash()) + if block_hash != calculated: + raise ValueError("header hash mismatch") + target = target_from_bits(parsed_header.nBits) + if not target or int(calculated, 16) > target: + raise ValueError("header does not satisfy a valid PoW target") + if record["prev_hash"] != b2lx(parsed_header.hashPrevBlock): + raise ValueError("prev_hash mismatch with header") + if timestamp != parsed_header.nTime: + raise ValueError("nTime mismatch with header") + check_context(record) + context_count += bool(record.get("context")) + observation_count += check_observations(record) + check_local_evidence(record, parsed_header) + evidence_block = None + if block is not None: + data = block.read_bytes() + if data[:80] != header: + raise ValueError(f"{block}: first 80 bytes do not match dataset header") + evidence_block = read_block(data) + if height >= 481824: + verify_witness_commitment(evidence_block) + details = record.get("context", {}) + if "coinbase_scriptsig_hex" in details: + if evidence_block.vtx[0].vin[0].scriptSig.hex() != details["coinbase_scriptsig_hex"]: + raise ValueError("coinbase scriptSig does not match context") + check_failure_evidence(record, evidence_block, prevouts_dir, fetch_prevouts, apis) + except (OSError, ValueError) as exc: + problems.append(f"{where}: {exc}") + for block in sorted(remaining_blocks.values()): + problems.append(f"{block}: orphan block file; name must match a dataset record") + return problems, (len(seen), context_count, observation_count, block_count) + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--fetch-prevouts", action="store_true", help="fetch missing sigops prevout evidence from public APIs") + parser.add_argument("--prevouts-dir", type=Path, default=PREVOUTS_DIR, help="verified transaction cache directory") + parser.add_argument("--api-url", action="append", help="Esplora API base URL; repeat for fallback providers") + args = parser.parse_args() + problems, counts = check_dataset(prevouts_dir=args.prevouts_dir, fetch_prevouts=args.fetch_prevouts, + apis=args.api_url or DEFAULT_APIS) + if problems: + print("sanity-check failed:") + print("\n".join(problems)) + return 1 + print("sanity-check successful") + print(f" {counts[0]} blocks, {counts[1]} contexts, {counts[2]} observations, {counts[3]} block files") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/ci/test_block_evidence.py b/ci/test_block_evidence.py new file mode 100644 index 0000000..6a1e59a --- /dev/null +++ b/ci/test_block_evidence.py @@ -0,0 +1,90 @@ +"""Block parsing, commitments and sigop counting without mining or API access.""" + +import unittest + +from bitcoin.core import CBlock, COutPoint, CTransaction, CTxIn, CTxOut, CTxWitness, CTxInWitness +from bitcoin.core.script import CScript, CScriptWitness, OP_TRUE + +from block_evidence import ( + MAX_MONEY, establishes_rule, read_block, sha256d, sigop_count, witness_sigops, +) + + +def transaction(prev_hash=bytes(32), vout=0xffffffff, amount=1, witness=False): + """Serialize a one-input, one-output transaction and its stripped form.""" + tx = CTransaction( + [CTxIn(COutPoint(prev_hash, vout), CScript(b"\x01\x01"))], + [CTxOut(amount, CScript([OP_TRUE]))], + witness=CTxWitness([CTxInWitness(CScriptWitness([b"B"]))]) if witness else CTxWitness(), + ) + return tx.serialize(), tx.serialize({"include_witness": False}) + + +def block(*transactions): + """Build a merkle-bound test block; PoW is tested separately in the dataset.""" + root = CBlock.build_merkle_tree_from_txids([sha256d(stripped) for _, stripped in transactions])[-1] + # Keep raw transaction bytes so malformed encodings can be supplied by tests. + return bytes(36) + root + bytes(12) + bytes([len(transactions)]) + b"".join(wire for wire, _ in transactions) + + +class BlockEvidenceChecks(unittest.TestCase): + def test_overflow_boundary(self): + """Only outputs above MAX_MONEY establish the output-too-large failure.""" + for amount, expected in ((-1, False), (MAX_MONEY, False), (MAX_MONEY + 1, True)): + with self.subTest(amount=amount): + parsed = read_block(block(transaction(amount=amount))) + self.assertEqual(establishes_rule(parsed, "bad-txns-vout-toolarge"), expected) + + def test_forward_spend_requires_later_transaction_and_existing_output(self): + """Ordering evidence must identify an existing output created later in the block.""" + coinbase = transaction() + producer = transaction(prev_hash=b"\x11" * 32, vout=0) + consumer = transaction(prev_hash=sha256d(producer[1]), vout=0) + rule = "bad-txns-inputs-missingorspent" + self.assertTrue(establishes_rule(read_block(block(coinbase, consumer, producer)), rule)) + self.assertFalse(establishes_rule(read_block(block(coinbase, producer, consumer)), rule)) + bad_index = transaction(prev_hash=sha256d(producer[1]), vout=1) + self.assertFalse(establishes_rule(read_block(block(coinbase, bad_index, producer)), rule)) + self.assertFalse(establishes_rule(read_block(block(coinbase, producer)), rule)) + + def test_invalid_block_serialization(self): + """Reject malformed bodies, transaction commitments and witness encodings.""" + tx = transaction() + data = block(tx) + witness = transaction(witness=True) + cases = { + "header only": data[:80], + "truncated transaction": data[:-1], + "trailing bytes": data + b"\x00", + "noncanonical count": data[:80] + b"\xfd\x01\x00" + data[81:], + "empty block": bytes(80) + b"\x00", + "merkle mismatch": data[:36] + bytes(32) + data[68:], + "duplicate txids": block(tx, tx), + "missing coinbase": block(transaction(prev_hash=b"\x11" * 32, vout=0)), + "unknown witness flag": block((witness[0][:5] + b"\x02" + witness[0][6:], witness[1])), + "empty witness stacks": block((witness[0][:-7] + b"\x00" + witness[0][-4:], witness[1])), + } + for case, wire in cases.items(): + with self.subTest(case=case), self.assertRaises(ValueError): + read_block(wire) + + +class SigopChecks(unittest.TestCase): + def test_legacy_multisig_accurate_count_and_pushed_bytes(self): + """Check multisig counting modes, ignore pushed opcodes and stop at malformed pushes.""" + self.assertEqual(sigop_count(bytes.fromhex("52aeac")), 21) + self.assertEqual(sigop_count(bytes.fromhex("52aeac"), accurate=True), 3) + self.assertEqual(sigop_count(bytes.fromhex("0050ae"), accurate=True), 20) + self.assertEqual(sigop_count(bytes.fromhex("02acaeac")), 1) + self.assertEqual(sigop_count(bytes.fromhex("ac4c02ac")), 1) # malformed push ends counting + + def test_witness_script_accurate_count_and_taproot_exclusion(self): + """Count P2WSH sigops; empty stacks, Taproot and malformed programs contribute zero.""" + self.assertEqual(witness_sigops(b"\x00\x20" + bytes(32), [bytes.fromhex("53aeac")]), 4) + self.assertEqual(witness_sigops(b"\x00\x20" + bytes(32), []), 0) + self.assertEqual(witness_sigops(b"\x51\x20" + bytes(32), [b"\xac"]), 0) + self.assertEqual(witness_sigops(b"\x00\x14" + bytes(19), []), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/ci/test_prevouts.py b/ci/test_prevouts.py new file mode 100644 index 0000000..8cf787c --- /dev/null +++ b/ci/test_prevouts.py @@ -0,0 +1,70 @@ +"""Public-API acquisition and cache failures must never become evidence.""" + +from io import BytesIO +from pathlib import Path +import tempfile +import unittest +from unittest.mock import patch +from urllib.error import URLError + +from block_evidence import read_transaction, sha256d +from prevouts import decode_previous, fetch_previous, load_previous +from test_block_evidence import transaction + + +class PrevoutChecks(unittest.TestCase): + def setUp(self): + self.wire, self.stripped = transaction(witness=True) + self.txid = sha256d(self.stripped)[::-1].hex() + self.temp = tempfile.TemporaryDirectory() + self.addCleanup(self.temp.cleanup) + self.cache = Path(self.temp.name) + self.spending = read_transaction(transaction(sha256d(self.stripped), 0)[0]) + self.coinbase = read_transaction(transaction(amount=2)[0]) + + def test_transaction_identity_and_full_consumption(self): + """Accept only complete transaction bytes matching the requested txid.""" + self.assertEqual(decode_previous(self.wire, self.txid).serialize({"include_witness": False}), self.stripped) + for data in (self.wire + b"\x00", self.wire[:-1]): + with self.assertRaises(ValueError): + decode_previous(data, self.txid) + with self.assertRaisesRegex(ValueError, "identity mismatch"): + decode_previous(self.wire, "00" * 32) + + @patch("prevouts.time.sleep") + def test_api_download_and_provider_fallback(self, sleep): + """Retry an unavailable provider before fetching valid bytes from the next API.""" + responses = [URLError("down"), URLError("down"), BytesIO(self.wire.hex().encode())] + with patch("prevouts.urlopen", side_effect=responses) as opener: + tx = fetch_previous(self.txid, ("https://one.example/api", "https://two.example/api")) + self.assertEqual(tx.serialize({"include_witness": False}), self.stripped) + self.assertIn("two.example", opener.call_args.args[0].full_url) + self.assertEqual(opener.call_count, 3) + + @patch("prevouts.time.sleep") + def test_unavailable_api_fails(self, sleep): + """Exhausted downloads fail explicitly instead of supplying incomplete evidence.""" + with patch("prevouts.urlopen", side_effect=URLError("down")): + with self.assertRaisesRegex(ValueError, "could not download previous transaction"): + fetch_previous(self.txid, ("https://one.example/api",)) + + @patch("prevouts.time.sleep") + def test_cache_lifecycle(self, sleep): + """Download stripped bytes, reuse verified hits and reject missing or corrupt entries.""" + txs = [self.coinbase, self.spending] + with self.subTest(case="offline miss"), self.assertRaisesRegex(ValueError, "missing cached"): + load_previous(txs, self.cache) + path = self.cache / f"{self.txid}.bin" + with self.subTest(case="download"), patch("prevouts.urlopen", return_value=BytesIO(self.wire.hex().encode())): + load_previous(txs, self.cache, fetch=True) + self.assertEqual(path.read_bytes(), self.stripped) + self.assertEqual(len(list(self.cache.iterdir())), 1) + with self.subTest(case="cache hit"), patch("prevouts.urlopen", side_effect=AssertionError("network on a cache hit")): + self.assertIn(bytes.fromhex(self.txid)[::-1], load_previous(txs, self.cache, fetch=True)) + path.write_bytes(transaction(amount=2)[1]) + with self.subTest(case="corrupt entry"), self.assertRaisesRegex(ValueError, "identity mismatch"): + load_previous(txs, self.cache, fetch=True) + + +if __name__ == "__main__": + unittest.main() diff --git a/ci/test_sanity_check.py b/ci/test_sanity_check.py new file mode 100644 index 0000000..0f9f475 --- /dev/null +++ b/ci/test_sanity_check.py @@ -0,0 +1,264 @@ +"""Regression tests for the dataset boundary, independent of catalogue growth.""" + +import copy +import importlib.util +import json +from pathlib import Path +import tempfile +import unittest +from unittest.mock import patch + +from bitcoin.core import CBlock, CBlockHeader + +SPEC = importlib.util.spec_from_file_location("sanity_check", Path(__file__).with_name("sanity-check.py")) +CHECK = importlib.util.module_from_spec(SPEC) +SPEC.loader.exec_module(CHECK) + + +class DatasetChecks(unittest.TestCase): + def setUp(self): + self.records = [json.loads(line) for line in CHECK.DATA_PATH.read_text().splitlines()] + # Structural tests use a header-only rule. Body-level records must no + # longer pass merely because their supporting bytes were left out. + self.record = self.for_rule("bip66_block_version_below_3") + self.temp = tempfile.TemporaryDirectory() + self.addCleanup(self.temp.cleanup) + self.root = Path(self.temp.name) + + def for_rule(self, rule): + return copy.deepcopy(next(r for r in self.records if r["rule"] == rule)) + + def copy_body(self, record): + blocks = self.root / "blocks" + blocks.mkdir(exist_ok=True) + name = f"{record['height']}-{record['hash']}.bin" + path = blocks / name + path.write_bytes((CHECK.BLOCKS_DIR / name).read_bytes()) + return path + + def validate(self, records=None): + path = self.root / "data.jsonl" + path.write_text("".join(json.dumps(record) + "\n" for record in (records or [self.record]))) + return CHECK.check_dataset(path, self.root / "blocks")[0] + + def test_documented_sigops_breakdowns(self): + """Reproduce both F2Pool blocks' documented legacy, P2SH and witness costs.""" + # Independent incident regression values. Admission still calculates + # the cost of every new body; it does not look up an expected count. + expected = { + 783426: {"legacy": 74520, "p2sh": 160, "witness": 5323, "total": 80003}, + 784121: {"legacy": 72204, "p2sh": 908, "witness": 6891, "total": 80003}, + } + for height, costs in expected.items(): + record = next(r for r in self.records if r["height"] == height) + path = CHECK.BLOCKS_DIR / f"{height}-{record['hash']}.bin" + block = CHECK.read_block(path.read_bytes()) + previous = CHECK.load_previous(block.vtx) + self.assertEqual(CHECK.sigop_cost(block, previous), costs) + + def test_invalid_record_fields(self): + """Reject malformed fields, mismatched headers, unknown rules and wrong reject strings.""" + cases = ( + ("height boolean", "height", True, "height must be an integer"), + ("uppercase hex", "hash", self.record["hash"].upper(), "lowercase hex"), + ("short hex", "header", "00", "must encode 80 bytes"), + ("blank string", "rule", " ", "non-empty string"), + ("header mismatch", "header", "00" + self.record["header"][2:], "header hash mismatch"), + ("unknown rule", "rule", "invented_rule", "unknown rule"), + ("reject mismatch", "core_reject_reason", "bad-cb-height", "core_reject_reason="), + ) + for case, field, value, error in cases: + with self.subTest(case=case), patch.dict(self.record, {field: value}): + self.assertTrue(any(error in p for p in self.validate())) + + def test_first_error_per_record(self): + """Stop at each record's first bad field and continue with the next record.""" + first = dict(self.record, height=True, header="invalid") + second = dict(self.record, nTime="invalid") + problems = self.validate([first, second]) + self.assertEqual(len(problems), 2) + self.assertIn("data.jsonl:1: height must be an integer", problems[0]) + self.assertIn("data.jsonl:2: nTime must be an integer", problems[1]) + + def test_duplicate_hash_rejected(self): + """Reject repeated block hashes even when the two records are identical.""" + self.assertTrue(any("duplicate block hash" in p for p in self.validate([self.record, self.record]))) + + def test_observations(self): + """Preserve distinct child blocks and independent sources, but reject exact duplicates.""" + witness = {"channel": "merge_mining", "source": "archive", "provenance": "https://example.org/evidence", "child_chain": "namecoin", "child_height": 1} + witnesses = [witness, dict(witness, child_height=2), dict(witness, source="independent")] + cases = ( + ("distinct witnesses", witnesses, None), + ("duplicate witness", witnesses + [copy.deepcopy(witness)], "duplicate observation"), + ) + for case, observations, error in cases: + with self.subTest(case=case): + self.record["observations"] = observations + problems = self.validate() + if error is None: + self.assertEqual(problems, []) + else: + self.assertTrue(any(error in p for p in problems)) + + def test_rule_context_required(self): + """Removing any context field required by the rule registry must fail validation.""" + for rule, (_, required, _) in CHECK.RULES.items(): + for field in required: + with self.subTest(rule=rule, field=field): + self.record = self.for_rule(rule) + del self.record["context"][field] + self.assertTrue(any("requires" in p for p in self.validate())) + + def test_sigops_requires_previous_transactions(self): + """A complete sigops block still fails admission when previous transactions are missing.""" + self.record = self.for_rule("bad-blk-sigops") + self.copy_body(self.record) + path = self.root / "sigops.jsonl" + path.write_text(json.dumps(self.record) + "\n") + problems, _ = CHECK.check_dataset(path, self.root / "blocks", self.root / "empty-cache") + self.assertTrue(any("missing cached previous transaction" in p for p in problems)) + + def test_sigops_limit_and_supported_activation(self): + """Require cost above 80000 and reject pre-SegWit records before fetching evidence.""" + self.record = self.for_rule("bad-blk-sigops") + for cost, valid in ((80000, False), (80001, True)): + with patch.object(CHECK, "load_previous", return_value={}), patch.object( + CHECK, "sigop_cost", return_value={"total": cost}): + if valid: + CHECK.check_failure_evidence(self.record, CBlock()) + else: + with self.assertRaisesRegex(ValueError, "does not exceed"): + CHECK.check_failure_evidence(self.record, CBlock()) + self.record["height"] = 481823 + with patch.object(CHECK, "load_previous", side_effect=AssertionError("premature download")): + with self.assertRaisesRegex(ValueError, "post-SegWit"): + CHECK.check_failure_evidence(self.record, CBlock()) + + def test_body_witness_mutation_is_detected_before_sigop_counting(self): + """Changed witness bytes must fail commitment checks before prevout acquisition.""" + self.record = self.for_rule("bad-blk-sigops") + path = self.copy_body(self.record) + original = path.read_bytes() + block = CHECK.read_block(original) + item = next(item for tx in block.vtx[1:] for txinwit in tx.wit.vtxinwit for item in txinwit.scriptWitness.stack if len(item) > 40) + self.assertEqual(original.count(item), 1) + path.write_bytes(original.replace(item, bytes([item[0] ^ 1]) + item[1:], 1)) + # Its txid merkle root is unchanged, but the witness commitment fails. + CHECK.read_block(path.read_bytes()) + with patch.object(CHECK, "load_previous", side_effect=AssertionError("unbound witness evidence")): + self.assertTrue(any("witness merkle commitment mismatch" in p for p in self.validate())) + + def test_body_evidence_is_required(self): + """Every body-based rule requires bytes even when observations are omitted.""" + for rule, (_, _, mode) in CHECK.RULES.items(): + if mode == "local": + continue + with self.subTest(rule=rule): + self.record = self.for_rule(rule) + self.record.pop("observations", None) + self.assertTrue(any("complete block body" in p for p in self.validate())) + + def test_body_matches_claimed_evidence(self): + """Bind the named failure and supplied coinbase scriptSig to the available body.""" + self.record = self.for_rule("bad-txns-vout-toolarge") + self.copy_body(self.record) + cases = ( + ("wrong failure", {"rule": "bad-txns-inputs-missingorspent", + "core_reject_reason": "bad-txns-inputs-missingorspent"}, "does not demonstrate"), + ("wrong coinbase", {"context": dict(self.record["context"], coinbase_scriptsig_hex="0101")}, "coinbase scriptSig does not match"), + ) + for case, changes, error in cases: + with self.subTest(case=case), patch.dict(self.record, changes): + self.assertTrue(any(error in p for p in self.validate())) + + def test_body_parse_error_is_reported(self): + """Propagate a parser error without also claiming that the available body is absent.""" + self.record = self.for_rule("bad-txns-vout-toolarge") + path = self.copy_body(self.record) + path.write_bytes(path.read_bytes()[:-1]) + problems = self.validate() + self.assertTrue(any("truncated" in p for p in problems)) + self.assertFalse(any("requires a complete block body" in p for p in problems)) + + def test_mtp_comparison_includes_equality(self): + """Timestamp failure includes equality with parent MTP but excludes later timestamps.""" + self.record = self.for_rule("time_below_mtp") + for delta, valid in ((-1, False), (0, True), (1, True)): + with self.subTest(delta=delta): + self.record["context"]["parent_mtp"] = self.record["nTime"] + delta + self.assertEqual(not self.validate(), valid) + + def test_retarget_requires_different_valid_target_at_boundary(self): + """Retarget evidence needs a valid differing expected target at a retarget height.""" + self.record = self.for_rule("nbits_retarget_not_applied") + original = copy.deepcopy(self.record) + bits = bytes.fromhex(self.record["header"])[72:76][::-1].hex() + for expected in (bits, "00000000", "1d80ffff"): + with self.subTest(expected=expected): + self.record["context"]["expected_nbits"] = expected + self.assertTrue(self.validate()) + self.record = original + self.record["height"] += 1 + self.assertTrue(any("retarget height" in p for p in self.validate())) + + def test_coinbase_length_boundary(self): + """A 100-byte coinbase scriptSig is insufficient evidence; 101 bytes establishes failure.""" + self.record = self.for_rule("coinbase_scriptsig_length_above_100") + self.record["context"].pop("coinbase_height") + for size, valid in ((100, False), (101, True)): + self.record["context"]["coinbase_scriptsig_hex"] = "00" * size + self.assertEqual(not self.validate(), valid) + + def test_bip34_requires_failing_prefix_and_consistent_decoded_height(self): + """BIP34 evidence must agree with decoded height and demonstrate the claimed prefix failure.""" + for rule in ("bip34_v2_coinbase_height_mismatch", "bip34_coinbase_height_mismatch"): + with self.subTest(rule=rule): + self.record = self.for_rule(rule) + self.record["context"]["coinbase_height"] += 1 + self.assertTrue(any("does not match" in p for p in self.validate())) + self.record["context"].update(coinbase_height=self.record["height"], + coinbase_scriptsig_hex=CHECK.height_prefix(self.record["height"]).hex()) + self.assertTrue(any("correct BIP34" in p for p in self.validate())) + self.record = self.for_rule("bip34_coinbase_height_missing") + self.record["context"]["coinbase_scriptsig_hex"] = "0101" + self.assertTrue(any("no decodable height" in p for p in self.validate())) + self.record = self.for_rule("bip34_coinbase_height_mismatch") + prefix = CHECK.height_prefix(self.record["height"]) + self.record["context"].update(coinbase_height=self.record["height"], + coinbase_scriptsig_hex=(b"\x4c" + prefix).hex()) + self.assertEqual(self.validate(), []) # same number, wrong byte prefix + + def test_version_rules_require_activation_and_old_version(self): + """Reject version-rule claims before activation or with a sufficiently new version.""" + for rule, (activation, version) in CHECK.VERSION_RULES.items(): + self.record = self.for_rule(rule) + self.record["height"] = activation - 1 + self.assertTrue(any("requires height" in p for p in self.validate())) + self.record["height"] = activation + self.assertEqual(self.validate(), []) + # Direct predicate check isolates version semantics from PoW. + with self.assertRaisesRegex(ValueError, "version <"): + CHECK.check_local_evidence(self.record, CBlockHeader(nVersion=version)) + + def test_invalid_targets(self): + """Reject zero, negative, overflowing and above-limit targets while decoding valid targets.""" + for bits in (0, 0x1D80FFFF, 0x23000001, 0x1E00FFFF, 0x01000001): + with self.subTest(bits=bits): + self.assertEqual(CHECK.target_from_bits(bits), 0) + self.assertEqual(CHECK.target_from_bits(0x1D00FFFF), CHECK.POW_LIMIT) + self.assertEqual(CHECK.target_from_bits(0x03012345), 0x012345) + + def test_orphan_and_mismatched_block_files(self): + """Reject binaries without a dataset record or without its matching 80-byte header.""" + blocks = self.root / "blocks" + blocks.mkdir() + (blocks / "unknown.bin").write_bytes(b"bad") + self.assertTrue(any("orphan block file" in p for p in self.validate())) + (blocks / "unknown.bin").unlink() + (blocks / f"{self.record['height']}-{self.record['hash']}.bin").write_bytes(b"bad") + self.assertTrue(any("first 80 bytes" in p for p in self.validate())) + + +if __name__ == "__main__": + unittest.main() diff --git a/data/invalid-blocks.jsonl b/data/invalid-blocks.jsonl new file mode 100644 index 0000000..83d3fab --- /dev/null +++ b/data/invalid-blocks.jsonl @@ -0,0 +1,46 @@ +{"height":74638,"hash":"0000000000790ab3f22ec756ad43b6ab569abf0bddeb97c67a6f7b1470a7ec1c","header":"01000000846e2b968653ef0a25a92c12e8884d76919907df8e3079e665686000000000005eecb6808d6de56a05211483d86fc6c7d17cda46c3388dd0c8139e4114ba8e61751e684c0e80001ccf2fae01","prev_hash":"0000000000606865e679308edf079991764d88e8122ca9250aef5386962b6e84","nTime":1281891957,"core_reject_reason":"bad-txns-vout-toolarge","rule":"bad-txns-vout-toolarge","context":{"coinbase_scriptsig_hex":"040e80001c028f00","parent_kind":"canonical"},"observations":[{"channel":"p2p","source":"stale-blocks","provenance":"https://github.com/bitcoin-data/stale-blocks/pull/65"}]} +{"height":225013,"hash":"000000000000037f2cc0769d4244cf50f1cace4ab76b0b4adb31010e10150708","header":"02000000386dc07a7e4776eb8e87e6a97cf8332b7b873ba8764d0bc206000000000000005ab4785c9cb7a514fe6bbe66800391cbc56400977161d43f9c9bb9bd1b7ac8087d543b514bd7031a63a27512","prev_hash":"0000000000000006c20b4d76a83b877b2b33f87ca9e6878eeb76477e7ac06d38","nTime":1362842749,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a03d74b","coinbase_height":436459339,"coinbase_scriptsig_hex":"044bd7031a0173522cfabe6d6d5f96eead5ea22511ec2950557d0834f76cd860bbee47f1d5bb386270d4f183b80800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":80590,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L2","child_block_hash":"25c0c320839d5fdfa2bea57d6335f212798dad156d243946cb6365e3b496488e","child_block_time":1362842673,"child_header":"01010400d172e1559fefaf57ec032d6aa0541215fb1749fbf27da89210cdf15e6c4de3280c99b52bbebad9660834f0a73cc954cd38e04e4492bb6dc6f3d84ea824145bcf31543b5191c3071b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":120330,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L27","child_block_hash":"6214faa077468141f92a0588f78a3140743b3dc8af6ac7effc9fbc73661bae81","child_block_time":1362842672,"child_header":"01010300ef6f83bfd4c3e1a1d2e47b932bb9c61bfb5795edb602c95c08f19416757179d9e52d09588372602162839a72ae83a9a3d470c0cd676135a95533fa5138702b1830543b51728e021b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":99370,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L42","child_block_hash":"43aeacac4539943a530413ecd48eeea120544dca1c1a9f2718d6cca482f0a729","child_block_time":1362842196},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":225015,"hash":"000000000000015437122b60d0a1d2ed7e1f98b5b292e886d6ca62042bba2035","header":"020000007b857cd06c12f2a8e032bc38215b8ebbbe387f3b1bd487a92600000000000000900b7044d905f7e58bfc9d98b5e298a86fdfb1e2ea86c892c010fceefc6568e43f573b514bd7031aea797c30","prev_hash":"0000000000000026a987d41b3b7f38bebb8e5b2138bc32e0a8f2126cd07c857b","nTime":1362843455,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a03d74b","coinbase_height":436459339,"coinbase_scriptsig_hex":"044bd7031a025001522cfabe6d6d43629863b5b1d5de8916a8bd7cbd1918bc6543e246e7ba6e55bf745dcb513e2f0800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":80595,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L3","child_block_hash":"4cb852207cf335969f2ec2cf65ffabb657818e4b65f87e97f52932ac46a28f8d","child_block_time":1362843422,"child_header":"01010400cf2a6264a20af2fb0b4d43af8d79115d54ef83980e149f255afad643d0d433202558e4f3bfea7775606c42f65c1e19ccfb4c3489ff7c9b96f9eeb1df43d946891e573b51cba5071b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":120333,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L28","child_block_hash":"5b9a346a5060370d6aa8a0a3467c5563b38d62d2a2bae2017956c5e0222d5806","child_block_time":1362843421,"child_header":"01010300f1e2ef20771d69fe2d265356eca3dc7c178b270a940ddb5930992bdb609168c5695d33c7a85439a88244feac2772f8e13c82b6ab85f87294e9bb2bca93657bb81d573b51728e021b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":99371,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L43","child_block_hash":"0530563a96697ca4e83d6db1b5ef3071215cefc643467be5c4f5500f39adc3d4","child_block_time":1362842753},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":225134,"hash":"00000000000003abc9b545f105aec0a14cab2b65665f967b2527b61bb25e21bd","header":"02000000fb061d4b8bf9481f83015cfab27775637b2dccd41b9897990b030000000000009092b803d258eb4204aa5ddd1b5cd30e0cc686482e7c9a9b9aa66c8bdeb49030ee233c514bd7031ae3c9a949","prev_hash":"000000000000030b9997981bd4cc2d7b637577b2fa5c01831f48f98b4b1d06fb","nTime":1362895854,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a03d74b","coinbase_height":436459339,"coinbase_scriptsig_hex":"044bd7031a0163522cfabe6d6dbc4328f620ad2dc10be02522a7cc7f0ae498b549888f50859690fece2d306b320800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":80734,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L4","child_block_hash":"28ddfb7730a86c3ae551339a757d50408dd6910efb3b8a27754aced594b8498c","child_block_time":1362895508,"child_header":"01010400204c0bbe2f827b762f384bca89f5fad1efb20d298a26d65e3d45911e2925dc8ff79f0421d2bdab5e4cde7032efe2ac5cf481e343bbb35bdf27d5746fe571ba9994223c51216e021b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":120574,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L29","child_block_hash":"17ad05bb5c0fa486ded594f663e50f23ee20a24bcb99055669e8844af2f74505","child_block_time":1362895741,"child_header":"01010300fda1499bd7d06132f44b4cbeca4aeda85bb9977fcc0510cd7b499c285f5c215f792b856e4cd3c44f34fced7c600512f5c66577834a8253500cc07a3e3f8b69187d233c510303091b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":99462,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L44","child_block_hash":"5e76c749131b42cace33e8a4eb2abe4d01dacc8789f5960f983af725b5faa75c","child_block_time":1362895571},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":225145,"hash":"00000000000001a3aa38003bb99c2bb16dc48dfcf5542ddf86139e639ff51433","header":"0200000071ac9ec4f545de83b50dd06f02617b2641e91795fc81bbe5620000000000000058e90dbf39d25518f2adfb453e62ef9c1b10045b0e951fd7226deec3b24360799b3c3c514bd7031aa4124baa","prev_hash":"0000000000000062e5bb81fc9517e941267b61026fd00db583de45f5c49eac71","nTime":1362902171,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a03d74b","coinbase_height":436459339,"coinbase_scriptsig_hex":"044bd7031a0123522cfabe6d6dd14fcb9aca36a2eda2d2a5697fd1937b98d28349001f69bf4a2608bad70776dd0800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":80749,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L5","child_block_hash":"0bf768f6cea5c5690b53dece76b26124a923ee9f41415d2c8cfebb27252f8e92","child_block_time":1362902063,"child_header":"0101040028616a0105bdbd8190b0db70d3344988767544972a2fad8732750f1c13162a6e46e0c471a8d631b38c9c2f7ad9307e2cdb8848e538eddc6510b444761943b9a42f3c3c51e242021b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":120612,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L30","child_block_hash":"a0716f57d734fc68c4d6bbce35a16a00a252aa8b50dc3f673953447573342170","child_block_time":1362902127,"child_header":"010103006a6eb591034d678463a3405131ec8a9a6c33c002a339b5966ce7bb17e1a150b6e4f274ff8d0354e2f190509df101ef9f713ab9596979180d11ee1ec3a2ec4f386f3c3c510303091b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":99474,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L45","child_block_hash":"a1d1c8925f45bf833917e18d55c68b3cb0de663937628d76fae347e0b8da38dd","child_block_time":1362902081},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":225221,"hash":"0000000000000386f943ff46dbf220fed2ef2ce55214d6fce868db21507ddc99","header":"02000000e21d1552e98b7e27ef520831a493f9b066e0337de4a94657bf010000000000005364c40df1d34c42c986efe3210a6da8e734ef5430acf3df84af1eb8a402b37960cc3c514bd7031a37df7135","prev_hash":"00000000000001bf5746a9e47d33e066b0f993a4310852ef277e8be952151de2","nTime":1362938976,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a03d74b","coinbase_height":436459339,"coinbase_scriptsig_hex":"044bd7031a59522cfabe6d6db0539f1943fa0263ab4bc7be9259f1270ebaa0d23733e662654b6a049aa054880800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":80807,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L6","child_block_hash":"4b6a57eac0c83f4c8dec5df31d6aa6f84e9e9d538c3b19990b502b106a951deb","child_block_time":1362938031,"child_header":"01010400e4e5e07511c40b8608f39eab53fa27d02036e55d6585226c4230db4bfab906df27a7d9449f472a9ab5a09c45da03dab09f6f9218d3c721f98e5f534c7c64d491afc83c5155cf011b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":99535,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L46","child_block_hash":"bcb37b2ea04949e52ce41fd3fdbba4019cabe7dec93085cdf249233e95948b50","child_block_time":1362938816},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":225430,"hash":"00000000000001468e0b21b62cd0b41ec317eeeaa5afc0a8df43c01180e57f7f","header":"0200000006d04625789f74813125765744bf8c4e0900893328ca98ce66030000000000007d0a60c5177d95e08ab82903dc7aef1fa7f63c17c3aba40e4826f252580051a687583e514bd7031a865b53df","prev_hash":"0000000000000366ce98ca28338900094e8cbf445776253181749f782546d006","nTime":1363040391,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a03d74b","coinbase_height":436459339,"coinbase_scriptsig_hex":"044bd7031a60522cfabe6d6dd2a3e6a60af19ef1519a648a205be968aa42d0040a12ea7e2aa6410e80a9313f0800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":80961,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L8","child_block_hash":"fd160092c46f8dcefbf5662e9b517a9935e0832ec7a34e6fb532e34a77e1df76","child_block_time":1363040328,"child_header":"01010400c7b2fee7ec86251adec32c8f5296e3ed7a5380dedfdf7dc5cee7b3e94eb6eeb1d00f0087105ee2cb965658f249e4f53ee61e46ab2c46e8ccafd20ab3a7689d5448583e51e3fd011b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":121267,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L32","child_block_hash":"fb5de9740c981f07563db8dd0afe3c97360ba1c1669ea85cd0951929664a8889","child_block_time":1363040305,"child_header":"01010300447ba4e8b75029dc511355e01aa4d22f5e92061891c39be84de71fd25341231230a08bc39a7380ddc60651704a850934ae8440c0d38f6bbbb11098178e7a751131583e511710061b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":99715,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L48","child_block_hash":"3afcd143f3a1486770294eb3584b4040d5b914b5d0cef77fab14441396339246","child_block_time":1363040304},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":225430,"hash":"000000000000017c4a0a7be4244a3b2c0dd41f884586ad8de78356a0994e8960","header":"0200000006d04625789f74813125765744bf8c4e0900893328ca98ce6603000000000000a6eeff902159dffcb4229785324170c04aca85096c288225c10e8071d68bc62e27583e514bd7031a269c603c","prev_hash":"0000000000000366ce98ca28338900094e8cbf445776253181749f782546d006","nTime":1363040295,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a03d74b","coinbase_height":436459339,"coinbase_scriptsig_hex":"044bd7031a0161522cfabe6d6d11011523a342d5a6a793d960db1f1393207dd969bc87be8058b6877f28f639cd0800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":80960,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L7","child_block_hash":"b1eeb64ee9b3e7cec57ddfdfde80537aede396528f2cc3de1a2586ece7feb2c7","child_block_time":1363040111,"child_header":"010104005115cd08511f9de1c5140fa7948192355a16e200ef623045ce75c25c7ab6bb926537b21fc4f0458976d207d0f1bc6a735d2bd85980ed5655a94e8a5d549c1d556f573e515d07021b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":121266,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L31","child_block_hash":"12234153d21fe74de89bc3911806925e2fd2a41ae0551351dc2950b7e8a47b44","child_block_time":1363040110,"child_header":"01010300a6a849600a844dd6aa03d5ac5fe7763cc5690455ef1f0d1849b9f61c3d538fdcd678c74e78288b1d1d17209dd3a2b672d5ab254f314eb738939e5580256f8fa96e573e511710061b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":99714,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L47","child_block_hash":"48a1792f661402f596cea37746110bc0abb545951b190213ae32ff06b2932b77","child_block_time":1363040171},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":225464,"hash":"0000000000000085a485d05c96051ff43ea70b8868d7373df9de771ca65b52c9","header":"020000005d520cf0ef788857fab3eae748c283d7adc95e9c70506e2de10100000000000008a8b5401a5ca734d4c479785caf00771abf72912271a04b9d35a44571957d01c6dd3e514bd7031a2fc4ac21","prev_hash":"00000000000001e12d6e50709c5ec9add783c248e7eab3fa578878eff00c525d","nTime":1363074502,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a03d74b","coinbase_height":436459339,"coinbase_scriptsig_hex":"044bd7031a028c00522cfabe6d6d16e6f88281aa9c8e23d07358e51aef40e8314c14debbe9b7569af3644962f8860800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":81009,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L9","child_block_hash":"f7a88536d8bcc5b649f42d66daecddda3b3de1ddf8b8e542ed62a9eaed946565","child_block_time":1363074436,"child_header":"01010400ba0addb8fe8b08f3243ff8e22a08c2093972286594777a33ccb1251af880f124843e5f39a29173929f41b0a0702d214dcd0e804d95ae1b54703efa4a2eb382b084dd3e51e7fb011b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":121399,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L33","child_block_hash":"e9baff68f1504f4f3634d51c19821202da7be18317723082564ba9cf37c2b25c","child_block_time":1363074422,"child_header":"01010300b2480c6ee578d461e146db608296f125a82271d3a606a499555e1ed56f4522f6575df851aebc9cf12d17c8d91900734a4875059175da9aea6bb2a736877ea42376dd3e51f6b2051b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":99771,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L49","child_block_hash":"a6d12172da309eab059c1a6122452b111bcd308e07b327e714e90472a4403c6d","child_block_time":1363073898},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":226230,"hash":"000000000000004cf2026785b16399bea2abab0f8b8a82d070ac0db40a06b3cb","header":"020000001849df411d256460fde8722a0b32fbb8a6b99d611f4b76e59f02000000000000c7052bbc6cd53cb2d7925cb99fa0e8d743f725463a527ef380d01a2ccbd805bf18df4451fa75031a83d77fbf","prev_hash":"000000000000029fe5764b1f619db9a6b8fb320b2a72e8fd6064251d41df4918","nTime":1363468056,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a0375fa","coinbase_height":436434426,"coinbase_scriptsig_hex":"04fa75031a60522cfabe6d6d447172e8723db361a6e8c8d1df6be09db405940728e05acfa6622fd07a8a4a100800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":81561,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L10","child_block_hash":"be03a6a2c8057a0a93fa2fc419e15e53bda24f68310d372c63d709c19ece86bc","child_block_time":1363468054,"child_header":"01010400c6e9dcd58c4bcab8dc501d166dc19b3a57a61c30b1525bc45de394d1a1382a0053c921259866451bcc82d1c34fff94910bb35928dafd7d9092cc409cc6c8cb3816df44516369031b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":122307,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L34","child_block_hash":"8cd097c2d00fcb14d58e1a3ab88812f8128fadf0b0a8d0fbf6d2a577959aed3a","child_block_time":1363468053,"child_header":"010103002fb21446eb5fc039b17c7b8a8ac108f82f1812b744df213815c42bebd359431804feecfd6510da8bbaa7a5998daa8b53c50da51c476408576e13959a04c41d9615df4451dfd2051b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":100567,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L50","child_block_hash":"7c3b67677f6024bbb5099133cd10974a746902c0795027d8dda0179bc948103c","child_block_time":1363468027},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":226845,"hash":"00000000000000c37c3327de7555db3e3dbe91cbe0294e532f8a32574d5b997d","header":"02000000f77ebccf92b40cf51a525875220875df01b95c778ddf8ac52f030000000000005d4e6eba589cc767dd1a2fa1dbbbc9c35f28b9ded13447b43d8acf8c3e0bbce2522c4951fa75031a2e7bb6a5","prev_hash":"000000000000032fc58adf8d775cb901df7508227558521af50cb492cfbc7ef7","nTime":1363749970,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a0375fa","coinbase_height":436434426,"coinbase_scriptsig_hex":"04fa75031a0164522cfabe6d6d8ff0a68e344b586a001a21254da9133a46d86d070ddd2c19529d6c273a7b263d0800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":82009,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L11","child_block_hash":"6d485b52fb8779e1a917607a2a954d45052f22fbd8050ebce16dda8f215904bc","child_block_time":1363749310,"child_header":"010104001abe9af97f4ecfdd8752535f0e51d64651f6827a3a7ffb47f26ffb0e301a2439d0d9f5c384025acb7aabd5fa3dc0ba8dcd0d850da2f15f8c5e801aa069c3d6f0be2949519589021b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":101111,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L51","child_block_hash":"4b136930741efaa66d716dcbeb07b89be946e00e65b1f473d0c2a7c4469e3d43","child_block_time":1363749919},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":226895,"hash":"000000000000030a6d0a4a0c91af3610843d170594eac75cc8a0e16390ba9559","header":"020000006036e5185cf3827a9a67d45375ac98fb3ec26b598a86204fdd010000000000002fff1208697910da11f0f06122c0fb16a4213c341b7d4ea8ea38c23012057463b07d4951fa75031aacfaebd9","prev_hash":"00000000000001dd4f20868a596bc23efb98ac7553d4679a7a82f35c18e53660","nTime":1363770800,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a0375fa","coinbase_height":436434426,"coinbase_scriptsig_hex":"04fa75031a024502522cfabe6d6d016035269eb3ad99d1ff362ebd4536c56037cba0deffeb2bf2409cd7ae79bafc0800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":82041,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L12","child_block_hash":"7dd41fa396dd483ae9ed6c095e0f099fc08d2f9e02f84742a58221f86dcf01d7","child_block_time":1363770749,"child_header":"0101040049e26ec9674ec4379332081fe1a7422ef18fab2fc3f5ce3245b1ebef88d9fc6523078a428d3f35f1654dd284c1666da2bd467a43ff9c9dd717682f2cdeb2597e7d7d49512673021b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":123067,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L35","child_block_hash":"f1d33597c5a630efecb37f0f66d3d67d6b9304500cbcf67d32e2b25e4ae24bad","child_block_time":1363770766,"child_header":"01010300b85255534b2054921a7ba22b9d8bce8de210c9fd2cf4630fffe783d228017e9563464e3a15de351a173fe1462adbcb3efa3f6082822ad393c9901b556b96008e8e7d49519e0c051b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":101158,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L52","child_block_hash":"29ceb559c8e4e4e12e419564220608af50a4e14517f84d96d8d78af2308350a2","child_block_time":1363770774},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":226912,"hash":"00000000000000a34d399a3cb82e222fad8e73e465b905e333ada1662c61e0e0","header":"0200000027e41c96a70919889e3f3f198e753ab05e7abad736ef9e660b01000000000000194b8dc54fb94a7134e6ba959266725ddaf0cbdcc51deba763b314a188d0f4d305994951fa75031a53b3fdc6","prev_hash":"000000000000010b669eef36d7ba7a5eb03a758e193f3f9e881909a7961ce427","nTime":1363777797,"core_reject_reason":"bad-cb-height","rule":"bip34_v2_coinbase_height_mismatch","context":{"expected_nbits":"1a0375fa","coinbase_height":436434426,"coinbase_scriptsig_hex":"04fa75031a02ab00522cfabe6d6dfd815d1d65ff88b939971ca477af659572ea9543a296e67d465c60ef342bfa500800000000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":82055,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L13","child_block_hash":"777783caba68202d4cc012203def39694ec8698edd280b8bdf74aafbc305957a","child_block_time":1363777739,"child_header":"010104008463a8d9e8e31552f6070b44a09019a6242cd501e947bb94002a6f632314c669c279e4ed90f89c5b09e1578287a629488f55cdc64fba55a617d1810c986b621ecb9849511460021b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":123093,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L36","child_block_hash":"6423a2132ba0d7523e2cffb4e21c74a0287ce9b4c677bc431825c81c92da8335","child_block_time":1363777719,"child_header":"01010300c5577918c001b292902ab13c55dc5c332866e27323df0fdd42e1003c58a838cd9e9254998563bc6de120417204f8ec88b7d76355c070253602b4593346bdad7cb79849519e0c051b00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":101169,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L53","child_block_hash":"46a3c04b871ab54058bf4b339bf77fbe94ab769437dc286fb1099a2ea7add696","child_block_time":1363777754},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":229388,"hash":"00000000000000329b2b44eca61829f13c94bbafb35022f13e49ffff279e3f03","header":"02000000f1ee309b4cd8cca9b0d7de01af3f7445bb4a1d6cef49b0b8380100000000000005082ee9139cb8e8b74afed2b16b2671371ee60b5959d7896d42b09def2e83273fb75b516e81021a5f159853","prev_hash":"0000000000000138b8b049ef6c1d4abb45743faf01ded7b0a9ccd84c9b30eef1","nTime":1364965183,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"1a02816e","coinbase_height":229426,"coinbase_scriptsig_hex":"0332800370736a046e81021a04e900c812522cfabe6d6d84a6a479387f8dfdc7b3256d61e2d5ba08d6dd2adb8090010936cff61dfebce70100000000000000425443204775696c642033ac1eeeed88","pool":"BTC Guild","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":103543,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L56","child_block_hash":"84a6a479387f8dfdc7b3256d61e2d5ba08d6dd2adb8090010936cff61dfebce7","child_block_time":1364965116},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":229388,"hash":"000000000000008af04b94d8286fe0e8d0aea3b2f35e758ef1e73e153169fa58","header":"02000000f1ee309b4cd8cca9b0d7de01af3f7445bb4a1d6cef49b0b83801000000000000e37420b5b31b8fca3391c447b2e2ac4919ef5b546d9a55637da33d9e13f57c2ae9b35b516e81021a2f08c260","prev_hash":"0000000000000138b8b049ef6c1d4abb45743faf01ded7b0a9ccd84c9b30eef1","nTime":1364964329,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"1a02816e","coinbase_height":229425,"coinbase_scriptsig_hex":"0331800370736a046e81021a04f9bfbe12522cfabe6d6d09236c4cc87a673a8b478605e6fcdd5585c5bc4609916597bd962bd2ed862e680100000000000000425443204775696c642033ac1eeeed88","pool":"BTC Guild","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":103541,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L55","child_block_hash":"09236c4cc87a673a8b478605e6fcdd5585c5bc4609916597bd962bd2ed862e68","child_block_time":1364964071},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":229388,"hash":"00000000000001365d20401c25e9c8c1bc1570f99a943bc1575b20e16d77a18c","header":"02000000f1ee309b4cd8cca9b0d7de01af3f7445bb4a1d6cef49b0b838010000000000002ec69a1597e707ae5eff51be565ff16b8a712f946aa489046563b34db4ef9ac9bcef5b516e81021a9f76b3ea","prev_hash":"0000000000000138b8b049ef6c1d4abb45743faf01ded7b0a9ccd84c9b30eef1","nTime":1364979644,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"1a02816e","coinbase_height":229457,"coinbase_scriptsig_hex":"0351800370736a046e81021a0402076813522cfabe6d6d9f81006fa0cb5799f97b3f8ee995dbbda55c1e83754d64cadb321d1db65dc8d30100000000000000425443204775696c642033ac1eeeed88","pool":"BTC Guild","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":103577,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L57","child_block_hash":"9f81006fa0cb5799f97b3f8ee995dbbda55c1e83754d64cadb321d1db65dc8d3","child_block_time":1364979601},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":229388,"hash":"00000000000001fb5262fee5a4b0e93f1274226980cc0893dcaa9dd9e1187f95","header":"02000000f1ee309b4cd8cca9b0d7de01af3f7445bb4a1d6cef49b0b83801000000000000130c108a5443c5742eceaaa4d5b76081030a4c27f0e1d30946e73b1ac9d982926b955b516e81021aa75feaa6","prev_hash":"0000000000000138b8b049ef6c1d4abb45743faf01ded7b0a9ccd84c9b30eef1","nTime":1364956523,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"1a02816e","coinbase_height":229405,"coinbase_scriptsig_hex":"031d800370736a046e81021a042a066b12522cfabe6d6d3f9360023bc09ec8ffce3d57c1492bbc8e1b1d0144655509fca0e1ace595c31d0100000000000000425443204775696c642033ac1eeeed88","pool":"BTC Guild","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":103522,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L54","child_block_hash":"3f9360023bc09ec8ffce3d57c1492bbc8e1b1d0144655509fca0e1ace595c31d","child_block_time":1364956453},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":229388,"hash":"0000000000000239bfc9b6f400b5b02ab401077bdc470d082e3da34276925cc8","header":"02000000f1ee309b4cd8cca9b0d7de01af3f7445bb4a1d6cef49b0b83801000000000000ce886eb61f833834a8cbb315c864bffd70d3affa3da07db505a9c901e9556c84650c5c516e81021a2f1c4c17","prev_hash":"0000000000000138b8b049ef6c1d4abb45743faf01ded7b0a9ccd84c9b30eef1","nTime":1364986981,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"1a02816e","coinbase_height":229471,"coinbase_scriptsig_hex":"035f800370736a046e81021a040d94ba13522cfabe6d6dd48364adb1effd444f3c8d87680ed30368fd5b12d0e20ea956578132f9df04160100000000000000425443204775696c642033ac1eeeed88","pool":"BTC Guild","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":103588,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L58","child_block_hash":"d48364adb1effd444f3c8d87680ed30368fd5b12d0e20ea956578132f9df0416","child_block_time":1364986963},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":229388,"hash":"000000000000024fc7ce00ec89295323699886784960f68a04f4a4871b61caa8","header":"02000000f1ee309b4cd8cca9b0d7de01af3f7445bb4a1d6cef49b0b8380100000000000017caa8b8538d2a3ecd5f1de8dcf26188ed759ef855cfbb7a94f5e45346cef99b314a5c516e81021a528e3ac6","prev_hash":"0000000000000138b8b049ef6c1d4abb45743faf01ded7b0a9ccd84c9b30eef1","nTime":1365002801,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"1a02816e","coinbase_height":229506,"coinbase_scriptsig_hex":"0382800370736a046e81021a0430a77b14522cfabe6d6d71c2e6d47b4b265b5ad2f064723ecd40bc7eee5267d59df1aa84989c0cc87dc10100000000000000425443204775696c642033ac1eeeed88","pool":"BTC Guild","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":103624,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L59","child_block_hash":"71c2e6d47b4b265b5ad2f064723ecd40bc7eee5267d59df1aa84989c0cc87dc1","child_block_time":1365002734},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":277975,"hash":"0000000000000000de6f0b2978aa2b268cb9a54c5de6d21f97d17c6b0ff0ac3f","header":"020000002db9320653d57e6cdf66a0d2b01a0aa44cfa7a188bd973a801000000000000004a573e6262ea4d71195a4cbe22da361e554e9a75695e73ce3547a6657799b52dda30c3520ca3031992d8c3c3","prev_hash":"0000000000000001a873d98b187afa4ca40a1ab0d2a066df6c7ed5530632b92d","nTime":1388523738,"core_reject_reason":"bad-cb-length","rule":"coinbase_scriptsig_length_above_100","context":{"expected_nbits":"1903a30c","coinbase_height":277975,"coinbase_scriptsig_hex":"03d73d04062f503253482f04bc30c352082e02a002002bed9a4d522cfabe6d6d711f2290b40d6f75dc3fa9d2245d018ce18782d3e4b9b4feff5b16cdacd4743004000000000000004861707079204e657720596561722120596f7572732047486173682e494f2e","pool":"GHash.IO","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":120059,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L14","child_block_hash":"20b36cb62172235862776e5c5211b9e38702e2e7a3d3aa7193b220293d1e4dae","child_block_time":1388523571,"child_header":"01010400b648b8637e37ab1ff24cd51b1f8fe7b6bb71fb5cd99376a1bef50aef1d5728309739d38ed7f9fd09b97badb10dcb0110a19992b7cceb4dc801cf54e1af5976c33330c3521b84071900000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":181126,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L37","child_block_hash":"a6a29c257ec54bc8b2fc6c3e9eee656f0446728f5ff8b1b3f4737b79e9684250","child_block_time":1388523444,"child_header":"01010300ff41e731043c8e5706c31dd8c91798da3cd5199dbf336d3e072e5a4b8d8d10e133ceaf70da4ffd18f761bdce7e8d5f845ef1ccfd0fbe3229911805f67d9fc804b42fc3522b75091900000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":154429,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L60","child_block_hash":"e24a30c11ea8cf03abcf677699e83952972d75069c36ef378789da4d7a350726","child_block_time":1388523641},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":331673,"hash":"000000000000000010bcbb75dc17fce43da835bd26ccec95ed0d39570a51112a","header":"02000000d7384068c6519dd9433298ccc83e584ffa931d81b447b4100000000000000000592005770073e8125fb2c7509e00322316974bbc2157a8d31790f831652a325d198e755461481b183dacedbb","prev_hash":"000000000000000010b447b4811d93fa4f583ec8cc983243d99d51c6684038d7","nTime":1416990233,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"181b4861","coinbase_height":331674,"coinbase_scriptsig_hex":"039a0f05e4b883e5bda9e7a59ee4bb99e9b1bcfabe6d6d40c126ee5ab79a5d91c96be476ae5b8dd1af1a08e59edb8ff44122bd8d127d2d100000000000000000948656da9c02004d696e656420627920796f6e676368616f3334","pool":"yongchao34","parent_kind":"stale"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":163400,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L15","child_block_hash":"d0b8fa609e522cf20d0223e1c66f94d8f35794881c2357570b56b958ae5a07c3","child_block_time":1416989992,"child_header":"0101040086d0d5b5bc67f153c40c9266cc85aa0c944b043f86368b2fada702f249945554e501aa172c507b31f2d925f4fc5e42f3295288a7e3b1ea34b3ef77bfc00f8030288d7554497f3d1800000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":234208,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L38","child_block_hash":"c27064d175645affe3f703818d4b2b27764c512f3d912082a4a70c423151ad20","child_block_time":1416989784,"child_header":"01010300aa9497a4cd799ab3953d0f94888ff1854878bf4dec983a2499c591d651b6c1ec5d5e2b550db70d353683f6ff370f355e0e4d18c037cdd95b3523b3c1dde0c542588c7554f8f93d1800000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":207157,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L61","child_block_hash":"f34f5d8bf1857c37ca8ea966c2ca199d423a3a666dc132d9a1a8ea74855accab","child_block_time":1416990212,"child_header":"02010100896049400e7d37d8eb9c35bc96caa3b429227d4df2e2d33e09095eca786dc88388e763d146aeae0c87f34c8be0c444fe42783bb17dbb167f759f98f23589e76c048e7554f955331800000000"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"i0coin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"i0coin","child_height":1315879,"child_block_hash":"e234210c7550a5dc4c2712e339824678a96a2e47e0a806c6f773458e73b9b634","child_block_time":1416990003,"child_header":"010102006e033211137d2b831fcc40e3c985d3db86a90b42d6c50da7524bb0c7a54456547080f2f23aa3610ecb649986357063318f0ea24970da7e775fd918ddadbc9539338d7554e1d1031900000000","provenance":"https://drive.google.com/file/d/11-D1r5s8267YmOT1VaObrcmVoV8d_JAn/view?usp=sharing"}]} +{"height":331674,"hash":"00000000000000000d610e393ffeed6b9494d54121f05f7a3905f940f0e0cf69","header":"020000002a11510a57390ded95eccc26bd35a83de4fc17dc75bbbc10000000000000000049ef9f18b223482653e3587739cc9adbc70a4d79b1b3b5dd7fc143b791d7c6c1e58f755461481b180b3bf3f3","prev_hash":"000000000000000010bcbb75dc17fce43da835bd26ccec95ed0d39570a51112a","nTime":1416990693,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"181b4861","coinbase_height":331675,"coinbase_scriptsig_hex":"039b0f05e4b883e5bda9e7a59ee4bb99e9b1bcfabe6d6d43ca0fd0c1489d7195b50b67a538a60a8aac6e5782e44261ae0c5ada2b2fbce11000000000000000010c01ffda4701004d696e6564206279206c656e676775616e677869616e","pool":"lengguangxian","parent_kind":"invalid"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":163402,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L16","child_block_hash":"27dfdd8329a651e3036ddafd9939fde96a1b627b72f6412dd149a7bd05f9a232","child_block_time":1416990547,"child_header":"01010400a986bc310ce72f074d892c68a25056bdd28a47ba398086a707ae56a65743569ea8f61788b3aef6d8134dcb16a21afcddb3aa191d3ecf6bfb61a0dc1812d7ae8d538f7554179a3d1800000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":234210,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L39","child_block_hash":"31353dc7469095c0324bcc9c39377e9f85c167d0d254d4cdd32e41214544f55b","child_block_time":1416990614,"child_header":"010103006597b87f08297e06ba8aea3d98f7adef652c21bbe90a63cb6286762085972804608a2c43e6588679c6d911eaf58a8ebfd32e21312286b469eda990ea66a18179968f7554f8f93d1800000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":207159,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L62","child_block_hash":"cf7b250b370d7cfc8823919994bb2b90ebc1e8e3d92620c5543e1763e3b1245b","child_block_time":1416990551,"child_header":"02010100e7a3536edf7ebbcea39d5ac542b59083ef26737164d0296a68dd2af28ffad735572d6632f0f6dc1598f86affce191fa7ce6dfb4a0fe474f7ce6ed6c45b8e3eca578f7554f955331800000000"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"i0coin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"i0coin","child_height":1315884,"child_block_hash":"55491ea85a0d48e43710cbbfeb22c88d828596484f443c8154fb6db83e0157d9","child_block_time":1416990688,"child_header":"01010200e26cb8806a9d66176b099dd02f985615c80dda45b66cc4bc33a50f191f26fe58201fb0800de1051022c3827dc6dee57827f68f22fefb198476d7100160273de0e08f7554e1d1031900000000","provenance":"https://drive.google.com/file/d/11-D1r5s8267YmOT1VaObrcmVoV8d_JAn/view?usp=sharing"}]} +{"height":331735,"hash":"000000000000000010d43fb3f8d02cab156f333f2bfc172de9e6d87359118a1a","header":"02000000b228e7793c713d7452898047cda97c6a18eaa89a7beae71900000000000000001996d26e735c678ef161026ad86a07cd3bc57ff8796c7d79dd975bbeae841b64dd34765461481b18e7e8d1db","prev_hash":"000000000000000019e7ea7b9aa8ea186a7ca9cd47808952743d713c79e728b2","nTime":1417032925,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"181b4861","coinbase_height":331736,"coinbase_scriptsig_hex":"03d80f05194d696e656420627920416e74506f6f6c201197731e547634ddfabe6d6d02b0c8aa564c26d206db1bb2305bf3cba8ad46f355e7238fa5864a06a3a776ec0400000000000000650200007f58e854","pool":"AntPool","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":163460,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L17","child_block_hash":"12531c85a17b26e3ad3442ed7536f48d7b1e8973b181ae9abdf1b8e15974ac2e","child_block_time":1417032681,"child_header":"01010400b85cf26bc29272399c2f904f2fb36d3f05b7203ef1615d95ce60e02c52b45adf859b644f31b0ff8537ec07b06a8edd1a1ae6b5b1aadd455e79252fc44571ae03e9337654f86a351800000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":234279,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L40","child_block_hash":"9ec0a5e6e2afa97a097c28ae71998fdd5230ad02c0e1eb6a238c66db6691c334","child_block_time":1417032681,"child_header":"01010300e9f7bd989f4e6a68be9a694f3077490fabc670a0996e87b9342245b443efc5d1343c3df28ad10df76ff945d17e442f94c4ac110a79459023673a5d2acf4ebd3ee9337654f8f93d1800000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":207232,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L63","child_block_hash":"aa1fdb54f4ba89a6f0e0b4196b5613540e6c1febf9f89adabede9eb81ef3ff31","child_block_time":1417032681},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":363726,"hash":"0000000000000000032527aa796d3672e32e5f85a452d3a584a28fc7efbcd5d0","header":"020000003109b588941188a9f1c2576aae462d729b8cce9da1ea790300000000000000000f5a43f10171ff87c1411e5c5478a72fff16b12023ee382168515b18a41b83c1543d97558e41161831fc274a","prev_hash":"00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931","nTime":1435974996,"core_reject_reason":"bad-version","rule":"bip66_block_version_below_3","context":{"parent_kind":"canonical"},"observations":[{"channel":"p2p","source":"kit-mon1","first_seen":1436886615,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon1.json.tar.gz"},{"channel":"p2p","source":"kit-mon2","first_seen":1437057180,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon2.json.tar.gz"},{"channel":"scrape","source":"blockchain.com","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/blockchain.com/orphans_blockchain.com.json"}]} +{"height":363847,"hash":"00000000000000000c9bb4a508fff34f5450d9c62ef2cb833e53909a4c549de5","header":"0200000076e168bf1a90e1d8b11ecced4a0fb346f3e22832edbf3f0c0000000000000000733a6d9f466fd1c278b401fa8e1298e260ec46a510f4f5baa03ab09a9cfde4d7955298558e41161873fb1718","prev_hash":"00000000000000000c3fbfed3228e2f346b30f4aedcc1eb1d8e1901abf68e176","nTime":1436045973,"core_reject_reason":"bad-version","rule":"bip66_block_version_below_3","context":{"parent_kind":"canonical"},"observations":[{"channel":"p2p","source":"kit-mon1","first_seen":1436886879,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon1.json.tar.gz"},{"channel":"p2p","source":"kit-mon2","first_seen":1437145172,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon2.json.tar.gz"},{"channel":"scrape","source":"blockchain.com","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/blockchain.com/orphans_blockchain.com.json"}]} +{"height":363967,"hash":"00000000000000000954ed93eda1e79e8261137548fa9ccf4d516bb384a3660b","header":"02000000d0ee922c45dfe214d3aaaddbe314faf9faeb52d88b2e9d000000000000000000742832b0e5574ef9653054858b6a9459a9cb46ddd95aa091b993e0df96a48c6a7f5999558e411618a20e60e8","prev_hash":"0000000000000000009d2e8bd852ebfaf9fa14e3dbadaad314e2df452c92eed0","nTime":1436113279,"core_reject_reason":"bad-version","rule":"bip66_block_version_below_3","context":{"expected_nbits":"1816418e","coinbase_height":363967,"coinbase_scriptsig_hex":"03bf8d05045599597ffabe6d6d27e048c4a0bfe74e325a7c96ace681cb0857905425f4c24ca88fb3b646fed3e70100000000000000180100004c534b02","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":237930,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L64","child_block_hash":"27e048c4a0bfe74e325a7c96ace681cb0857905425f4c24ca88fb3b646fed3e7","child_block_time":1436113379},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"p2p","source":"kit-mon1","first_seen":1437145232,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon1.json.tar.gz"},{"channel":"p2p","source":"kit-mon2","first_seen":1437145232,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon2.json.tar.gz"},{"channel":"scrape","source":"blockchain.com","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/blockchain.com/orphans_blockchain.com.json"}]} +{"height":364341,"hash":"000000000000000012aac0664cd8b6cbc3ea485921a05f2c4340f928b0226d3c","header":"02000000cf955add9393b5e10d539356f171340697d226e98e6f680800000000000000003b46df0118463e54293ff11319cac5d609a6a3a6dbe614b773c49285896863a3298c9c558e4116186b69e33a","prev_hash":"000000000000000008686f8ee926d297063471f15693530de1b59393dd5a95cf","nTime":1436322857,"core_reject_reason":"bad-version","rule":"bip66_block_version_below_3","context":{"expected_nbits":"1816418e","coinbase_height":364341,"coinbase_scriptsig_hex":"03358f052cfabe6d6da8e7031652edd333c809b423e10227792e3dbcb7b173b1585dc1476ce72eb8000400000000000000062f503253482f","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":192332,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L18","child_block_hash":"2635fbea11ff1e0bf28467d868857cbd457169d30b8ca3dbfbc72a610807534b","child_block_time":1436322549,"child_header":"010104006db47708b4ec2f815af8bae59413f6f2b71eaac554d51bf6e43d4ee253466f91aacae1ed9c559a3b06bd42497a3defce8e78fddc5e70fe2c289606793854b343f58a9c55cb62031900000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"ixcoin","child_height":268098,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L41","child_block_hash":"dc902a09beeb9e10a1e4dd0c41e66a0a64f6849d059478be823b5d9ede985f97","child_block_time":1436322789,"child_header":"01010300f73a32bbd472836d36d5b5cdd3c3d1596733ce93819db1daa3b039d4e400fbbe3247a15e209469719d5914c6e023ff321ce9127626660712c8cd26473283d53ce58b9c557e8c7e1800000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":238279,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L65","child_block_hash":"fc6c87936193dde9d03334e9357fd0f6c161f9fb0addc80bb35e15f763ae9242","child_block_time":1436322802},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"ixcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"p2p","source":"kit-mon1","first_seen":1437215507,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon1.json.tar.gz"},{"channel":"p2p","source":"kit-mon2","first_seen":1437271117,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon2.json.tar.gz"}]} +{"height":367047,"hash":"00000000000000000f93ba8faf8bb018c7db642e30391748860cbfa5803a32a4","header":"0200000052621b40bc489705b02f2f02df486696ba5302610906100a000000000000000019dbb981ac5d96e8700dbf87a0dda31be5ad61dccca3dae1196915b4dbcd3d220fdab455150815188250fe62","prev_hash":"00000000000000000a100609610253ba966648df022f2fb0059748bc401b6252","nTime":1437915663,"core_reject_reason":"bad-version","rule":"bip66_block_version_below_3","context":{"expected_nbits":"18150815","coinbase_height":367047,"coinbase_scriptsig_hex":"03c79905534f434b25449607578bd762522cfabe6d6d8f433c640092b20a74c858f622235f3ef0a432b34b8d7f9a23ed781ec2c0b40120000000000000002f6d6d706f6f6c","pool":"mmpool","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"devcoin","child_height":194759,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L19","child_block_hash":"0a81670fb1c2c92e3e69bc6c43a28b38feb48e20034612a26bbdb7d2a3650d0b","child_block_time":1437915532,"child_header":"010104006b8bfb7f1d7cbd5b34eee74e70d26abf48ee5a86b230aa0e2c2b0c02fb9387dd7dd3e422e31702fefaa26b4e70ab9c578286d1edcfaee8a590366e527545da2a8cd9b45512d1021900000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"groupcoin","child_height":180938,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L24","child_block_hash":"a907e7dee1ada61662e332f887f8bfc8a0464f3f7fdb94c0856fd5b5e1584302","child_block_time":1437915602,"child_header":"010105001597e1749664b5f9d2cbc722676ba7544f00335f8ce35c3e5e4b74fc0ba8bf02901687ed35e52eb5b99e2afb7edb59cdd9ef27116ce2953a4f7c5d9d3094ebbdd2d9b455f44a021a00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"i0coin","child_height":1546541,"provenance":"https://drive.google.com/file/d/11-D1r5s8267YmOT1VaObrcmVoV8d_JAn/view?usp=sharing","child_block_hash":"5bf13bc80a9b265fe895a1347190ce38ee0688ff8f02849fbbf7138bb776f1f2","child_block_time":1437915587,"child_header":"010102002d9a0b4ae23de80a62b3f44015b50d63bd1d8e041a16fba7cd969b4c5dbe2ca211c69033dda8d64a25191f6194d5df44d280e7ac6a937c302ec1f7e7ba14ce48c3d9b4557ffb011a00000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":241087,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L66","child_block_hash":"53382d7cd5ce62d3220c550f7ccd36650bc2fcc20ef5404f38b69ae5ae856398","child_block_time":1437915611},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"unobtanium","child_height":637957,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L87","child_block_hash":"fe3a8719509cfee3450bb36102405e6f2c706de19590f500db4cfc32562c614f","child_block_time":1437915647,"child_header":"03017500a6ad998bf971bca3ae3823fa9d39d286764e5baaad1dfca460ce72d666ed5889b1c993be66cf4eb570f2e02a7fcb3a2e2e28a81df315bc56e00ad249a975432bffd9b455d952621900000000"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"devcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"groupcoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"i0coin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"unobtanium","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":380992,"hash":"0000000000000000084ee972bfe620224e6893448a9001d2b1f236ede0423779","header":"0300000092d98cb6018e9baa8dfe136fa81266dfa588c0ee23b26e030000000000000000af324cb995102e1d1c5e7d59459d5f651090881815f2a63f0eba667ce3db7538cf003156140f12182744ec68","prev_hash":"0000000000000000036eb223eec088a5df6612a86f13fe8daa9b8e01b68cd992","nTime":1446052047,"core_reject_reason":"time-too-old","rule":"time_below_mtp","context":{"expected_nbits":"18120f14","parent_mtp":1446068449,"coinbase_height":380992,"coinbase_scriptsig_hex":"0340d005e4b883e5bda9e7a59ee4bb99e9b1bcd50ac9b4c902bcd5e2bad45a05683fe7f021962425668f3d52fb85b887a7641d02000000f09f909f2f4249503130302f4d696e656420627920796e646c0000000000000000000000000000000000000000","pool":"yndl","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":255293,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L67","child_block_hash":"c4d8eda3b78a364d1376aa9ed5392b1f4eeb673f6d9fef3b9ede7f558bc50447","child_block_time":1446069661},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":383540,"hash":"000000000000000009c55c7e380b7600a2966de1b79230c74212d9c45a91a50b","header":"0300000067632629ccfb115468a3bf5de123daa6195d08fa07bc21070000000000000000596b9301095713baf9cacd3454ca28f6dce7549e7c475ed3779e197aa7d0e09efa3e475689b210188de55dcc","prev_hash":"00000000000000000721bc07fa085d19a6da23e15dbfa3685411fbcc29266367","nTime":1447509754,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"1810b289","coinbase_height":383539,"coinbase_scriptsig_hex":"0333da050e00456c69676975730056473ebf05fabe6d6dea750998570cd15be3f4d81146f617c7f8cfbb02e53cf5953aef025e55b48ae20100000000000000002f737332322f008102000090990500","pool":"Eligius","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":257852,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L68","child_block_hash":"ea750998570cd15be3f4d81146f617c7f8cfbb02e53cf5953aef025e55b48ae2","child_block_time":1447509676},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":389043,"hash":"00000000000000000306ea979ad487157d2950081413eb9d2dca82060f1b89b2","header":"030000009b8df38b440b4e93de66f1bc04aafd774d9b0f5eada3430900000000000000006e552de3422d394c0ef86c00bfd46e1b90ecc55f2a8c163ff9760d1850d6b782fc1374564fe60d18581bca4e","prev_hash":"00000000000000000943a3ad5e0f9b4d77fdaa04bcf166de934e0b448bf38d9b","nTime":1450447868,"core_reject_reason":"bad-version","rule":"bip65_block_version_below_4","context":{"expected_nbits":"180de64f","coinbase_height":389043,"coinbase_scriptsig_hex":"03b3ef05040314745608fabe6d6d20d6656f5ca5ac4408cbee6ff6d3235c6039015372788a3c0b0c39721502efd001000000000000004000000f873d00860d2f6e6f64655374726174756d2f","pool":"nodeStratum","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":263217,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L69","child_block_hash":"20d6656f5ca5ac4408cbee6ff6d3235c6039015372788a3c0b0c39721502efd0","child_block_time":1450447692},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"p2p","source":"kit-mon1","first_seen":1450447890,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon1.json.tar.gz"},{"channel":"p2p","source":"kit-mon2","first_seen":1450447889,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon2.json.tar.gz"}]} +{"height":402610,"hash":"000000000000000003a1ce220ae97419cc4bdb5d70b90189b8f8a06b0b37e3a2","header":"04000000d29de83f75a5660bdb41268113ef1641ef823386119b6e0200000000000000008d1db810ec599011afd5752e00d557a6875094e9436cf1fd9412e463f37cdf59a9a4e656a8f00618c2eac184","prev_hash":"0000000000000000026e9b11863382ef4116ef13812641db0b66a5753fe89dd2","nTime":1457956009,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"1806f0a8","coinbase_height":402611,"coinbase_scriptsig_hex":"03b3240637e4b883e5bda9e7a59ee4bb99e9b1bcdb8c127393c82df3adac41a9a3a6d30491ade6cab548308a174cc92165515c1f02000000f09f909f124d696e656420627920633633333436313039000000000000000000000000000000000000000000","pool":"c63346109","parent_kind":"stale"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":276713,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L70","child_block_hash":"229b2fa5af33af86559c830b86d4cc90830834e06612e43f0b0f8e8636d6f39a","child_block_time":1457955815,"child_header":"040101009eae642e432113e560f4bb4c8bda6e59fb9f79d1cd2486ba53909535bffff325e6c52c32ce27a17151ee2c7a64bdd3a441f6237ba4e39c7b62089d7db8885abce7a3e656e24b171800000000"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"}]} +{"height":422059,"hash":"00000000000000000254ed1e8143f0bcd3c3564db07e7c35631e999d53e81fa7","header":"0000002015b9a5a957588d43fdcbc9c8c8fb5b2d378b74bc54fc1e040000000000000000bb4bf58844f6bec746791e35d4f99e476ec7a2ab9a70b6172087ab8e4b1c0681d27c945769260518385ece24","prev_hash":"0000000000000000041efc54bc748b372d5bfbc8c8c9cbfd438d5857a9a5b915","nTime":1469349074,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"18052669","coinbase_height":422060,"coinbase_scriptsig_hex":"03ac7006162f5669614254432f48656c6c6f2c20576f726c64212f2cfabe6d6d66a8e99ddd64fdd53d2fcba9e0da13d660eb4f3af15c1cc9f4afd712b09729fb01000000000000000cd114e24c6b5af1af8c290400","pool":"ViaBTC","parent_kind":"stale"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":296773,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L71","child_block_hash":"66a8e99ddd64fdd53d2fcba9e0da13d660eb4f3af15c1cc9f4afd712b09729fb","child_block_time":1469348069,"child_header":"04010100498a5a053ae0b56d2397b69808899b1676cb8cbccca1242ee61249b42242bec388fe0e2260ff96162a9e53c8565ee4d286bd7bb4a045b194cf9a0f7f06bd9f3ae57894572fe20d1800000000"},{"channel":"merge_mining","source":"mergedmonitor","child_chain":"namecoin","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/mergedmonitor/mergedmonitor.json"},{"channel":"p2p","source":"kit-mon1","first_seen":1469348631,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon1.json.tar.gz"},{"channel":"p2p","source":"kit-mon2","first_seen":1469348631,"provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/kit/mon2.json.tar.gz"}]} +{"height":477115,"hash":"0000000000000000013ee4a86822d37a061732e04ee5f41fb77168f193363d1b","header":"12000020257adfb6e7e0b3cd645a9458c6fbc4362eff71878cae3301000000000000000047e7d6f16255b474b896c6bf5c7336c1b570b8de4f2367d126bda61e8007c6d41d217459dc5d0118b5a222ce","prev_hash":"00000000000000000133ae8c8771ff2e36c4fbc658945a64cdb3e0e7b6df7a25","nTime":1500782877,"core_reject_reason":"bad-txns-inputs-missingorspent","rule":"bad-txns-inputs-missingorspent","context":{"coinbase_height":477115,"coinbase_scriptsig_hex":"03bb47072cfabe6d6dab936343b3137ca4569b6c9ef7af36bce731965d82b1b9a221da07786260a5df01000000000000002f4e59412f","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":352422,"child_block_hash":"ab936343b3137ca4569b6c9ef7af36bce731965d82b1b9a221da07786260a5df","child_block_time":1500782788,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/child-identity/namecoin_child_identity.csv#L1390"},{"channel":"scrape","source":"chainquery.com","provenance":"https://github.com/NStifter/mergedmonitor/blob/54344d4e355f73eb94bef8d391e8fb6e4a9323a6/fork-analysis/chainquery.com/orphans_chainquery.com.json"}]} +{"height":543804,"hash":"0000000000000000000c958fe3563e7e3ecda8e35e6d6ecce4d5693cec1f1918","header":"000000a0e1f0be09a3ee109bc463656178dfcc9b5b3f4bdf857b12000000000000000000b61fd2f54e77727b941724900da0695433083c49a4c6a3374ce652f15e3ec92a5623b15b1f5a2717661d5ac5","prev_hash":"000000000000000000127b85df4b3f5b9bccdf78616563c49b10eea309bef0e1","nTime":1538335574,"core_reject_reason":"bad-version","rule":"bip65_block_version_below_4","context":{"expected_nbits":"17275a1f","coinbase_height":543804,"coinbase_scriptsig_hex":"033c4c08045623b15b622f4254432e434f4d2ffabe6d6dee6689d8fa713e1a935e1b03dd664008ac0a74b753d03c527f6d25800e82299a0100000000000000fc00cfe8cc4d000000000000","pool":"BTC.COM","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":419550,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L72","child_block_hash":"ee6689d8fa713e1a935e1b03dd664008ac0a74b753d03c527f6d25800e82299a","child_block_time":1538335419},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"rsk","child_height":789982,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L79","child_block_hash":"7e26d8a3de73a67b4bbe35bfd0763556504ef02ee5eb84e15c1c99024a6a0077","child_block_time":1538335566}]} +{"height":544024,"hash":"0000000000000000001ac59b46b44a9e525bc03a5cd2e138a8ae684445fa6ed8","header":"000000e083bcaf0ad9fb201f6f888ee014d8c1e8c317213cb5ba1e000000000000000000fc3d782759e6ade1a1b211bff767cd07d7f33dc0c21f82c8d62359bc3aa2b31ac0fab25b1f5a271719a0fc34","prev_hash":"0000000000000000001ebab53c2117c3e8c1d814e08e886f1f20fbd90aafbc83","nTime":1538456256,"core_reject_reason":"bad-version","rule":"bip65_block_version_below_4","context":{"expected_nbits":"17275a1f","coinbase_height":544024,"coinbase_scriptsig_hex":"03184d0804c9fab25b612f4254432e434f4d2ffabe6d6dcea0fda9be365f0d78b66072ae5cf48ed7cb6338df96d4a951f49bcc9641a6710100000000000000fb0136c12081000000000000","pool":"BTC.COM","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":419759,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L74","child_block_hash":"cea0fda9be365f0d78b66072ae5cf48ed7cb6338df96d4a951f49bcc9641a671","child_block_time":1538455676},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"rsk","child_height":793596,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L81","child_block_hash":"9820cd4d8c71156858576c8fb33c1d26acf4a35f6759be6992d20aa34380854c","child_block_time":1538456260}]} +{"height":544024,"hash":"0000000000000000001ffb5988298bfc9f528f9a47e6062ebe8a01177af25d21","header":"000000a083bcaf0ad9fb201f6f888ee014d8c1e8c317213cb5ba1e0000000000000000002ff9d73a3acc053757fc4f126dd404601687113d789ab1706af2ff45e44324d4a8eeb25b1f5a2717a2dcff2c","prev_hash":"0000000000000000001ebab53c2117c3e8c1d814e08e886f1f20fbd90aafbc83","nTime":1538453160,"core_reject_reason":"bad-version","rule":"bip65_block_version_below_4","context":{"expected_nbits":"17275a1f","coinbase_height":544024,"coinbase_scriptsig_hex":"03184d0804a9eeb25b622f4254432e434f4d2ffabe6d6d00b4b5e6ade353899dc765c9ea4101e089f70877b7d314d29fc9b7d0654fcf020100000000000000fb006d12d345000000000000","pool":"BTC.COM","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":419757,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L73","child_block_hash":"00b4b5e6ade353899dc765c9ea4101e089f70877b7d314d29fc9b7d0654fcf02","child_block_time":1538452868},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"rsk","child_height":793505,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L80","child_block_hash":"10c113540401f22983c36bfa6f83165c5b0986589a0653cd4ba41cec337dfac0","child_block_time":1538453154}]} +{"height":544600,"hash":"000000000000000000188a6aecb603cb6a068ad236f925255a491124b5c5dc8a","header":"000000e0ac98ac0f58c139e1dca0a46d8fde38b1a734c61669d30a000000000000000000c5678277c2623de52e1b23786a24570ceea239df26ec3ea92bda7e865457ed062c8bb85b91c12517b20cd911","prev_hash":"0000000000000000000ad36916c634a7b138de8f6da4a0dce139c1580fac98ac","nTime":1538820908,"core_reject_reason":"bad-version","rule":"bip65_block_version_below_4","context":{"expected_nbits":"1725c191","coinbase_height":544600,"coinbase_scriptsig_hex":"03584f08042c8bb85b622f4254432e434f4d2ffabe6d6d88922b0299a396056945229bf094718c1388b6df2c4560845fa027e8942ca65d0100000000000000fd0069592843000000000000","pool":"BTC.COM","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":420338,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L75","child_block_hash":"88922b0299a396056945229bf094718c1388b6df2c4560845fa027e8942ca65d","child_block_time":1538820381},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"rsk","child_height":804553,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L82","child_block_hash":"9cb1fa3f08b969d76fabe6971c880416e0650bd9decdda956bb1101b036a12f3","child_block_time":1538820886}]} +{"height":649674,"hash":"00000000000000000008c80c1f8c101f8aa1fabd59d63ab1350bd1d5dba425e6","header":"00000020bf0f92c82f18ef43fa86c8037669db3d095d4375409d07000000000000000000b47cdd7f24671f05b94720902226f18383e0e2cb4dcaefbb40dbb138a70770009db86b5faa920e17b4ed6590","prev_hash":"000000000000000000079d4075435d093ddb697603c886fa43ef182fc8920fbf","nTime":1600895133,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_missing","context":{"expected_nbits":"170e92aa","coinbase_scriptsig_hex":"fecae9090048617468185a489434ae20d115d61694f7ca019160c1be165bace94440d705171e1b871bb876a249290000000000","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"hathor","child_height":756587,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L25","child_block_hash":"00000000000000000008c80c1f8c101f8aa1fabd59d63ab1350bd1d5dba425e6","child_block_time":1600895133}]} +{"height":717696,"hash":"0000000000000000000045c5040bf46b4cd6c6f8f4004c149cd602e4e356e71c","header":"0000ff3f9acaa5d26d392ace656c2428c991b0a3d3d773845a1300000000000000000000cd79ee4e64b40a2bbf130ca47d2d3cb0315d26cb96425bcb7dd82f375e8c6e739743d961ab980b17262f8aa5","prev_hash":"00000000000000000000135a8473d7d3a3b091c928246c65ce2a396dd2a5ca9a","nTime":1641628567,"core_reject_reason":"bad-diffbits","rule":"nbits_retarget_not_applied","context":{"expected_nbits":"170b8c8b","coinbase_height":717696,"coinbase_scriptsig_hex":"0380f30a192f5669614254432f4d696e656420627920657373696265742f2cfabe6d6dc0edbc53e6583117e3fb0c174156ff34a95f1a1093bb03192bdd8b47f896cb9f10000000000000001071ffd417d8ab2bd883332eb005000000","pool":"ViaBTC","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-monitor","child_chain":"namecoin","child_height":593434,"child_block_hash":"d22cf8a7666d92e8a254aeba4b92def80e52aa30c62293ae05d79c967b086d7f","child_block_time":1641627165,"provenance":"https://mmm.deadmanoz.xyz/api/v1/block/0000000000000000000045c5040bf46b4cd6c6f8f4004c149cd602e4e356e71c"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"emercoin","child_height":518861,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L22","child_block_hash":"4e16eeb9918708624ad75d072e87d609d983e980c737a0af5b421c3f4f7b3950","child_block_time":1641627605,"child_header":"08019a027023fa433164b011f9defc077112043feaddb6bc98a92c6314a4ca6667c3564edc7ab7b15018ebdceb93bcbf593da233ec220dd9a0523e4f055f5e0624ba33ecd53fd961b66e0e1700000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"syscoin","child_height":1336057,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L84","child_block_hash":"489b69af1f76fc07eff93cc55833326b42e19a9c8568d7353512ee1441a32a25","child_block_time":1641627642}]} +{"height":783426,"hash":"00000000000000000002ec935e245f8ae70fc68cc828f05bf4cfa002668599e4","header":"0000692bb7ccd9ee0d58f8638057eee7a04cc2329f7a89284124010000000000000000004865405dc5ca751cc6ef35ab36264563f64a3061668a0f9a671aefa05012cac223de27643e02061776764640","prev_hash":"00000000000000000001244128897a9f32c24ca0e7ee578063f8580deed9ccb7","nTime":1680334371,"core_reject_reason":"bad-blk-sigops","rule":"bad-blk-sigops","context":{"coinbase_height":783426,"coinbase_scriptsig_hex":"0342f40b2cfabe6d6d76eebeccd7ca22e72d1f7c18b9a3ae8c3f93c04072e77b94dfcf0f0dd560be4410000000f09f909f092f4632506f6f6c2f66000000000000000000000000000000000000000000000000000000000000000000000005007c000000","pool":"F2Pool","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"elastos","child_height":1395837,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/child-identity/elastos_child_identity.csv#L130","child_block_hash":"be374a919b4c352b5ca7ab11937a68cc615fc590573da33bfd32f7cbf5d8d98c","child_block_time":1680334370},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":658973,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/child-identity/namecoin_child_identity.csv#L1630","child_block_hash":"f6a77e2178f078dd1d305a6f64dde99070ac41be141460fd3b1f949cfd988917","child_block_time":1680334314,"child_header":"04010100a03332a4347f65d54933d041a7d892201083cd47acc6af603745da1dd9bfca792dbb347476d12b011a281314cdaa27a78faae760b94b31dccacf142ed920f1f7eadd276420040a1700000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"rsk","child_height":5178853,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/child-identity/rsk_child_identity.csv#L187","child_block_hash":"ba25dfd9a60d1bf4d3548929a774c77ee94c8f2fdb344620722acf3e3b1638f8","child_block_time":1680334360},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"syscoin","child_height":1590668,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/child-identity/syscoin_child_identity.csv#L46","child_block_hash":"8c83c0e7b6879052aff6a1845d468766877dae4f052308c962343cc776c16c4b","child_block_time":1680334281},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"xaya","child_height":4720941,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/validated-stales/xaya_validated_stales.csv#L32","child_block_hash":"8eb4d4f2930ca73e067cee8dedf1687c3a877885d329d71a7b1aa05111bd1e8a","child_block_time":1680334331,"child_header":"0000002055bd00186f9c269679bb0685a1217a6e2c7d9bd019517217b133da00c700eece7c31850e277a993f9368eb6eceba5cd5dfff32e4f4e2fca719bb22915e15345efbdd27640000000000000000"},{"channel":"p2p","source":"b10c","provenance":"https://b10c.me/observations/11-invalid-blocks-783426-and-784121/"}]} +{"height":784121,"hash":"000000000000000000046a2698233ed93bb5e74ba7d2146a68ddb0c2504c980d","header":"000031206c9db21f1c594c7620ee28965c84e39641d8823004ef040000000000000000005a5bff1e6abffdebee80864effcd0f3d9c57756095f3238a2cb888ab162ff93bd0182e643e020617016cea5a","prev_hash":"00000000000000000004ef043082d84196e3845c9628ee20764c591c1fb29d6c","nTime":1680742608,"core_reject_reason":"bad-blk-sigops","rule":"bad-blk-sigops","context":{"coinbase_height":784121,"coinbase_scriptsig_hex":"03f9f60b2cfabe6d6df25b386d041b6a6ecf202e73afd2bf8d3422cb2f6e9c9975fdc4c37a958136fd10000000f09f909f092f4632506f6f6c2f730000000000000000000000000000000000000000000000000000000000000000000000050045010000","pool":"F2Pool","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"elastos","child_height":1399199,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/child-identity/elastos_child_identity.csv#L131","child_block_hash":"300bbce2511b40acba55597aad4eae88cc4a0d230d67d5db1c941696d3b9e7e9","child_block_time":1680742605},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":659651,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/child-identity/namecoin_child_identity.csv#L1631","child_block_hash":"ac896d49ff6133d6f9a1146bc8f97a4152c1b73d21165a022c661c06adc563c7","child_block_time":1680742574,"child_header":"0401010048dc45b1088cf8c5e2c23a474c44b0d9f87c2a6d8353c4263ca08174893d619ff3e91854ef78e1bf367bd4ab6732d58c1000299c97bbeefa9e46a3dcfa67f32eae182e6488ac091700000000"},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"rsk","child_height":5191801,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/child-identity/rsk_child_identity.csv#L189","child_block_hash":"b7af3aad1f7702bf97619fa3c783659c5d40ec2e7d00952d933f17bf86718aa6","child_block_time":1680742594},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"syscoin","child_height":1593384,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/child-identity/syscoin_child_identity.csv#L48","child_block_hash":"a35aedab8aabac7e2a37929a231f4cbbc1eea2b64671ba78b78672f78dce7338","child_block_time":1680742579},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"xaya","child_height":4733918,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/validated-stales/xaya_validated_stales.csv#L33","child_block_hash":"7309841ba47b1e771535cca0395549eac6ca434bd86a98aa3d6d39ad34e835a7","child_block_time":1680742579,"child_header":"00000020daf03a26db1265c074768e7ce894c86be28717a2bb59c999ddab581d2d761f4edb49bc80e6dc3156def8bed2e2e6e2f8ca1034fac07f0a7c6c96709b75692663b3182e640000000000000000"},{"channel":"p2p","source":"b10c","provenance":"https://b10c.me/observations/11-invalid-blocks-783426-and-784121/"}]} +{"height":789038,"hash":"0000000000000000000291349d44e756df07ce08d848df0ca0bbd9884af393ed","header":"00001420a9b33b3d10ad624252280e9661a51561e3385eab693403000000000000000000c08b8b2acb801db22d78da722a2b826723c9c0485301189db92310ea90e2b649aa3b5b6401dd0517366b9e43","prev_hash":"000000000000000000033469ab5e38e36115a561960e28524262ad103d3bb3a9","nTime":1683700650,"core_reject_reason":"bad-cb-height","rule":"bip34_coinbase_height_mismatch","context":{"expected_nbits":"1705dd01","coinbase_height":789039,"coinbase_scriptsig_hex":"032f0a0c1b4d696e656420627920416e74506f6f6c383733e2000002b5eac7d7fabe6d6df30ef030508734cec49b1d7ddbe98a52a2f7ad5986eac10cd313f0c6dbb46d6d0200000000000000000024c9610e000000000000","pool":"AntPool","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":664459,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L76","child_block_hash":"4ca8a67a1dce81a5a4e83b308104221603394626b4aee59f6791e01a3dca636a","child_block_time":1683700617},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"rsk","child_height":5287383,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L83","child_block_hash":"560564407a25f9dec7c67f563ef13a493b9f6513a57836e734d713c7bf6f5fa2","child_block_time":1683700646}]} +{"height":809478,"hash":"000000000000000000006840568a01091022093a176d12a1e8e5e261e4f11853","header":"00803e2a03190f85de29847f84ce19c659c71efbcd0ef1e7975e0300000000000000000066dfc5aec3a3d9440cc5c7d8d2f48da60d0b49bec84dfe927865c03f6052daeaea4913657fed041740428d60","prev_hash":"000000000000000000035e97e7f10ecdfb1ec759c619ce847f8429de850f1903","nTime":1695762922,"core_reject_reason":"bad-txns-inputs-missingorspent","rule":"bad-txns-inputs-missingorspent","context":{"coinbase_height":809478,"coinbase_scriptsig_hex":"03065a0c04ed4913652f4d41524120506f6f6c202876303932363233292f76649b3c094f135bf4b83108c14ea85f127ebfce0f004e020000ffffffff","pool":"MARA Pool","parent_kind":"canonical"},"observations":[{"channel":"p2p","source":"b10c","provenance":"https://b10c.me/observations/07-invalid-block-809478/"}]} +{"height":946213,"hash":"00000000000000000000c3d95a4bdc068dfe0c6d1e7ad13045c6f570e58d9ed7","header":"00a0032bb223f1aad55892df75d0ff4712f0543959c5065ab89d000000000000000000005eba715327fc82c765fa651bd6226c4b4a6a846cd60197bcd76d47ada0611cfce335df696913021725806e70","prev_hash":"000000000000000000009db85a06c5593954f01247ffd075df9258d5aaf123b2","nTime":1776236003,"core_reject_reason":"time-too-old","rule":"time_below_mtp","context":{"expected_nbits":"17021369","parent_mtp":1776870621,"coinbase_height":946213,"coinbase_scriptsig_hex":"0325700e2cfabe6d6d07a206acc4d465037a85ceac8a1903f27526149e57a46fc1edbb6a7c67320d4f10000000f09f909f092f4632506f6f6c2f670000000000000000000000000000000000000000000000000000000000000000000000050095000000","pool":"F2Pool","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"elastos","child_height":2196610,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L20","child_block_hash":"13cd51dbc539ec740f803014f6e7ec6c6b086810c6b3ca5ce79a88fbb67446c2","child_block_time":1776878612},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":821553,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L77","child_block_hash":"12f2953ccece032e95db4c044364ad3f23943a707a04a8ad6dbf80fcd01469d0","child_block_time":1776876260},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"syscoin","child_height":2226227,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L85","child_block_hash":"f7bd05a66ff6f0ad6a72e40ca17802affc81be32b52d0974bf86fc06368ae22a","child_block_time":1776878264}]} +{"height":957780,"hash":"0000000000000000000198e12592edbe83c84a78f75b3f8d67a3fe2075ef2ffb","header":"00000020818872136c490609d2eeb2faeaf4f0f05f07838e9bb301000000000000000000fcff7aa8f453695c8295551e7aad10faf56fc5f5e7eda4f47933db2d80adb252e7bd416a9d360217f479b1bf","prev_hash":"00000000000000000001b39b8e83075ff0f0f4eafab2eed20906496c13728881","nTime":1782693351,"core_reject_reason":"time-too-old","rule":"time_below_mtp","context":{"expected_nbits":"1702369d","parent_mtp":1783900280,"coinbase_height":957780,"coinbase_scriptsig_hex":"03549d0e2cfabe6d6db72b2e8a573b09f5d46aad91f9214fabcdcccd69a9b172992099d95e393da9cc10000000f09f909f092f4632506f6f6c2f6700000000000000000000000000000000000000000000000000000000000000000000000500580a0200","pool":"F2Pool","parent_kind":"canonical"},"observations":[{"channel":"merge_mining","source":"merge-mining-research","child_chain":"elastos","child_height":2255118,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L21","child_block_hash":"6e843965ff30c6315314618980bd4fb8fe5de493d0512caac26cfd0cdc59b7cc","child_block_time":1783902849},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"fractal","child_height":1936022,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L23","child_block_hash":"ce9ba3d1f11ccfb630656b5f6b3f997dbc548deb8b4c3ab010bd22fbefafba35","child_block_time":1783902853},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"namecoin","child_height":833329,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L78","child_block_hash":"07fcf2c9e2431e1a14bc8a251149d33140ffce2aa0665bc8236c7243a8e2c5ae","child_block_time":1783902407},{"channel":"merge_mining","source":"merge-mining-research","child_chain":"syscoin","child_height":2272433,"provenance":"https://github.com/deadmanoz/merge-mining-research/blob/f543b1f23c57be6840c7a2a44a59306b5d0180f7/data/error-blocks/error_block_observations.csv#L86","child_block_hash":"d249d9e1c3b54e0d693c464ca43698b96be3d3421b847398592fcd0cea6f2618","child_block_time":1783902744}]} diff --git a/docs/notes.md b/docs/notes.md new file mode 100644 index 0000000..c047d2d --- /dev/null +++ b/docs/notes.md @@ -0,0 +1,43 @@ +# Notes + +Background that does not fit the [schema](schema.md) or the README. +Deeper per-block history is documented elsewhere; see the observation `provenance` URLs in [`data/invalid-blocks.jsonl`](../data/invalid-blocks.jsonl). + +## Replaying full blocks + +A `.bin` can be replayed with `bitcoin-cli submitblock`, but what comes back depends on where the violation is caught. +74638 fails the context-free `CheckBlock` checks before anything is stored, so every replay returns `bad-txns-vout-toolarge` on any node. +Its header alone is valid, though: `submitheader` accepts it (noted in ), since every header-level check passes and the violation lives entirely in the body. +The transaction-ordering and 2023 sigops blocks fail in `ConnectBlock`, which never runs for a deep side-chain block: a node seeing them fresh returns `inconclusive` and stores the block as a `valid-headers` chain tip, a node that already stores them returns `duplicate`, and only a node that attempted the connect at their original tip and marked them failed returns `duplicate-invalid` (the result reported in ). + +## Incident notes + +### 74638 - value overflow (2010) + +`bad-txns-vout-toolarge` is the 2010 overflow incident ([CVE-2010-5139](https://en.bitcoin.it/wiki/Value_overflow_incident)). +A transaction created two outputs of about 92 billion BTC each. +The outputs were non-negative, so they passed the then-current per-output check; their sum overflowed a signed 64-bit integer and wrapped negative, so the input-versus-output check passed too. +Bitcoin 0.3.10 added a money-range check (there is no BIP). +Core now rejects any single output above `MAX_MONEY` with this string. + +### 783426 and 784121 - F2Pool sigops (2023) + +Both blocks exceed the sigop limit: accurate sigop cost 80003 against the 80000 maximum, counted in `ConnectBlock`. +The context-free legacy count is under the limit, which is why replay cannot reproduce `bad-blk-sigops`. +Documented in [b10c observation 11](https://b10c.me/observations/11-invalid-blocks-783426-and-784121/). +CI reproduces the 80003 cost for each block using previous transactions authenticated against its inputs. +Block 783426 has 74520 legacy cost, 160 P2SH cost and 5323 witness cost; block 784121 has 72204, 908 and 6891 respectively. +The previous transactions are fetched from public APIs and cached; the block bodies and their witness commitments supply the remaining evidence. + +### 477115 - transaction ordering (2017) + +Three of the block's 255 transactions spend an output of a transaction that appears later in the same block. +As with 809478, `ConnectBlock` encounters these inputs before their outputs are available: `bad-txns-inputs-missingorspent`. +This violation is re-derivable from the [preserved full block](../blocks/477115-0000000000000000013ee4a86822d37a061732e04ee5f41fb77168f193363d1b.bin). + +### 809478 - MARA transaction ordering (2023) + +145 of the block's 2528 transactions spend an output of a transaction that appears later in the same block. +`ConnectBlock` processes transactions in order, so the first such input fails the coins lookup: `bad-txns-inputs-missingorspent`. +This violation is re-derivable from the `.bin` alone. +Documented in [b10c observation 07](https://b10c.me/observations/07-invalid-block-809478/). diff --git a/docs/schema.md b/docs/schema.md new file mode 100644 index 0000000..562e622 --- /dev/null +++ b/docs/schema.md @@ -0,0 +1,180 @@ +# Schema + +`data/invalid-blocks.jsonl` contains one JSON object per line. +The key is the hash of the 80-byte Bitcoin header. +Height is `prev + 1`, not a unique key: different blocks at the same height remain separate records. + +A block may enter the dataset only if its header meets its encoded PoW target and its named consensus failure has the evidence required below. +Header/context rules use the supplied header and context. +Body rules require a complete block; sigops additionally requires previous transactions fetched from public APIs or verified cache entries. +Observations document acquisition and incident history, but an explorer label or reported reject string cannot substitute for the evidence check. + +JSONL keeps each block's identity, optional context and repeated observations together. +Use UTF-8, LF line endings, a final newline and records sorted by `(height, hash)`. +Numeric fields are JSON integers. +Omit unknown or inapplicable optional fields instead of writing `null` or empty strings. +`context` and `observations` may be omitted when absent. + +Hex strings are lowercase without `0x`. +Bitcoin hashes use RPC/display byte order with leading zeros; `header` is the 160-character wire serialization. +Full blocks, when available, are `blocks/{height}-{hash}.bin`. + +## Required fields + +| Field | Type | Meaning | +| --- | --- | --- | +| `height` | integer | Positive Bitcoin height, derived from the parent, at most 2147483647. | +| `hash` | string | Header hash, the unique key. | +| `header` | string | 80-byte Bitcoin header in hex. | +| `prev_hash` | string | Parent hash, decoded from `header`. | +| `nTime` | integer | Header timestamp in Unix seconds, decoded from `header`. | +| `core_reject_reason` | string | Core reject-string family, required to match the rule table below. Core may format `bad-version(0x...)`; store `bad-version`. | +| `rule` | string | One of the registered consensus rules below, preserving distinctions such as BIP34 rollout stages. Unknown rules are rejected. | + +## Optional `context` object + +These fields describe the Bitcoin block, not an individual sighting. +A field required by the named rule must be present. +Context is shared across observations; adding another witness does not duplicate the block's validation context. + +| Field | Type | Meaning | +| --- | --- | --- | +| `expected_nbits` | string | Canonical compact target as eight hex characters. Required for `nbits_retarget_not_applied`. | +| `parent_mtp` | integer | Parent median-time-past, the median of eleven block timestamps, in Unix seconds. Required for `time_below_mtp`. | +| `coinbase_height` | integer | Height decoded from the BIP34 scriptSig prefix. Required for a BIP34 height mismatch. | +| `coinbase_scriptsig_hex` | string | Coinbase input scriptSig. Required for BIP34 failures and `coinbase_scriptsig_length_above_100`. | +| `pool` | string | Pool identified from the coinbase tag, when known. | +| `parent_kind` | string | `canonical`, `stale`, or `invalid`. `invalid` means the parent is in this dataset. | + +## Optional `observations` array + +Each object records one witness or acquisition source. +Preserve multiple child blocks on the same chain and independent observers of the same Bitcoin block. +Exact duplicate objects are rejected; repeated child-chain names are allowed. + +Observation counts count provenance records, not necessarily independent physical sightings. +An archive may identify a witnessing chain without a child height or hash; retain that evidence without inventing a child identity. +Such a record may overlap a more detailed witness published by another source. + +| Field | Type | Required | Meaning | +| --- | --- | --- | --- | +| `channel` | string | yes | `merge_mining`, `p2p`, or `scrape`, as defined below. | +| `source` | string | yes | Recorder, provider or evidence catalogue, such as `b10c`, `merge-mining-research`, or `blockchain.com`. | +| `provenance` | string | yes | HTTP(S) URL a reviewer can open to inspect the evidence. Prefer a commit-pinned archive. | +| `child_chain` | string | for `merge_mining` | Merge-mined child chain. | +| `child_height` | integer | no | Height of the witnessing child block. | +| `child_block_hash` | string | no | Child block hash in that chain's native RPC/display order, 64 hex characters. | +| `child_block_time` | integer | no | Timestamp encoded in the child block, in Unix seconds. This is not a receipt time. | +| `child_header` | string | no | 80-byte serialized child header in hex, only for chains with that header format. | +| `first_seen` | integer | no | Actual observation/receipt time in Unix seconds, when recorded. Do not substitute a Bitcoin or child block timestamp. | + +`merge_mining` means the Bitcoin parent is evidenced by a child-chain commitment. +This includes AuxPoW and other merge-mining mechanisms, such as RSK; acquiring that evidence from an archive does not change its channel. +`p2p` means a recorder received the Bitcoin block/header from the Bitcoin network, including compact-block relay. +`scrape` means recovery from a website, HTTP API or their archived output, where direct Bitcoin P2P reception is not established. +It describes acquisition, not validity or mining origin. +`source` identifies who supplied the record; `provenance` identifies the inspectable evidence. + +Child-chain fields are only allowed for `merge_mining`. +Child header hashing and timestamp layouts differ across chains; the generic validator checks the header's byte encoding, not its chain-specific semantics. + +## Rules and Core reject strings + +Core functions live in [bitcoin/bitcoin](https://github.com/bitcoin/bitcoin): + +- [src/validation.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/validation.cpp): `ConnectBlock`, `ContextualCheckBlock`, `ContextualCheckBlockHeader` +- [src/consensus/tx_check.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/consensus/tx_check.cpp): `CheckTransaction` +- [src/consensus/tx_verify.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/consensus/tx_verify.cpp): `CheckTxInputs`, `GetTransactionSigOpCost` +- [src/script/script.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/script/script.cpp): `GetSigOpCount` +- [src/script/interpreter.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/script/interpreter.cpp): `CountWitnessSigOps` + +| `rule` | `core_reject_reason` | Typical Core check | +| --- | --- | --- | +| `bad-txns-vout-toolarge` | `bad-txns-vout-toolarge` | `CheckTransaction` | +| `bad-blk-sigops` | `bad-blk-sigops` | `ConnectBlock` | +| `bad-txns-inputs-missingorspent` | `bad-txns-inputs-missingorspent` | `ConnectBlock` via `CheckTxInputs` | +| `bip34_v2_coinbase_height_mismatch` | `bad-cb-height` | `ContextualCheckBlock` | +| `bip34_coinbase_height_mismatch` | `bad-cb-height` | `ContextualCheckBlock` | +| `bip34_coinbase_height_missing` | `bad-cb-height` | `ContextualCheckBlock` | +| `bip66_block_version_below_3` | `bad-version` | `ContextualCheckBlockHeader` | +| `bip65_block_version_below_4` | `bad-version` | `ContextualCheckBlockHeader` | +| `coinbase_scriptsig_length_above_100` | `bad-cb-length` | `CheckTransaction` | +| `time_below_mtp` | `time-too-old` | `ContextualCheckBlockHeader` | +| `nbits_retarget_not_applied` | `bad-diffbits` | `ContextualCheckBlockHeader` | + +When multiple version rules apply, use the most recently activated rule. + +`bad-cb-height` covers both BIP34 stages. +Records at or above full activation, height 227931, use `bip34_coinbase_height_mismatch` or `bip34_coinbase_height_missing`; current Core still enforces that rule. +Earlier `bip34_v2_coinbase_height_mismatch` records belong to the rollout phase, when the rule applied only to version-2 blocks. +Their rejection must be checked under the rules nodes of that era ran. + +## Evidence enforced by CI + +`ci/sanity-check.py` registers each rule's reject string, required context and evidence path in `RULES`. +A new rule requires a registry entry, an evidence check, regression tests and an update to this document. +A provenance URL cannot bypass these requirements. + +| Rule | Required evidence and check | +| --- | --- | +| `bad-txns-vout-toolarge` | A complete block whose transactions contain an output above 21000000 BTC. | +| `bad-txns-inputs-missingorspent` | A complete block containing a spend of an existing output of a later transaction in that block. Other missing/spent-input cases require an additional evidence checker before admission. | +| `bad-blk-sigops` | A complete block at mainnet height 481824 or later, authenticated previous transactions for every external input, and calculated BIP16/BIP141 sigop cost above 80000. | +| `bip34_v2_coinbase_height_mismatch` | Both coinbase context fields, decoded height matching the scriptSig, and a scriptSig that lacks the exact expected BIP34 prefix. Header version must be at least 2 and height below 227931. Applicability of the historical rolling-version threshold still requires review. | +| `bip34_coinbase_height_mismatch` | Both coinbase context fields, decoded height matching the scriptSig, and a scriptSig that lacks the exact expected BIP34 prefix, at height 227931 or later. A non-minimal encoding of the right number also fails the prefix check. | +| `bip34_coinbase_height_missing` | Coinbase scriptSig with no decodable height prefix, at height 227931 or later. | +| `bip66_block_version_below_3` | Signed header version below 3 at height 363725 or later. | +| `bip65_block_version_below_4` | Signed header version below 4 at height 388381 or later. | +| `coinbase_scriptsig_length_above_100` | Supplied coinbase scriptSig exceeds 100 bytes. | +| `time_below_mtp` | Header timestamp is less than or equal to supplied `parent_mtp`. Equality also fails Core's check. | +| `nbits_retarget_not_applied` | Height is a multiple of 2016; supplied `expected_nbits` encodes a valid target and differs from the header's nBits. | + +Every available `.bin` must parse completely, match the dataset header and reproduce its transaction merkle root. +Parsing uses `python-bitcoinlib` without its general consensus-validity checks, because these blocks deliberately violate consensus. Reserializing must reproduce the input bytes exactly; normalized encodings and trailing data are rejected. +Duplicate transaction IDs are rejected by this evidence reader. +Where context includes a coinbase scriptSig, it must match the body's coinbase. +At or after mainnet SegWit activation, witness data must match the coinbase witness commitment. +`ci/block_evidence.py` uses the library's block methods to locate the witness commitment and calculate merkle roots, then applies the evidence checks and overflow/forward-spend predicates. + +The validator also checks JSONL structure, field types, decoded Bitcoin header identity, compact target and PoW, ordering, uniqueness and observation fields. +Locally checked predicates establish consistency with the supplied context. +Review must still establish the block height, parent MTP, expected difficulty, historical activation state and the connection between an extracted coinbase script and its header when no complete body is available. +The retarget check does not reconstruct the previous difficulty or prove that it was reused. +CI does not execute scripts, validate child-chain commitments, reconstruct historical chain state or fetch observation provenance. +It verifies the named failures, not every consensus rule or the exact first rejection a historical node would return. +Incident background is in [notes.md](notes.md). + +## Sigops evidence and public APIs + +`ci/prevouts.py` resolves the previous transactions named by inputs in a sigops block. +Transactions earlier in the same block are resolved from the body. +External transactions are fetched as raw hex from Esplora-compatible endpoints, defaulting to `mempool.space/api` with `blockstream.info/api` as a fallback. +Use `--fetch-prevouts` to permit downloads and repeat `--api-url` to supply other endpoint bases. +Requests have timeouts, bounded retries and two download workers. +Download failures fail validation explicitly. + +Before accepting a response, CI parses the whole transaction and verifies its txid against the spending input. +It caches stripped transaction bytes under `.cache/prevouts/{txid}.bin`; witness data from previous transactions is unnecessary for authenticating their outputs. +Every cache hit undergoes the same identity check. +A corrupt cache entry fails instead of being trusted or silently replaced. +GitHub Actions caches previous transactions by the contents of the block files, reusing older caches to reduce downloads when blocks are added. +Only successful non-PR runs on the default branch save an archive, and only when no exact cache exists for that block set. +Without `--fetch-prevouts`, all required entries must already be cached; missing evidence is an error. +Cache contents are not committed to the dataset. + +The workflow also runs daily at 03:23 UTC on the default branch, revalidating the cached evidence and fetching any missing entries. +Pull requests can restore this default-branch cache, but do not upload cache archives, avoiding separate archives for unmerged changes. +The schedule takes effect once the workflow is merged into the default branch; `workflow_dispatch` allows a manual run. +This keeps the cache in use, but does not make it permanent storage: GitHub's default policy [evicts caches unused for seven days and can evict entries under storage pressure](https://docs.github.com/en/actions/reference/workflows-and-actions/dependency-caching#usage-limits-and-eviction-policy). +GitHub also [disables public-repository schedules after 60 days without repository activity](https://docs.github.com/en/actions/how-tos/manage-workflow-runs/disable-and-enable-workflows). +Maintainers must re-enable a disabled schedule; after eviction, validation downloads and authenticates the missing transactions again. +Long-term preservation independent of public API availability requires a separate durable archive. + +Script classification and push decoding use `python-bitcoinlib`. A small local sigop counter remains because version 0.12.2's accurate-multisig helper raises an exception and its malformed-push handling does not preserve the accumulated count. +`ci/block_evidence.py` calculates the legacy cost (input and output sigops multiplied by four), additional P2SH cost (accurate redeem-script count multiplied by four), and version-0 witness cost. +Taproot has a separate validation budget and adds no cost to this block-wide counter. +The block's witness commitment is verified before counting witness scripts, so changing a witness script cannot manufacture evidence while leaving the transaction merkle root unchanged. + +The previous-transaction txid authenticates its output scripts, but does not prove that an output was unspent at the candidate's parent or that a signature is valid. +Those are separate consensus checks. +This calculation establishes the excessive sigop cost without reconstructing a historical UTXO set or depending on an explorer's rejection label. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a910876 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +python-bitcoinlib==0.12.2