By Vincent (@tivince82)
Target Repository: Scottcjn/Rustchain
Reference Pull Request: Scottcjn/Rustchain#8517
1. Introduction: The Challenge of Cross-Chain Reconciliation
Cross-chain bridges represent some of the most critical infrastructure in modern decentralized ecosystems. They are tasked with locking native assets on a source chain while minting or releasing wrapped representations on a target network (such as Solana or Base). In RustChain's architecture, Layer 2 of the federation arc (specified in FEDERATION_BRIDGED_SUPPLY_SPEC.md) provides continuous, per-epoch reconciliation snapshots.
These snapshots serve two vital purposes:
-
Deterministic State Attestation: Every epoch, the node records a permanent snapshot containing
locked_in_rtc,completed_in_rtc,voided_in_rtc, and the canonicalbridged_supply_committed. This snapshot is cryptographically fingerprinted using a SHA-256state_hashover the canonical-JSON payload. - Cross-Chain Drift Detection: The Layer 2 reconciliation protocol allows automated checkers to compare RustChain's internal ledger against external destination ledgers, detecting discrepancies before they escalate into insolvency or consensus divergence.
However, an accounting bug in the formula calculating bridged_supply_committed introduced a silent, structural under-reporting flaw. In this deep dive, we explore how the defect occurred, how to reproduce it, and how the fix restores mathematical invariants across the federation.
2. The Accounting Architecture: Aggregate vs. Committed State
In node/bridge_federation_routes.py, the function _aggregate_bridge_state(conn) computes the current status of all bridge operations by aggregating the bridge_transfers table:
# Extract from node/bridge_federation_routes.py
cursor.execute(
"SELECT status, COUNT(*), COALESCE(SUM(amount_rtc), 0.0) "
"FROM bridge_transfers GROUP BY status"
)
by_status = {status: {"count": int(n), "total_rtc": float(total)}
for status, n, total in cursor.fetchall()}
# "Locked in" = pending + locked + confirming
locked_in = sum(
by_status.get(s, {}).get("total_rtc", 0.0)
for s in ("pending", "locked", "confirming")
)
completed_in = by_status.get("completed", {}).get("total_rtc", 0.0)
voided_in = by_status.get("voided", {}).get("total_rtc", 0.0)
Notice the crucial domain definition:
-
locked_in: Represents RTC that has been initiated but not yet finalized across the bridge. It explicitly sums only("pending", "locked", "confirming"). -
completed_in: Represents transfers that have successfully finalized. -
voided_in: Represents transfers that were cancelled, rejected, or refunded. Voided transfers are never included inlocked_inorcompleted_in.
3. The Vulnerability: The Double-Subtraction Trap
In node/bridge_reconciliation.py, the committed supply formula was defined as:
# Defective implementation in node/bridge_reconciliation.py
def _bridged_supply_committed(state: Dict[str, Any]) -> float:
"""Per FEDERATION_BRIDGED_SUPPLY_SPEC.md section 3:
bridged_supply_committed = locked_in + completed_in - voided_in
"""
return (
float(state.get("locked_in_rtc", 0.0))
+ float(state.get("completed_in_rtc", 0.0))
- float(state.get("voided_in_rtc", 0.0))
)
Why this is mathematically broken:
Because voided_in was already excluded from locked_in during the aggregate query in _aggregate_bridge_state, subtracting voided_in a second time constitutes a double-subtraction.
Consider a concrete economic scenario:
- A user initiates a bridge transfer of 50 RTC (Status:
pending, thenvoideddue to timeout). - Another user initiates and completes a transfer of 100 RTC (Status:
completed). - Active active transfers: 50 RTC (Status:
locked).
Actual committed bridge supply: $100 \text{ RTC (completed)} + 50 \text{ RTC (locked)} = 150 \text{ RTC}$.
Formula result before fix: $150 \text{ RTC} - 50 \text{ RTC (voided)} = 100 \text{ RTC}$.
Even worse: if a network experiences a flurry of cancelled transfers where $\text{voided_in} > \text{locked_in} + \text{completed_in}$, the reported bridged_supply_committed becomes negative, violating non-negativity invariants and triggering false alerts in downstream automated audit watchers.
Moreover, because the test suite in node/tests/test_bridge_reconciliation.py hardcoded the erroneous value:
# Defective test assertion
assert snap["bridged_supply_committed"] == pytest.approx(77.0) # 30 + 50 - 3 = 77
The test passed, giving a false sense of security while embedding an accounting error directly into regression gates.
4. Native Python Reproduction Harness
The following standalone script demonstrates the discrepancy against SQLite in memory:
import sqlite3
def run_simulation():
conn = sqlite3.connect(":memory:")
cur = conn.cursor()
cur.execute("""
CREATE TABLE bridge_transfers (
id INTEGER PRIMARY KEY,
amount_rtc REAL,
status TEXT
)
""")
# Seed transfers: 30 locked, 50 completed, 3 voided
transfers = [
(10.0, "pending"),
(20.0, "locked"),
(50.0, "completed"),
(3.0, "voided"),
]
cur.executemany("INSERT INTO bridge_transfers (amount_rtc, status) VALUES (?, ?)", transfers)
conn.commit()
# 1. Aggregate
cur.execute("SELECT status, SUM(amount_rtc) FROM bridge_transfers GROUP BY status")
totals = dict(cur.fetchall())
locked_in = totals.get("pending", 0.0) + totals.get("locked", 0.0)
completed_in = totals.get("completed", 0.0)
voided_in = totals.get("voided", 0.0)
# 2. Defective Calculation
defective_committed = locked_in + completed_in - voided_in
# 3. Corrected Calculation
correct_committed = locked_in + completed_in
print(f"Locked In: {locked_in} RTC")
print(f"Completed In: {completed_in} RTC")
print(f"Voided In: {voided_in} RTC")
print(f"Defective Calculation: {defective_committed} RTC (Under-reported!)")
print(f"Correct Calculation: {correct_committed} RTC (Matches Reality)")
assert correct_committed == 80.0
print("Verification Successful: Correct committed supply is 80.0 RTC.")
if __name__ == "__main__":
run_simulation()
5. The Remediation (PR #8517)
The remediation in Scottcjn/Rustchain#8517 addresses both the function implementation and test assertions:
1. Code Fix (node/bridge_reconciliation.py)
def _bridged_supply_committed(state: Dict[str, Any]) -> float:
"""Per FEDERATION_BRIDGED_SUPPLY_SPEC.md section 3:
- bridged_supply_committed = locked_in + completed_in - voided_in
+ bridged_supply_committed = locked_in + completed_in
"""
return (
float(state.get("locked_in_rtc", 0.0))
+ float(state.get("completed_in_rtc", 0.0))
- - float(state.get("voided_in_rtc", 0.0))
)
2. Test Verification (node/tests/test_bridge_reconciliation.py)
def test_snapshot_bridged_supply_committed_formula(db_path):
...
assert snap["locked_in_rtc"] == 30.0
assert snap["completed_in_rtc"] == 50.0
assert snap["voided_in_rtc"] == 3.0
- assert snap["bridged_supply_committed"] == pytest.approx(77.0)
+ assert snap["bridged_supply_committed"] == pytest.approx(80.0)
Running pytest across node/tests/test_bridge_reconciliation.py yields 19/19 passed in 0.62s (100% green).
6. Key Takeaways for Distributed Systems Engineers
- Beware of Derived Quantities in Multi-Stage Aggregation: When calculating metrics derived from lower-level aggregations, always verify whether filtered categories are already partitioned or mutually exclusive.
-
Avoid Affirming the Consequent in Unit Tests: Writing a test assertion that checks
actual == expected_formularather than verifying the underlying domain invariant can cement bugs into the test suite. - Audit Bridge Invariants Early: In cross-chain protocols, reconciliation logic must remain strictly non-negative and monotonic with respect to finalized settlement events.
Resources & Links
- RustChain Main Repository: https://github.com/Scottcjn/Rustchain
- Pull Request #8517: https://github.com/Scottcjn/Rustchain/pull/8517
- Official Documentation: https://rustchain.org
Top comments (0)