|
| 1 | +## Abstract |
| 2 | + |
| 3 | +This document proposes an architecture for "Plutus Script Re-Executor" — a tool for Cardano dapps developers to run custom PlutusCore scripts while following the node in parallel to the original scripts. |
| 4 | + |
| 5 | +This is up-to-date document. The history of decisions that influenced the specification should be available in [ADRs](adr/) |
| 6 | + |
| 7 | +### Architecture Overview |
| 8 | + |
| 9 | +The Plutus Script Re-Executor system consists of main components: |
| 10 | + |
| 11 | +1. **Scanning Process** — process that connects to Cardano node and follows it, scanning the blocks |
| 12 | +2. **Context builder** — instrument that provides `ScriptContext` for a given `ScriptHash` |
| 13 | +3. **Script executor** — tool to run custom `PlutusCore` scripts using the provided `ScriptContext` |
| 14 | +4. **Events API** — REST endpoints with access to the results of the re-executor |
| 15 | +5. **Full Cardano Node** — standard node providing blocks, validation services and canonical chain state |
| 16 | +6. **Leash Node-to-Client protocol** — mini-protocol & connection mode to limit the node's eagerness |
| 17 | +7. **Configuration map** — user configuration parser |
| 18 | +8. **Data storage** — database to keep the data |
| 19 | + |
| 20 | +### Glossary |
| 21 | + |
| 22 | +- ScriptHash — Type representing the /BLAKE2b-224/ hash of a script. 28 bytes. |
| 23 | +- ScriptContext — An input to a Plutus script created by the ledger. It includes details of the transaction being validated. Additionally, since a transaction may do multiple things, each of which needs to be validated by a separate script, the script context also specifies what exactly the current script is responsible for validating. |
| 24 | +- PlutusCore — a low-level language for on-chain code, based on untyped lambda calculus. |
| 25 | +- Mini-protocol — a mini protocol is a well-defined and modular building block of the network protocol. Structuring a protocol around mini-protocols helps manage the overall complexity of the design and adds useful flexibility. |
| 26 | + |
| 27 | +References: |
| 28 | +- https://plutus.cardano.intersectmbo.org/docs/glossary |
| 29 | +- https://ouroboros-network.cardano.intersectmbo.org/pdfs/network-spec/network-spec.pdf |
| 30 | + |
| 31 | +### Component Specifications |
| 32 | + |
| 33 | +#### 1. Scanning process |
| 34 | + |
| 35 | +**Purpose**: follows the node and scans for specified `ScriptHash` scripts. |
| 36 | + |
| 37 | +**Configuration**: takes a list of `ScriptHash` entities from the configuration map. |
| 38 | + |
| 39 | +#### 2. Context builder |
| 40 | + |
| 41 | +**Purpose**: to be able to run a script we need to rebuild its context on-chain, this component either provides it from the data storage or queries from the node. |
| 42 | + |
| 43 | +#### 3. Script executor |
| 44 | + |
| 45 | +**Purpose**: run the provided `PlutusCore` script in the given `ScriptContext`. |
| 46 | + |
| 47 | +**Configuration**: takes the configuration map. |
| 48 | + |
| 49 | +**Details**: the executor takes the configuration map and each time it sees a known `ScriptHash` in the transaction, it executed the corresponding script from the map. |
| 50 | + |
| 51 | +#### 4. Events API |
| 52 | + |
| 53 | +**Purpose**: provides access to the results of the scripts re-executing. |
| 54 | + |
| 55 | +**Architecture**: HTTP API that queries data, providing JSON responses. |
| 56 | + |
| 57 | +**Types of events**: |
| 58 | + |
| 59 | +- **Execution**: identifies each re-execution and includes its observed trace messages. |
| 60 | +- **Selection**: identifies when each time the local node updates its selection, including the slot number, block number, and header hash, which is sufficient information for the dapp developer to estimate of the on-going settlement probability for each script execution, according to standard Cardano settlement tables. |
| 61 | +- **Cancellation**: identifies which script executions were undone whenever the local node switches away from the blocks that executed some scripts in the configuration data. |
| 62 | + |
| 63 | +**Endpoints**: |
| 64 | + |
| 65 | +##### GET /events/ |
| 66 | + |
| 67 | +Returns all events with filtering. |
| 68 | + |
| 69 | +**Query Parameters**: |
| 70 | +- `type`: `execution`, `selection`, or `cancellation` (required) |
| 71 | +- `time_range`: ISO 8601 time range (optional) |
| 72 | +- `slot_range`: Slot number range (optional) |
| 73 | +- `limit`: Results per page (default: 50, max: 1000) |
| 74 | +- `offset`: Pagination offset (default: 0) |
| 75 | + |
| 76 | +**Response**: JSON array of all relevant events with basic metadata (block hash, slot, timestamp). |
| 77 | + |
| 78 | +##### GET /events/{ script_hash | name or alias } |
| 79 | + |
| 80 | +Returns all events relevant to the provided `script_hash` or `name` with filtering. |
| 81 | + |
| 82 | +**Query Parameters**: |
| 83 | +- `type`: `execution`, `selection`, or `cancellation` (required) |
| 84 | +- `time_range`: ISO 8601 time range (optional) |
| 85 | +- `slot_range`: Slot number range (optional) |
| 86 | +- `limit`: Results per page (default: 50, max: 1000) |
| 87 | +- `offset`: Pagination offset (default: 0) |
| 88 | + |
| 89 | +**Response**: JSON array of all relevant events to the provided `script_hash` with basic metadata (block hash, slot, timestamp). |
| 90 | + |
| 91 | +##### GET /metrics |
| 92 | + |
| 93 | +Prometheus metrics endpoint exposing operational statistics in standard exposition format. |
| 94 | + |
| 95 | +**Key Metrics**: |
| 96 | +- Scanning: blocks/transactions scanned, scripts per block/transaction |
| 97 | +- Processing: operation durations, unprocessed data backlog, database operations |
| 98 | + - Average block processing time |
| 99 | + - Average script execution time |
| 100 | +- Storage: database size by table, evictions, storage limit hits |
| 101 | +- System Health: active processes, service availability, resources consumption |
| 102 | + |
| 103 | +#### 5. Full Cardano Node Integration |
| 104 | + |
| 105 | +**Purpose**: Provide data for the scanning process. |
| 106 | + |
| 107 | +**Responsibilities**: |
| 108 | + |
| 109 | +- **Validation Service**: Provides Node-to-Client queries for background workers to classify collected data |
| 110 | +- **Canonical Chain State**: Maintains full ledger state to identify which blocks are on the canonical chain |
| 111 | + |
| 112 | +**Configuration**: |
| 113 | + |
| 114 | +- Standard cardano-node with normal network connectivity |
| 115 | +- Maintains full ledger state for validation queries |
| 116 | + |
| 117 | +#### 6. Leash Node-to-Client protocol |
| 118 | + |
| 119 | +**Purpose**: a Node-to-Client protocol that allows to "leash" the node and keep the resource usage under control. |
| 120 | + |
| 121 | +**Details**: TODO: describe the Leash protocol. |
| 122 | + |
| 123 | +#### 7. Configuration map |
| 124 | + |
| 125 | +**Purpose**: allows to user to specify which scripts should be executed under specified `script_hash`. |
| 126 | + |
| 127 | +**Format**: |
| 128 | + |
| 129 | +Each script is specified by: |
| 130 | +- Script hash |
| 131 | +- Name/alias (optional) |
| 132 | +- Either CborHex or file path or plain text uplc |
| 133 | + |
| 134 | +**Example**: |
| 135 | + |
| 136 | +```yaml |
| 137 | +scripts: |
| 138 | + - script_hash: 921169a988ba72ffd6e9c269cadb3b53b5f360ff99f112d9b2ee30c4d74ad88b |
| 139 | + cbor_hex: 73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a804973475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a804973475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a804973475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049 |
| 140 | + |
| 141 | + - script_hash: 622229a988ba72ffd6e9c269cadb3b53b5f360ff99f112d9b2ee30c4d74ad88b |
| 142 | + name: my_script |
| 143 | + path: my_custom_script.json |
| 144 | + |
| 145 | + - script_hash: 777729a988ba72ffd6e9c269cadb3b53b5f360ff99f112d9b2ee30c4d74ad88b |
| 146 | + plain_uplc: | |
| 147 | + (program 0.1.0 (con integer 42)) |
| 148 | +
|
| 149 | +``` |
| 150 | +
|
| 151 | +where `my_custom_script.json`: |
| 152 | + |
| 153 | +```json |
| 154 | +{ |
| 155 | + "type": "PlutusScriptV1", |
| 156 | + "description": "", |
| 157 | + "cborHex": "585e585c01000033322232323233223232322223335300c333500b00a0033004120012009235007009008230024830af38f1ab664908dd3800891a8021a9801000a4c24002400224c44666ae54cdd70010008030028900089100109100090009" |
| 158 | +} |
| 159 | +``` |
| 160 | + |
| 161 | +#### 8. Data storage |
| 162 | + |
| 163 | +**Purpuse**: to save the emitted events for Events API and future analysis. |
| 164 | + |
| 165 | +**Motivation**: the current ledger state is big and we can't rely on RAM only to store the execution results. If a user specifies a popular script that is executed very often we easily can get a memory overflow error. |
| 166 | + |
| 167 | +**Entities**: |
| 168 | + |
| 169 | +Block: |
| 170 | +- `block_number`: Block number |
| 171 | +- `hash`: Header hash |
| 172 | +- `slot`: Slot number |
| 173 | + |
| 174 | +Execution event: |
| 175 | +- `block_number`: Block number |
| 176 | +- `transaction_hash`: Transaction hash |
| 177 | +- `script_hash`: `ScriptHash` |
| 178 | +- `name`: Name or alias (optional) |
| 179 | +- `script_context`: Relevant to the execution `ScriptContext` |
| 180 | +- `trace`: Trace of the execution |
| 181 | + |
| 182 | +Cancellation event: |
| 183 | +- `block_number`: Block number |
| 184 | +- `script_hash`: Script hash that was cancelled |
| 185 | + |
| 186 | +Selection event: |
| 187 | +- `block_number`: Block number |
| 188 | + |
| 189 | +```mermaid |
| 190 | +erDiagram |
| 191 | + EXECUTION_EVENT }o--|| BLOCK : contains |
| 192 | + EXECUTION_EVENT { |
| 193 | + int blockNumber |
| 194 | + binary transactionHash |
| 195 | + binary scriptHash |
| 196 | + string name |
| 197 | + binary scriptContext |
| 198 | + string trace |
| 199 | + } |
| 200 | + BLOCK ||--o{ SELECTION_EVENT : contains |
| 201 | + BLOCK ||--o{ CANCELLATION_EVENT : contains |
| 202 | + BLOCK { |
| 203 | + int blockNumber |
| 204 | + int slotNumber |
| 205 | + binary hash |
| 206 | + } |
| 207 | + SELECTION_EVENT { |
| 208 | + int blockNumber |
| 209 | + } |
| 210 | + CANCELLATION_EVENT { |
| 211 | + int blockNumber |
| 212 | + binary scriptHash |
| 213 | + } |
| 214 | +``` |
0 commit comments