Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 70 additions & 54 deletions OVERVIEW.md

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions PLUGINS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,14 @@ documents what it does, how it works, and how to configure it. The plugin lifecy
| `query_engine_plugin` | Opt-in SQL queries over the node's current chain state, answered by an in-process C++ service and, when HTTP is enabled, `POST /v1/query/execute`; runs only on a non-producing node in head or irreversible read mode | [README](plugins/query_engine_plugin/README.md) |
| `resource_monitor_plugin` | Watches free space on every file system nodeop writes to and gracefully shuts the node down before it runs out | [README](plugins/resource_monitor_plugin/README.md) |
| `signature_provider_kms_plugin` | Adds the `KMS:` signature-provider scheme, signing Ethereum keys remotely through AWS KMS so the key never leaves AWS | [README](plugins/signature_provider_kms_plugin/README.md) |
| `signature_provider_manager_plugin` | Owns every signing key the node uses, parsing each `--signature-provider` spec and publishing the providers to the chain, producer, net, outpost, and underwriter plugins | [README](plugins/signature_provider_manager_plugin/README.md) |
| `signature_provider_manager_plugin` | Owns every signing key the node uses, parsing each `--signature-provider` spec and publishing the providers to the chain, producer, net, and outpost plugins | [README](plugins/signature_provider_manager_plugin/README.md) |
| `signature_provider_ssm_plugin` | Adds the `SSM:` signature-provider scheme, fetching a private key once from an AWS SSM Parameter Store SecureString and signing locally thereafter | [README](plugins/signature_provider_ssm_plugin/README.md) |
| `snapshot_api_plugin` | Public, read-only HTTP endpoints for snapshot discovery and download, so nodes can bootstrap from each other | [README](plugins/snapshot_api_plugin/README.md) |
| `state_history_plugin` | Records per-block traces, chain-state deltas, and finality data to append-only logs and streams them to clients over a binary websocket protocol | [README](plugins/state_history_plugin/README.md) |
| `status_monitor_plugin` | Ships one `/v1/chain/get_info` snapshot per irreversible block to an OpenSearch/Elasticsearch `_bulk` endpoint, rendered through an operator JSON template | [README](plugins/status_monitor_plugin/README.md) |
| `test_control_api_plugin` | HTTP surface for `test_control_plugin`, registering the `/v1/test_control/*` write endpoints in their own `test_control` API category | [README](plugins/test_control_api_plugin/README.md) |
| `test_control_plugin` | Test-only plugin that arms deliberate node misbehavior: shut down inside a named producer's round, throw from a controller signal handler, or republish the next block with one action swapped | [README](plugins/test_control_plugin/README.md) |
| `trace_api_plugin` | Full-history action trace store with HTTP endpoints for querying traces, transactions, actions, and token transfers | [trace_api_plugin.md](plugins/trace_api_plugin/trace_api_plugin.md) |
| `underwriter_plugin` | Autonomous underwriter daemon that polls pending swaps and submits signed underwrite-intent commits for the outpost legs that still lack one | [README](plugins/underwriter_plugin/README.md) |
| `wallet_api_plugin` | Publishes the `kiod` key store as the `/v1/wallet/*` HTTP endpoints that `clio` and a `KIOD:` signature provider call. Linked and initialized by `kiod`, not `nodeop` | [README](plugins/wallet_api_plugin/README.md) |
| `wallet_plugin` | The `kiod` key store: a locked directory of AES-encrypted wallet files with inactivity auto-lock and transaction and digest signing. Linked and initialized by `kiod`, not `nodeop` | [README](plugins/wallet_plugin/README.md) |

Expand Down
5 changes: 3 additions & 2 deletions contracts/sysio.chalg/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ OPP envelope dispute resolution and slash-execution contract.
- Triggered by `sysio.msgch::evalcons`; dispatches the winning envelope via `sysio.msgch::resolvedisp`
- Tier-1 electorate snapshot from `sysio.roa::nodeowners`; the active `network_gen` is read through
the shared canonical ROA accessor
- Slashes via `sysio.opreg::slash` (opreg routes the unlocked bond to the matching LP and defers the
locked portion through `sysio.uwrit::release`)
- Slashes via `sysio.opreg::slash`: opreg marks the operator `SLASHED` and removes its whole
depot-native collateral balance from the operator's row; the slashed tokens stay in
`sysio.opreg`'s custody
- Pauses / unpauses via `sysio.epoch::pause` / `sysio.epoch::unpause`
61 changes: 39 additions & 22 deletions contracts/sysio.epoch/README.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,58 @@
# sysio.epoch

Epoch lifecycle and batch operator scheduling contract for the OPP (Outpost Protocol) system.
Global epoch clock and batch operator scheduling contract for the OPP (Outpost Protocol) system.

## Responsibility

- Manages the synthetic epoch clock (default: 6-minute epochs)
- Maintains the batch operator roster (registration, warmup, cooldown, blacklist)
- Assigns operators into 3 rotation groups of 7 via `schbatchgps`
- Advances epochs with deterministic group rotation (`epoch_index % 3`)
- Supports in-place operator replacement when an operator is slashed or deregistered
- Registers external chain outposts (ETH, SOL, etc.)
- Provides global pause/unpause (controlled by `sysio.chalg`)
- Owns the single global epoch clock (`epoch_duration_sec`, default 360 s, bounded to 60 s .. 30 days)
- Builds the initial batch operator schedule with `schbatchgps` and maintains it as a sliding window
of `batch_op_groups` groups of `operators_per_epoch` members; the group on duty is always the front
of the window
- Advances epochs (`advance`), crank-driven by `sysio.msgch::chkcons` after genesis
- Gates every advance on emissions readiness: if `sysio.system` cannot pay the epoch, the advance is
recorded in `blocklog` and skipped (never thrown), and retried on the next `chkcons`
- Provides the global pause/unpause used by `sysio.chalg` while an envelope dispute is open

Operator registration, collateral and status live on `sysio.opreg`; the outpost set lives on
`sysio.chains`. This contract reads both and mirrors neither.

## Tables

| Table | Type | Description |
|-------|------|-------------|
| `epochcfg` | Singleton | Epoch duration, group count, warmup/cooldown config |
| `epochstate` | Singleton | Current epoch index, active group, 3 groups of 7, pause flag |
| `operators` | Multi-index | Operator roster with type, status, collateral, group assignment |
| `outposts` | Multi-index | Registered external chain outposts |
| `epochcfg` | `kv::global` | `epoch_duration_sec`, `operators_per_epoch` (default 7), `batch_operator_minimum_active` (default 21), `batch_op_groups` (default 3), `epoch_retention_envelope_log_count` (default 200) |
| `epochstate` | `kv::global` | Current epoch index, current / next epoch start, active group cursor, the resident group window, last consensus hash, pause flag |
| `blocklog` | `kv::table` | One row per epoch the emissions gate blocked: reason, attempted emission, treasury and balance figures, first/last retry and retry count. Pruned when the gate passes |

## Actions

| Action | Auth | Description |
|--------|------|-------------|
| `setconfig` | `sysio.epoch` | Set epoch configuration |
| `regoperator` | `sysio.epoch` | Register an operator |
| `unregoper` | operator | Begin deregistration (cooldown) |
| `advance` | permissionless | Advance epoch if duration elapsed |
| `schbatchgps` | `sysio.epoch` | One-time group assignment (21 operators) |
| `replaceop` | `sysio.epoch` | Replace operator in-place within group |
| `regoutpost` | `sysio.epoch` | Register an outpost chain |
| `pause` | `sysio.chalg` | Set global pause |
| `unpause` | `sysio.chalg` | Clear global pause |
| `setconfig` | `sysio.epoch` | Set the epoch configuration. Requires `operators_per_epoch * batch_op_groups == batch_operator_minimum_active` and enforces the size caps (`MAX_OPERATORS_PER_EPOCH` 100, `MAX_BATCH_OP_GROUPS` 255, `MAX_SCHEDULED_BATCH_OPERATORS` 1000) |
| `schbatchgps` | `sysio.epoch` | Build the initial window from the `ACTIVE` batch operators on `sysio.opreg` (non-bootstrapped first, then bootstrapped, trimmed to `batch_operator_minimum_active`) |
| `advance` | permissionless at genesis (epoch 0 → 1); afterwards `sysio.msgch` or `sysio.epoch` | Advance the epoch once the wall-clock boundary has passed and the contract is not paused |
| `pause` | `sysio.chalg` | Set the global pause |
| `unpause` | `sysio.chalg` | Clear the global pause |

## What `advance` does

1. Emissions readiness gate (block-and-retry via `blocklog`, never a throw).
2. Delivery audit of the expiring group for every active outpost: every operator that delivered a
non-canonical envelope is slashed through `sysio.chalg::slashop`; each member's delivery result is
recorded with `sysio.opreg::recorddel`, followed by `sysio.opreg::termcheck`.
3. Bump the epoch index, drop the expired group from the front of the window and append a new tail
group drawn from `ACTIVE` batch operators that are not already resident (non-bootstrapped first).
The resident groups stay disjoint, so an operator serves at most once every `batch_op_groups`
epochs.
4. `sysio.opreg::flushwtdw` matures queued collateral withdrawals.
5. Queue `OPERATORS` and `BATCH_OPERATOR_GROUPS` to every active outpost through
`sysio.msgch::queueout` (an empty group is withheld), then `sysio.msgch::buildenv` per outpost.
6. `sysio.system::accrueepoch` and `rcrdbatch`, plus `payepoch` on pay epochs.

## Dependencies

- Notifies `sysio.msgch` on epoch advancement
- Advanced by `sysio.msgch` (`chkcons`, and `bootstrap` at epoch 0)
- Reads operators from `sysio.opreg`, authex links from `sysio.authex`, outposts from `sysio.chains`
- Calls `sysio.chalg::slashop`, `sysio.opreg::{recorddel,termcheck,flushwtdw}`,
`sysio.msgch::{queueout,buildenv}` and `sysio.system::{accrueepoch,rcrdbatch,payepoch}`
- Pause/unpause controlled by `sysio.chalg`
76 changes: 49 additions & 27 deletions contracts/sysio.msgch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,65 @@ Inbound/outbound OPP message chain management and consensus tracking contract.

## Responsibility

- Manages inbound chain requests from external outposts
- Collects deliveries from all 7 elected batch operators per epoch
- Evaluates consensus (Option A: unanimous 7/7, Option B: 4+ majority at epoch boundary)
- Stores and routes individual messages by attestation type
- Queues outbound messages and builds OPP envelopes for delivery to outposts
- Accepts inbound OPP envelopes delivered by the batch operators of the active group, one delivery per
operator per outpost per epoch (`MAX_ENVELOPE_BYTES` = 32,768; larger deliveries are rejected)
- Evaluates consensus per (outpost, epoch): every eligible operator delivers an identical envelope
(fast path), or a strict majority of the group agrees once the epoch boundary has passed. A
post-boundary split with no strict majority opens a `sysio.chalg` dispute
- Validates the per-outpost envelope chain and message sequence, stores the accepted messages and
attestations, and routes each attestation to its depot handler
- Queues outbound attestations and packs them into one OPP envelope per outpost per epoch; whatever
does not fit under the envelope cap stays queued for the next epoch
- Drives the epoch: `chkcons` advances `sysio.epoch` once every active outpost has reached
consensus and the wall-clock boundary has passed

## Tables

| Table | Type | Description |
|-------|------|-------------|
| `inchainreq` | Multi-index | Inbound chain requests per outpost/epoch |
| `deliveries` | Multi-index | Per-operator delivery records with chain hashes |
| `messages` | Multi-index | Individual OPP messages (inbound + outbound) |
| `outenvelopes` | Multi-index | Built outbound envelopes pending delivery |
| `envelopes` | `kv::table` | Inbound deliveries, one row per batch operator per outpost per epoch (working state, pruned to the current and previous epoch) |
| `messages` | `kv::table` | Individual OPP messages extracted from consensus-verified envelopes |
| `attestations` | `kv::table` | Attestations extracted inbound, and outbound attestations queued (`READY`) for envelope packing |
| `outenvelopes` | `kv::table` | Built outbound envelopes awaiting relay, with their canonical epoch digest |
| `outpcons` | `kv::table` | Per-outpost consensus record: accepted envelope digest and inbound message-chain tip |
| `attseq` | `kv::table` | Attestation sequence counter |
| `envlog` | `kv::table` | Metadata-only envelope audit log, capped at `active_outposts * 2 * epoch_retention_envelope_log_count` rows |

## Actions

| Action | Auth | Description |
|--------|------|-------------|
| `crank` | permissionless | Main depot crank, advances processing |
| `createreq` | `sysio.msgch` | Create inbound chain request for an outpost |
| `deliver` | operator | Batch operator delivers a chain with hash + messages |
| `evalcons` | `sysio.msgch` | Evaluate consensus on a chain request |
| `processmsg` | `sysio.msgch` | Process a READY message (unpack, route attestations) |
| `queueout` | `sysio.epoch`, `sysio.opreg`, `sysio.uwrit`, `sysio.reserv`, `sysio.synd`, or `sysio.msgch` | Queue an outbound message to an outpost |
| `buildenv` | `sysio.msgch` | Build outbound envelope from queued messages |
| `bootstrap` | `sysio.msgch` | Epoch-0 only: asserts the `sysio.system` emissions config is set, then triggers the first `sysio.epoch::advance` |
| `deliver` | batch operator (resident active group, `ACTIVE` in `sysio.opreg`) | Deliver an inbound envelope for an outpost; calls `evalcons` inline |
| `evalcons` | `sysio.msgch` | Evaluate consensus for an (outpost, epoch); on consensus store and dispatch the attestations; on an eligible split open a `sysio.chalg` dispute |
| `chkcons` | permissionless | If no dispute is open, every active outpost has consensus and the boundary has passed, call `sysio.epoch::advance` |
| `resolvedisp` | `sysio.chalg` | Dispatch the winning envelope of a resolved dispute |
| `queueout` | `sysio.epoch`, `sysio.opreg`, `sysio.synd`, or `sysio.msgch` | Queue an outbound attestation for an outpost |
| `buildenv` | `sysio.epoch` | Pack `READY` attestations into the outpost's outbound envelope for the epoch |

## Attestation routing

Inbound (outpost → depot):

- `SYNDICATE_LIQ` → `sysio.synd::onsynd`, `LIQ_YIELD` → `sysio.synd::onyield`. Each carries the
envelope's epoch and canonical digest, and is forwarded only once the payload's token is an active
`TOKEN_KIND_LIQ` row on `sysio.tokens` bound to the proven outpost and, for a syndication, the
user's key family is the outpost's own. After the envelope's last attestation it sends
`sysio.synd::closeenv`, only when at least one of them reached `sysio.synd`.
- `NODE_OWNER_REG` → `sysio.roa` (account creation and node-owner registration, recording the
outpost link).
- `STAKING_REWARD` → `sysio.dclaim::onreward`, after binding the reward's chain to the proven
delivering outpost.
- Every other type is dropped. Every refusal is a logged drop, never an abort.

Outbound (depot → outpost), queued through `queueout`:

- `OPERATORS` and `BATCH_OPERATOR_GROUPS` from `sysio.epoch::advance`, to every active outpost
- `DESYNDICATE_LIQ` from `sysio.synd::desyndicate`

## Dependencies

- Reads epoch state from `sysio.epoch`
- Notifies `sysio.chalg` on consensus failure
- Routes attestations to `sysio.epoch`, `sysio.uwrit`, `sysio.chalg`
- Routes `SYNDICATE_LIQ` and `LIQ_YIELD` to `sysio.synd` (`onsynd` for a syndication,
linked user or not, `onyield` for a yield report), each carrying the envelope's epoch and
canonical digest, once the payload's token is an active `TOKEN_KIND_LIQ` row on
`sysio.tokens` bound to the proven outpost and, for a syndication, the user's key family
is the outpost's own. After the envelope's last attestation it sends `sysio.synd::closeenv`,
only when at least one of them reached `sysio.synd`. Every refusal is a logged drop, never
an abort. `DESYNDICATE_LIQ` is outbound only:
`sysio.synd::desyndicate` queues it through `queueout`.
- Reads epoch state from `sysio.epoch` and operator status from `sysio.opreg`
- Opens disputes on `sysio.chalg` (`opendispute`); `sysio.chalg::chkdispute` calls back into `resolvedisp`
- Triggers `sysio.epoch::advance` from `chkcons` (and from `bootstrap` at epoch 0)
- Routes inbound attestations to `sysio.synd`, `sysio.roa` and `sysio.dclaim`
8 changes: 4 additions & 4 deletions contracts/sysio.msgch/src/sysio.msgch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -827,14 +827,14 @@ void dispatch_node_owner_reg(const std::vector<char>& data, uint64_t chain_code)
// task alongside liqEth / liqsol-token wiring.
break;

// Outbound-only types (depot emits these, never receives them inbound)
// and deprecated pre-launch types are dropped silently. SLASH was
// formerly its own attestation type; it now rides on OPERATOR_ACTION
// with action_type=SLASH and is gated inside `dispatch_operator_action`.
// Outbound-only types (depot emits these, never receives them inbound) are dropped silently;
// an outpost relaying one back is a benign no-op.
case AttestationType::ATTESTATION_TYPE_SWAP_REVERT:
case AttestationType::ATTESTATION_TYPE_DEPOSIT_REVERT:
case AttestationType::ATTESTATION_TYPE_OPERATORS:
case AttestationType::ATTESTATION_TYPE_BATCH_OPERATOR_GROUPS:
break;

case AttestationType::ATTESTATION_TYPE_NODE_OWNER_REG:
// NFT node-owner claim: create the account + register + record the ETH link. Self-contained
// (decodes NodeOwnerRegistration, inline-sends sysio.roa); soft-drops a malformed envelope.
Expand Down
Binary file modified contracts/sysio.msgch/sysio.msgch.wasm
Binary file not shown.
Loading
Loading