mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-30 09:30:00 -07:00
162 lines
5.5 KiB
Python
162 lines
5.5 KiB
Python
"""
|
|
Transaction endpoint compatibility tests — parametrized across blockchain eras.
|
|
|
|
Endpoints covered:
|
|
GET /api/tx/{txid}
|
|
GET /api/tx/{txid}/hex text/plain
|
|
GET /api/tx/{txid}/raw application/octet-stream
|
|
GET /api/tx/{txid}/status
|
|
GET /api/tx/{txid}/merkle-proof
|
|
GET /api/tx/{txid}/merkleblock-proof text/plain
|
|
GET /api/tx/{txid}/outspend/{vout}
|
|
GET /api/tx/{txid}/outspends
|
|
GET /api/v1/cpfp/{txid}
|
|
GET /api/v1/transaction-times
|
|
"""
|
|
|
|
import pytest
|
|
|
|
from conftest import show, assert_same_structure, assert_same_values
|
|
|
|
|
|
@pytest.fixture(params=range(8), ids=[
|
|
"h100", "h100k", "h400k", "h630k", "h800k", "recent1k", "recent100", "recent10",
|
|
])
|
|
def block(request, live):
|
|
i = request.param
|
|
if i >= len(live.blocks):
|
|
pytest.skip("block not discovered")
|
|
return live.blocks[i]
|
|
|
|
|
|
# ── /api/tx/{txid} ───────────────────────────────────────────────────
|
|
|
|
|
|
def test_tx_by_id(brk, mempool, block):
|
|
"""Full transaction data must match for a confirmed tx."""
|
|
path = f"/api/tx/{block.txid}"
|
|
b = brk.get_json(path)
|
|
m = mempool.get_json(path)
|
|
show("GET", path, b, m)
|
|
assert_same_values(b, m, exclude={"sigops"})
|
|
|
|
|
|
def test_tx_coinbase(brk, mempool, block):
|
|
"""Coinbase transaction must match."""
|
|
path = f"/api/tx/{block.coinbase_txid}"
|
|
b = brk.get_json(path)
|
|
m = mempool.get_json(path)
|
|
show("GET", path, b, m)
|
|
assert_same_values(b, m, exclude={"sigops"})
|
|
|
|
|
|
# ── /api/tx/{txid}/hex ───────────────────────────────────────────────
|
|
|
|
|
|
def test_tx_hex(brk, mempool, block):
|
|
"""Raw transaction hex must be identical."""
|
|
path = f"/api/tx/{block.txid}/hex"
|
|
b = brk.get_text(path)
|
|
m = mempool.get_text(path)
|
|
show("GET", path, b[:80] + "…", m[:80] + "…")
|
|
assert b == m
|
|
|
|
|
|
# ── /api/tx/{txid}/raw ───────────────────────────────────────────────
|
|
|
|
|
|
def test_tx_raw(brk, mempool, block):
|
|
"""Raw transaction bytes must be identical."""
|
|
path = f"/api/tx/{block.txid}/raw"
|
|
b = brk.get_bytes(path)
|
|
m = mempool.get_bytes(path)
|
|
show("GET", path, f"<{len(b)} bytes>", f"<{len(m)} bytes>")
|
|
assert b == m
|
|
|
|
|
|
# ── /api/tx/{txid}/status ────────────────────────────────────────────
|
|
|
|
|
|
def test_tx_status(brk, mempool, block):
|
|
"""Confirmation status must match for a confirmed tx."""
|
|
path = f"/api/tx/{block.txid}/status"
|
|
b = brk.get_json(path)
|
|
m = mempool.get_json(path)
|
|
show("GET", path, b, m)
|
|
assert_same_values(b, m)
|
|
|
|
|
|
# ── /api/tx/{txid}/merkle-proof ──────────────────────────────────────
|
|
|
|
|
|
def test_tx_merkle_proof(brk, mempool, block):
|
|
"""Merkle inclusion proof must match."""
|
|
path = f"/api/tx/{block.txid}/merkle-proof"
|
|
b = brk.get_json(path)
|
|
m = mempool.get_json(path)
|
|
show("GET", path, b, m)
|
|
assert_same_values(b, m)
|
|
|
|
|
|
# ── /api/tx/{txid}/merkleblock-proof ─────────────────────────────────
|
|
|
|
|
|
def test_tx_merkleblock_proof(brk, mempool, block):
|
|
"""BIP37 merkleblock proof hex must be identical."""
|
|
path = f"/api/tx/{block.txid}/merkleblock-proof"
|
|
b = brk.get_text(path)
|
|
m = mempool.get_text(path)
|
|
show("GET", path, b[:80] + "…", m[:80] + "…")
|
|
assert b == m
|
|
|
|
|
|
# ── /api/tx/{txid}/outspend/{vout} ───────────────────────────────────
|
|
|
|
|
|
def test_tx_outspend(brk, mempool, block):
|
|
"""Spending status of output 0 must match exactly."""
|
|
path = f"/api/tx/{block.txid}/outspend/0"
|
|
b = brk.get_json(path)
|
|
m = mempool.get_json(path)
|
|
show("GET", path, b, m)
|
|
assert_same_values(b, m)
|
|
|
|
|
|
# ── /api/tx/{txid}/outspends ─────────────────────────────────────────
|
|
|
|
|
|
def test_tx_outspends(brk, mempool, block):
|
|
"""Spending status of all outputs must match exactly."""
|
|
path = f"/api/tx/{block.txid}/outspends"
|
|
b = brk.get_json(path)
|
|
m = mempool.get_json(path)
|
|
show("GET", path, b, m)
|
|
assert_same_values(b, m)
|
|
|
|
|
|
# ── /api/v1/cpfp/{txid} ─────────────────────────────────────────────
|
|
|
|
|
|
def test_cpfp(brk, mempool, block):
|
|
"""CPFP info structure must match for a confirmed tx."""
|
|
path = f"/api/v1/cpfp/{block.txid}"
|
|
b = brk.get_json(path)
|
|
m = mempool.get_json(path)
|
|
show("GET", path, b, m)
|
|
assert_same_structure(b, m)
|
|
|
|
|
|
# ── /api/v1/transaction-times ────────────────────────────────────────
|
|
|
|
|
|
def test_transaction_times(brk, mempool, live):
|
|
"""First-seen timestamps array must have the same length."""
|
|
txids = [b.txid for b in live.blocks[:3]]
|
|
params = [("txId[]", t) for t in txids]
|
|
path = "/api/v1/transaction-times"
|
|
b = brk.get_json(path, params=params)
|
|
m = mempool.get_json(path, params=params)
|
|
show("GET", f"{path}?txId[]={{{len(txids)} txids}}", b, m)
|
|
assert isinstance(b, list) and isinstance(m, list)
|
|
assert len(b) == len(m) == len(txids)
|