# ECP-0092: Ethereum rails and private settlement for every.channel Status: Draft ## Problem / context `every.channel` already has useful anti-junk and manifest integrity primitives, but they stop at repo-local formats: custom Merkle trees, JSON body hashes, and Ed25519 signatures. That is enough for local validation, not for the broader direction now requested: - stream identity, broadcast de-duplication, manifests, and transport announcements should all have Ethereum-compatible representations, - private-chain settlement should reuse existing Ethereum tooling instead of inventing a custom ledger, - iroh should remain the transport substrate, - storage on chain must stay compact, and - `ecp-forge` should become the high-bandwidth head node for sequencing, archival, and bootstrap. This supersedes the specific ECP-0022 alternative that rejected “global consensus / blockchain for manifests” as overkill. The new direction is not a public general-purpose chain. It is a private, Ethereum-compatible settlement rail for every.channel commitments. ## Decision Adopt a dual-plane architecture: - `iroh` remains the transport, discovery, and media movement layer. - Local protocol integrity remains first-class: - `manifest_id` stays BLAKE3 over the manifest body, - object membership proofs stay `merkle+blake3`, - Ed25519 manifest signatures remain supported. - Ethereum-compatible commitments become an additive settlement/mirroring layer for stream identity, transport announcements, and manifests. - Ethereum-native signatures are added alongside local signatures: - manifests may carry secp256k1 EIP-712 signatures over `ManifestBody`, - no existing local signature path is removed as part of this proposal. - On-chain state remains compact: - manifests store only stream/epoch ids plus commitment hashes, - control announcements store only stream ids plus announcement commitments, - full media bytes, manifests, PSIP tables, and chunk inventories remain off-chain. - The chain is private and purpose-built for every.channel use cases: - no arbitrary application compute in the near term, - no fraud-proof system in the near term, - permissionless submission as far as operationally possible, - pseudonymous participation preferred over account-heavy identity. ## Details ### Canonical Ethereum representations Introduce Solidity-compatible struct mirrors for the protocol surfaces we actually ship: - `BroadcastId` - `SourceId` - `StreamKey` - `StreamDescriptor` - `StreamControlAnnouncement` - `ChunkId` - `ManifestVariant` - `ManifestBody` - `ManifestSignature` - `Manifest` These are encoded via Solidity ABI rules and hashed with `keccak256`. They mirror the shipped protocol types; they do not replace the local wire format or local hashing rules. ### Manifest commitments Publisher-generated manifests may carry a set of Ethereum commitments as first-class fields: - `manifest-data-merkle-keccak256-v1` - Keccak Merkle root over ordered chunk hashes, or over ordered variant roots for multi-variant manifests. - `manifest-body-abi-keccak256-v1` - `keccak256(abi.encode(EthManifestBody))` - `manifest-envelope-abi-keccak256-v1` - `keccak256(abi.encode(EthManifest))` `manifest_id` and `merkle_root` remain the local BLAKE3-backed protocol fields. Ethereum commitments are explicit, separately named, and never inferred from those local field names alone. ### Signature rails Manifest signatures become dual-rail: - local signatures continue to sign the local BLAKE3 `manifest_id` with Ed25519, - Ethereum-native signatures sign the typed `EthManifestBody` with secp256k1 EIP-712, - both signature families may appear on the same manifest. The Ethereum signature target is `ManifestBody`, not the full manifest envelope, so signatures do not become self-referential when more signatures are appended. ### Stream and control commitments Stream descriptors and control announcements may also carry Ethereum-compatible commitments: - `stream-id-keccak256-v1` - `stream-descriptor-abi-keccak256-v1` - `control-announcement-abi-keccak256-v1` This ties broadcast-scoped discovery identity to the same settlement vocabulary used by manifests without forcing transport-time consumers to abandon the local vocabulary they already use. ### Solidity rail contract Add a minimal contract that stores only the latest compact pointers: - latest manifest pointer per `stream_id + epoch_id` - latest transport announcement pointer per `stream_id` - event emissions for historical indexing The contract must stay event-heavy and storage-light. Full manifests stay in iroh / relay / archive storage. ### `ecp-forge` role `ecp-forge` becomes the maximal head node for this network: - private-chain bootstrap and packaging, - archival indexer for settlement events, - high-bandwidth manifest and control announcer, - optional sequencer / execution-client host for the private network. This role is operational, not constitutional. Other nodes must still be able to validate, mirror, and submit commitments without going through a closed control plane. ## Alternatives considered - Keep custom BLAKE3-only manifests forever. Rejected because it strands every.channel outside the tooling and audit surface of the Ethereum ecosystem. - Replace BLAKE3 and Ed25519 immediately. Rejected because it weakens the local protocol’s existing integrity path before the private rail is operational and discards useful cryptographic properties for no near-term operational win. - Build a custom blockchain. Rejected because existing Rust + Solidity stacks are already good enough and reduce implementation risk. - Use public Ethereum mainnet / arbitrary public L2s directly. Rejected for now because cost, privacy, and operational control do not fit the current network shape. ## Rollout / teardown plan 1. Add `ec-eth` with canonical Solidity-compatible representations and Keccak commitments. 2. Preserve the local BLAKE3/Ed25519 rail as the default transport integrity path. 3. Add optional secp256k1 EIP-712 manifest-body signatures alongside Ed25519 signatures. 4. Add the minimal Solidity rail contract for compact settlement pointers. 5. Teach publishers/indexers to mirror manifests and announcements onto the private chain. 6. Stand up the private Ethereum-compatible network on `ecp-forge` and companion nodes. Teardown: - back out the Ethereum rail changes explicitly in code; the preserved local rail remains as the fallback integrity path. ## Open questions - Which execution stack should back the private network first: a slim Reth-based node, or a more minimal Rust EVM deployment? - When the private rail becomes live, do we require both signature families for publisher policy, or is one valid rail-specific signature enough for a given transport or settlement action?