docs: add multi-operator governance section
This commit is contained in:
102
ARCHITECTURE.md
102
ARCHITECTURE.md
@@ -42,7 +42,49 @@ There is no bootstrap mechanism for SDK clients. They must be explicitly approve
|
||||
|
||||
---
|
||||
|
||||
## 3. Server Identity
|
||||
## 3. Multi-Operator Governance
|
||||
|
||||
When more than one User Agent is registered, the vault is treated as having multiple operators. In that mode, sensitive actions are governed by voting rather than by a single operator decision.
|
||||
|
||||
### 3.1 Voting Rules
|
||||
|
||||
Voting is based on the total number of registered operators:
|
||||
|
||||
- **1 operator:** no vote is needed; the single operator decides directly.
|
||||
- **2 operators:** full consensus is required; both operators must approve.
|
||||
- **3 or more operators:** quorum is `floor(N / 2) + 1`.
|
||||
|
||||
Examples:
|
||||
|
||||
- **3 operators:** 2 approvals required
|
||||
- **4 operators:** 3 approvals required
|
||||
|
||||
### 3.2 Actions Requiring a Vote
|
||||
|
||||
In multi-operator mode, a successful vote is required for:
|
||||
|
||||
- approving new SDK clients
|
||||
- granting an SDK client visibility to a wallet
|
||||
- approving a one-off transaction
|
||||
- approving creation of a persistent grant
|
||||
- approving server updates
|
||||
- updating Shamir secret-sharing parameters
|
||||
|
||||
### 3.3 Special Rule for Key Rotation
|
||||
|
||||
Key rotation always requires full quorum, regardless of the normal voting threshold.
|
||||
|
||||
This is stricter than ordinary governance actions because rotating the root key requires every operator to participate in coordinated share refresh/update steps. The root key itself is not redistributed directly, but each operator's share material must be changed consistently.
|
||||
|
||||
### 3.4 Root Key Custody
|
||||
|
||||
When the vault has multiple operators, the vault root key is protected using Shamir secret sharing.
|
||||
|
||||
This ensures that root-key recovery and governance-sensitive changes are aligned with the multi-operator model rather than delegated to a single operator-held secret.
|
||||
|
||||
---
|
||||
|
||||
## 4. Server Identity
|
||||
|
||||
The server proves its identity using TLS with a self-signed certificate. The TLS private key is generated on first run and is long-term; no rotation mechanism exists yet due to the complexity of multi-peer coordination.
|
||||
|
||||
@@ -55,9 +97,9 @@ Peers verify the server by its **public key fingerprint**:
|
||||
|
||||
---
|
||||
|
||||
## 4. Key Management
|
||||
## 5. Key Management
|
||||
|
||||
### 4.1 Key Hierarchy
|
||||
### 5.1 Key Hierarchy
|
||||
|
||||
There are three layers of keys:
|
||||
|
||||
@@ -72,19 +114,19 @@ This layered design enables:
|
||||
- **Password rotation** without re-encrypting every wallet key (only the root key is re-encrypted).
|
||||
- **Root key rotation** without requiring the user to change their password.
|
||||
|
||||
### 4.2 Encryption at Rest
|
||||
### 5.2 Encryption at Rest
|
||||
|
||||
The database stores everything in encrypted form using symmetric AEAD. The encryption scheme is versioned to support transparent migration — when the vault unseals, Arbiter automatically re-encrypts any entries that are behind the current scheme version. See [IMPLEMENTATION.md](IMPLEMENTATION.md) for the specific scheme and versioning mechanism.
|
||||
|
||||
---
|
||||
|
||||
## 5. Vault Lifecycle
|
||||
## 6. Vault Lifecycle
|
||||
|
||||
### 5.1 Sealed State
|
||||
### 6.1 Sealed State
|
||||
|
||||
On boot, the root key is encrypted and the server cannot perform any signing operations. This state is called **Sealed**.
|
||||
|
||||
### 5.2 Unseal Flow
|
||||
### 6.2 Unseal Flow
|
||||
|
||||
To transition to the **Unsealed** state, a User Agent must provide the password:
|
||||
|
||||
@@ -95,7 +137,7 @@ To transition to the **Unsealed** state, a User Agent must provide the password:
|
||||
- **Success:** The root key is decrypted and placed into a hardened memory cell. The server transitions to `Unsealed`. Any entries pending encryption scheme migration are re-encrypted.
|
||||
- **Failure:** The server returns an error indicating the password is incorrect.
|
||||
|
||||
### 5.3 Memory Protection
|
||||
### 6.3 Memory Protection
|
||||
|
||||
Once unsealed, the root key must be protected in memory against:
|
||||
|
||||
@@ -107,9 +149,9 @@ See [IMPLEMENTATION.md](IMPLEMENTATION.md) for the current and planned memory pr
|
||||
|
||||
---
|
||||
|
||||
## 6. Permission Engine
|
||||
## 7. Permission Engine
|
||||
|
||||
### 6.1 Fundamental Rules
|
||||
### 7.1 Fundamental Rules
|
||||
|
||||
- SDK clients have **no access by default**.
|
||||
- Access is granted **explicitly** by a User Agent.
|
||||
@@ -119,11 +161,45 @@ Each blockchain requires its own policy system due to differences in static tran
|
||||
|
||||
Arbiter is also responsible for ensuring that **transaction nonces are never reused**.
|
||||
|
||||
### 6.2 EVM Policies
|
||||
### 7.2 EVM Policies
|
||||
|
||||
Every EVM grant is scoped to a specific **wallet** and **chain ID**.
|
||||
|
||||
#### 6.2.1 Transaction Sub-Grants
|
||||
#### 7.2.0 Transaction Signing Sequence
|
||||
|
||||
The high-level interaction order is:
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
autonumber
|
||||
actor SDK as SDK Client
|
||||
participant Server
|
||||
participant UA as User Agent
|
||||
|
||||
SDK->>Server: SignTransactionRequest
|
||||
Server->>Server: Resolve wallet and wallet visibility
|
||||
alt Visibility approval required
|
||||
Server->>UA: Ask for wallet visibility approval
|
||||
UA-->>Server: Vote result
|
||||
end
|
||||
Server->>Server: Evaluate transaction
|
||||
Server->>Server: Load grant and limits context
|
||||
alt Grant approval required
|
||||
Server->>UA: Ask for execution / grant approval
|
||||
UA-->>Server: Vote result
|
||||
opt Create persistent grant
|
||||
Server->>Server: Create and store grant
|
||||
end
|
||||
Server->>Server: Retry evaluation
|
||||
end
|
||||
critical Final authorization path
|
||||
Server->>Server: Check limits and record execution
|
||||
Server-->>Server: Signature or evaluation error
|
||||
end
|
||||
Server-->>SDK: Signature or error
|
||||
```
|
||||
|
||||
#### 7.2.1 Transaction Sub-Grants
|
||||
|
||||
Arbiter maintains an ever-expanding database of known contracts and their ABIs. Based on contract knowledge, transaction requests fall into three categories:
|
||||
|
||||
@@ -147,7 +223,7 @@ Available restrictions:
|
||||
|
||||
These transactions have no `calldata` and therefore cannot interact with contracts. They can be subject to the same volume and rate restrictions as above.
|
||||
|
||||
#### 6.2.2 Global Limits
|
||||
#### 7.2.2 Global Limits
|
||||
|
||||
In addition to sub-grant-specific restrictions, the following limits can be applied across all grant types:
|
||||
|
||||
|
||||
@@ -128,6 +128,52 @@ The central abstraction is the `Policy` trait. Each implementation handles one s
|
||||
4. **Evaluate** — `Policy::evaluate` checks the decoded meaning against the grant's policy-specific constraints and returns any violations.
|
||||
5. **Record** — If `RunKind::Execution` and there are no violations, the engine writes to `evm_transaction_log` and calls `Policy::record_transaction` for any policy-specific logging (e.g., token transfer volume).
|
||||
|
||||
The detailed branch structure is shown below:
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[SDK Client sends sign transaction request] --> B[Server resolves wallet]
|
||||
B --> C{Wallet exists?}
|
||||
|
||||
C -- No --> Z1[Return wallet not found error]
|
||||
C -- Yes --> D[Check SDK client wallet visibility]
|
||||
|
||||
D --> E{Wallet visible to SDK client?}
|
||||
E -- No --> F[Start wallet visibility voting flow]
|
||||
F --> G{Vote approved?}
|
||||
G -- No --> Z2[Return wallet access denied error]
|
||||
G -- Yes --> H[Persist wallet visibility]
|
||||
E -- Yes --> I[Classify transaction meaning]
|
||||
H --> I
|
||||
|
||||
I --> J{Meaning supported?}
|
||||
J -- No --> Z3[Return unsupported transaction error]
|
||||
J -- Yes --> K[Find matching grant]
|
||||
|
||||
K --> L{Grant exists?}
|
||||
L -- Yes --> M[Check grant limits]
|
||||
L -- No --> N[Start execution or grant voting flow]
|
||||
|
||||
N --> O{User-agent decision}
|
||||
O -- Reject --> Z4[Return no matching grant error]
|
||||
O -- Allow once --> M
|
||||
O -- Create grant --> P[Create grant with user-selected limits]
|
||||
P --> Q[Persist grant]
|
||||
Q --> M
|
||||
|
||||
M --> R{Limits exceeded?}
|
||||
R -- Yes --> Z5[Return evaluation error]
|
||||
R -- No --> S[Record transaction in logs]
|
||||
S --> T[Produce signature]
|
||||
T --> U[Return signature to SDK client]
|
||||
|
||||
note1[Limit checks include volume, count, and gas constraints.]
|
||||
note2[Grant lookup depends on classified meaning, such as ether transfer or token transfer.]
|
||||
|
||||
K -. uses .-> note2
|
||||
M -. checks .-> note1
|
||||
```
|
||||
|
||||
### Policy Trait
|
||||
|
||||
| Method | Purpose |
|
||||
|
||||
Reference in New Issue
Block a user