Skip to content

Commit 3ea77ca

Browse files
committed
docs: update ADR 0026
1 parent 9f273f8 commit 3ea77ca

1 file changed

Lines changed: 36 additions & 39 deletions

File tree

docs/architecture/0026-v3-node-opt-out-metadata.md

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ Per-node keying is more granular, consistent with the existing opt-out model, an
4545

4646
### New Storage Item (pallet-tfgrid)
4747

48-
```
48+
```rust
4949
NodeV3OptOutMetadata: StorageMap<node_id (u32) → BoundedVec<u8, 256>>
5050
```
5151

@@ -69,15 +69,14 @@ NodeV3OptOutMetadata: StorageMap<node_id (u32) → BoundedVec<u8, 256>>
6969

7070
**Behaviour:**
7171

72-
- If `metadata` is non-empty: upsert `NodeV3OptOutMetadata[node_id]`, emit `NodeV3OptOutMetadataSet { node_id, metadata }`.
73-
- If `metadata` is empty: remove `NodeV3OptOutMetadata[node_id]`, emit `NodeV3OptOutMetadataCleared { node_id }`.
72+
- If `metadata` is non-empty: upsert `NodeV3OptOutMetadata[node_id]`, emit `NodeV3OptOutMetadataUpdated { node_id, metadata: Some(metadata) }`.
73+
- If `metadata` is empty: remove `NodeV3OptOutMetadata[node_id]`, emit `NodeV3OptOutMetadataUpdated { node_id, metadata: None }`.
7474

7575
The extrinsic is idempotent and can be called repeatedly to update or clear the metadata. Only the farm owner can call it, matching the ownership model of `opt_out_of_v3_billing`.
7676

7777
### New Events (pallet-tfgrid)
7878

79-
- `NodeV3OptOutMetadataSet { node_id: u32, metadata: Vec<u8> }` — emitted when metadata is set or updated.
80-
- `NodeV3OptOutMetadataCleared { node_id: u32 }` — emitted when metadata is explicitly cleared.
79+
- `NodeV3OptOutMetadataUpdated { node_id: u32, metadata: Option<Vec<u8>> }` — emitted when metadata is set, updated, or cleared. `Some(bytes)` indicates set/update, `None` indicates clear.
8180

8281
### New Errors (pallet-tfgrid)
8382

@@ -88,21 +87,20 @@ The extrinsic is idempotent and can be called repeatedly to update or clear the
8887

8988
### Full opt-out and linkage sequence
9089

91-
```
92-
Farmer
93-
94-
├─1─► opt_out_of_v3_billing(node_id)
95-
│ ├── Guard: caller twin == farm owner twin
96-
│ ├── Guard: node not already opted out
97-
│ ├── Insert: NodeV3BillingOptOut[node_id] = now()
98-
│ └── Emit: NodeV3BillingOptedOut { node_id, opted_out_at }
99-
100-
└─2─► set_node_v3_opt_out_metadata(node_id, v4_account_bytes)
101-
├── Guard: caller twin == farm owner twin
102-
├── Guard: NodeV3BillingOptOut[node_id] exists
103-
├── Guard: len(metadata) ≤ 256
104-
├── Insert: NodeV3OptOutMetadata[node_id] = v4_account_bytes
105-
└── Emit: NodeV3OptOutMetadataSet { node_id, metadata }
90+
```mermaid
91+
graph TD
92+
A[Farmer] -->|1| B[opt_out_of_v3_billing(node_id)]
93+
B --> C[Guard: caller twin == farm owner twin]
94+
C --> D[Guard: node not already opted out]
95+
D --> E[Insert: NodeV3BillingOptOut[node_id] = now()]
96+
E --> F[Emit: NodeV3BillingOptedOut { node_id, opted_out_at }]
97+
98+
A -->|2| G[set_node_v3_opt_out_metadata(node_id, v4_account_bytes)]
99+
G --> H[Guard: caller twin == farm owner twin]
100+
H --> I[Guard: NodeV3BillingOptOut[node_id] exists]
101+
I --> J[Guard: len(metadata) ≤ 256]
102+
J --> K[Insert: NodeV3OptOutMetadata[node_id] = v4_account_bytes]
103+
K --> L[Emit: NodeV3OptOutMetadataUpdated { node_id, metadata: Some(v4_account_bytes) }]
106104
```
107105

108106
After step 2, `NodeV3OptOutMetadata[node_id]` holds the farmer's v4 account address (or any agreed-upon linking payload).
@@ -111,26 +109,25 @@ After step 2, `NodeV3OptOutMetadata[node_id]` holds the farmer's v4 account addr
111109

112110
When a node registers or reports uptime on the v4 marketplace, the marketplace verifier must:
113111

112+
```mermaid
113+
graph TD
114+
A[V4 Marketplace Verifier] -->|1| B[Query TFChain: NodeV3BillingOptOut[node_id]]
115+
B --> C{None?}
116+
C -->|Yes| D[Node is NOT in migration window, reject]
117+
C -->|Some(opted_out_at)| E[Node is opted out, continue]
118+
119+
E -->|2| F[Query TFChain: NodeV3OptOutMetadata[node_id]]
120+
F --> G{None?}
121+
G -->|Yes| H[Treat as unlinked]
122+
G -->|Some(metadata)| I[Decode as v4 account address]
123+
124+
I -->|3| J[Verify v4 account matches node's reported account]
125+
J --> K{Match?}
126+
K -->|Mismatch| L[Reject; farmer must update metadata]
127+
K -->|Match| M[Node verified as legitimately transitioned]
128+
129+
M -->|4| N[Attribute node resources and uptime to verified v4 account]
114130
```
115-
V4 Marketplace Verifier
116-
117-
├─1─► Query TFChain: NodeV3BillingOptOut[node_id]
118-
│ ├── None → node is NOT in migration window, reject or handle as active v3 node
119-
│ └── Some(opted_out_at) → node is opted out, continue
120-
121-
├─2─► Query TFChain: NodeV3OptOutMetadata[node_id]
122-
│ ├── None → farmer has not yet linked a v4 account, treat as unlinked
123-
│ └── Some(metadata) → decode as v4 account address
124-
125-
├─3─► Verify that the v4 account in metadata matches the account
126-
│ that the node is reporting from on the v4 network
127-
│ ├── Mismatch → reject; farmer must update metadata or re-register
128-
│ └── Match → node is verified as legitimately transitioned
129-
130-
└─4─► Attribute node resources and uptime to the verified v4 account
131-
```
132-
133-
This means the v4 marketplace does **not** trust the node's self-reported identity alone — it cross-checks against the on-chain metadata set by the farm owner, which is the authoritative source.
134131

135132
### Metadata Content Convention
136133

0 commit comments

Comments
 (0)