# 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?
