Skip to content

Commit 9620380

Browse files
committed
docs: Add ADR for V3 billing opt-out mechanism
1 parent befa5e1 commit 9620380

1 file changed

Lines changed: 66 additions & 0 deletions

File tree

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# 25. V3 Billing Opt-Out for Node Migration
2+
3+
Date: 2026-02-18
4+
5+
## Status
6+
7+
Accepted
8+
9+
## Context
10+
11+
During the migration from v3 to Mycelium, farmers need a way to signal that their nodes are entering a migration window. Existing workloads on these nodes should not be billed during this period, as the node is transitioning infrastructure.
12+
13+
## Decision
14+
15+
### New Storage Items (pallet-tfgrid)
16+
17+
- **`NodeV3BillingOptOut`**: A `StorageMap<node_id → opted_out_at (Unix seconds)>` tracking which nodes have opted out. Presence in this map is the sole indicator of opt-out status. No storage migration is required as this is an additive change.
18+
- **`AllowedTwinAdmins`**: A `StorageValue<Vec<AccountId>>` listing accounts authorized to deploy on opted-out nodes.
19+
20+
### New Extrinsics (pallet-tfgrid)
21+
22+
| Extrinsic | Origin | Call Index |
23+
|---|---|---|
24+
| `opt_out_of_v3_billing(node_id)` | Farmer (signed) | 43 |
25+
| `add_twin_admin(account)` | Council (`RestrictedOrigin`) | 44 |
26+
| `remove_twin_admin(account)` | Council (`RestrictedOrigin`) | 45 |
27+
28+
Opt-out is one-way and permanent — there is no opt-back-in extrinsic. The `NodeV3BillingOptOut` entry is cleaned up automatically when the node is deleted.
29+
30+
### Deployment Guards (pallet-smart-contract)
31+
32+
`_create_node_contract` and `_create_rent_contract` both check `NodeV3BillingOptOut` before allowing deployment. If the target node has opted out, the caller's `AccountId` must be present in `AllowedTwinAdmins`, otherwise the call fails with `OnlyTwinAdminCanDeployOnThisNode`.
33+
34+
### Billing Suppression (pallet-smart-contract)
35+
36+
In `bill_contract`, a `should_waive_migration_billing` flag is computed by checking `NodeV3BillingOptOut` for the contract's node. When true:
37+
38+
- **`Created` state**: early return, no billing work performed.
39+
- **`GracePeriod` state**: cost is zeroed; `manage_contract_state` runs normally, allowing the contract to be restored to `Created` once the user tops up to cover pre-opt-out overdraft.
40+
- **`Deleted` state**: cost is zeroed; cleanup proceeds normally.
41+
42+
This is distinct from `should_waive_standby_rent` (standby power state, rent contracts only, emits `RentWaived`). The migration billing waiver is silent — no event is emitted because no billing is expected after opt-out.
43+
44+
### New Events (pallet-tfgrid)
45+
46+
- `NodeV3BillingOptedOut { node_id, opted_out_at }` — emitted on successful opt-out.
47+
- `TwinAdminAdded(AccountId)` — emitted when an admin is added.
48+
- `TwinAdminRemoved(AccountId)` — emitted when an admin is removed.
49+
50+
### New Errors
51+
52+
**pallet-smart-contract**
53+
54+
- `OnlyTwinAdminCanDeployOnThisNode` — returned when a non-admin attempts to deploy on an opted-out node.
55+
56+
**pallet-tfgrid**
57+
58+
- `NodeV3BillingOptOutAlreadyEnabled` — returned when `opt_out_of_v3_billing` is called on a node that has already opted out.
59+
- `AlreadyTwinAdmin` — returned when `add_twin_admin` is called for an account already in the admin list.
60+
- `NotTwinAdmin` — returned when `remove_twin_admin` is called for an account not in the admin list, or when the list is empty.
61+
62+
## Consequences
63+
64+
- **No storage migration**: all new storage items are additive.
65+
- **Free migration window**: existing workloads on opted-out nodes accumulate no new charges. Users with pre-existing overdraft (contracts in `GracePeriod`) can still top up to restore their workloads, after which subsequent billing cycles are free.
66+
- **Access control**: only council-approved twin admins can deploy new workloads on opted-out nodes.

0 commit comments

Comments
 (0)