Skip to content

docs(blockchain): rename locked notes to service notes - #423

Open
thomaslavaur wants to merge 1 commit into
masterfrom
tl/service_notes
Open

docs(blockchain): rename locked notes to service notes#423
thomaslavaur wants to merge 1 commit into
masterfrom
tl/service_notes

Conversation

@thomaslavaur

@thomaslavaur thomaslavaur commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Authors: Thomas Lavaur thomas@logos.co

The Mantle Ledger tracks three kinds of notes, regular notes, locked notes and channel notes, and only one of them was named after the state it is left in rather than after the role it plays. Channel notes are unspendable too, so "locked" never distinguished the two. This PR renames the kind, its state dictionary, its class and its identifier field into service note, service_notes, ServiceNote and service_note_id across the six blockchain specifications that use them.

Reviewer Orientation

Read Motivation first, then check the rename is complete rather than reading each document top to bottom. Nothing here changes a wire layout, a hash preimage or a validation rule, so the review question is whether the new name is the right one and whether any occurrence was missed.

# Priority Document / Change What to look for
1 Medium Start here, Mantle: the note kind and its state the renamed section and its anchor, the state dictionary, and the spendability sentence that no longer says "locked"
2 Medium SDP: the identifier field service_note_id in the three structures that carry it, and the two sentences that now say where the stake is locked
3 Low Mantle Transaction Encoding: the encoding production that only the production name changed, the SDPDeclare and SDPWithdraw field order and widths being untouched
4 Low Gas Cost Determination: the Input Gas description that the Input Gas now describes both note kinds the spendability check rejects, which is what Mantle has always asserted
5 Low Genesis Block and Cryptoeconomics skim, terminology alignment only

Status tracker

  • 🚧 Raw (make sure that all below is completed)
    • Template applied
    • Authors filled in
    • Authors agree on the RFC content
  • 📘 Draft (make sure that all below is completed)
    • All dependent specifications added (Notion backlinks checked)
    • Specifications to deprecate added, if applicable
    • Specifications to retire added, if applicable
    • Research Lead assigned, or Project Lead assigned if the Research Lead is an author
    • Relevant Research Domain Experts assigned (cannot be authors)
  • ⚙️ Verified (make sure that all below is completed)
    • Researchers’ comments addressed
    • All logical changes documented
    • All Research reviewers approve the latest version
    • Engineering Lead assigned
    • Relevant Engineering Domain Experts assigned
  • 🔀 Merged (make sure that all below is completed)
    • Engineers’ comments addressed
    • Every change added to the change log
    • All Engineering reviewers approve the latest version
    • Specification version numbers assigned
    • Implementation reviewed and merged
    • Branch updated to master and all conflicts resolved
    • PR merged

Change log

Revision Description Date
v1 Initial PR description 2026-08-27

Motivation

The Mantle Ledger tracks three kinds of notes and names two of them after what they are for, channel notes hold channel funds and regular notes hold everything else, while the third was named after what happens to it. A locked note is a note a Service Declaration uses as collateral, and locking is the mechanism that keeps it there, not the reason it exists. The name describes the side effect and leaves the purpose to be inferred.

That inversion costs the reader twice. Channel notes are unspendable for as long as they represent channel funds, so a rule that says a note is spendable when it is "not locked" reads as if it covered them, while the ledger check it describes rejects service notes and channel notes through two separate assertions. And a reader meeting locked_note_id in a DeclarationMessage learns that the note is locked, which the declaration itself already implies, rather than that it is the note carrying the service collateral.

Naming the kind after its role removes both problems. service note says what the note is for, leaves "locked" to describe the state a Declare Operation puts it in and a Withdraw Operation takes it out of, and lets the spendability rule name the two kinds it rejects instead of reusing a state word that applies to both.

Proposal

The note kind previously called a locked note is called a service note. The rename is uniform and mechanical: LockedNote becomes ServiceNote, locked_notes becomes service_notes, locked_note_id becomes service_note_id, the LockedNoteId production of the SDP Operations becomes ServiceNoteId, and the Locked notes section of Mantle becomes Service notes.

Only the naming changes. No structure gains or loses a field, no field changes width, position or order, no hash preimage changes, and no validation or execution step is added, removed or reordered. locked_note_id was already absent from the declaration_id preimage, so the identifier of a declaration is unaffected by the rename of the field.

Alongside the rename, the prose that leaned on "locked" to mean "is a service note" is restated in terms of the kind: the Mantle spendability sentence and the Input Gas description of Gas Cost Determination now name the note kinds the check rejects, and the SDP and Cryptoeconomics sentences about the minimum stake now say that the stake is locked in a service note.

Discussion

Why service note rather than collateral note or stake note

The three candidates all name the role. collateral note describes the function accurately but is narrower than the mechanism: the note is a Service Declaration's collateral today, and the kind is defined by which registry holds it rather than by what the registry is used for. stake note collides with Proof of Stake, where every aged note in the ledger is stake, service notes included, since a service note keeps participating in the leadership lottery while it is locked. service note is the one that names the thing the note is bound to, matches the ServiceType it is declared against, and sits next to channel note as a parallel construction, both being a note kind named after the subsystem holding it.

Backwards compatibility

None is at stake. The rename touches identifiers and prose in specification documents, and every wire format, preimage and rule they define is byte-identical before and after. An implementation built against the previous revision of these documents conforms to this one without a change, and the corresponding source identifiers can be renamed at leisure rather than as a condition of conformance.

What was deliberately left alone

  • The verb. Declaring still locks the note and withdrawing still unlocks it. Locked remains the right word for the state, and the SDP withdrawal text that says the stake is unlocked at epoch e+2 is unchanged.
  • The two appendix RFCs under mantle-transaction-encoding/appendices/ keep the historical name. They record proposals as they were accepted and are not living specifications.
  • Cryptarchia v1 contains no occurrence on master. The open fast bootstrapping work adds locked_notes to the Epoch State Root, along with a sdp_locked_note_hash function and a LOCKED_NOTE_HASH_V1 domain separation tag. Whichever of the two merges second carries the rename, and the two tags are the part that must not be missed, being hashed rather than merely written.

Details

1. The note kind and its state

Mantle owns the definition. The section and its anchor:

-### Locked notes
+### Service notes

-Locked notes are special notes in Mantle that serve as collateral for Service Declarations. A note can become locked after executing a Declare Operation, preventing it from being spent until explicitly released through a Withdraw Operation. The system maintains a mapping of locked note IDs to their supporting declarations.
+Service notes are special notes in Mantle that serve as collateral for Service Declarations. A note can become a service note after being locked by executing a Declare Operation, preventing it from being spent until explicitly released through a Withdraw Operation. The system maintains a mapping of service note IDs to their supporting declarations.

The SDP state validators keep, and the class it holds:

-locked_notes: dict[NoteID, LockedNote]
+service_notes: dict[NoteID, ServiceNote]
 declarations: dict[DeclarationID, DeclarationInfo]

-class LockedNote:
+class ServiceNote:
     declarations: set[DeclarationID]

The Ledger field, and the spendability rule that no longer reuses a state word covering both unspendable kinds:

 class Ledger:
     notes: list[Note]
-    locked_notes: dict[NoteId, LockedNote]
+    service_notes: dict[NoteId, ServiceNote]
     channel_notes: dict[NoteId, ChannelId]
-A note is spendable if and only if it exists, it is not spent or locked.
+A note is spendable if and only if it exists, it is not spent or a service note.
-            # Check that each note is individualy not locked, for the correct channel and unspent
+            # Check that each note is individualy not a service note, for the correct channel and unspent
             for note_id in inputs:
                 assert ledger.is_unspent(note_id)
-                assert note_id not in locked_notes
+                assert note_id not in service_notes
                 # ... unchanged channel checks elided

The two SDP Operation validation steps that named the state rather than the kind, both rules unchanged:

-  5. Ensure the note has not already been locked for this service.
+  5. Ensure the note has not already been used for this service.
-  1. Ensure that the locked note exists, is locked and bound to this declaration.
+  1. Ensure that the service note exists and is bound to this declaration.

The remaining occurrences in Mantle are the same rename applied to the DeclarationInfo, DeclarationMessage and WithdrawMessage fields, to the SDP_DECLARE, SDP_WITHDRAW and SDP epoch finalization pseudocode, to the worked examples, and to the test vector note recording that the declaration_id preimage excludes the field.

2. The identifier field

SDP carries the field in DeclarationMessage, DeclarationInfo and WithdrawMessage, identically in each:

 class DeclarationMessage:
     service_type: ServiceType
     locators: list[Locator]
     provider_id: Ed25519PublicKey
-    locked_note_id: NoteId
+    service_note_id: NoteId
     zk_id: ZkPublicKey

The two sentences that described the collateral without naming its kind:

-Before being admitted to the repository, the validator proves that it locked at least a minimum stake.
+Before being admitted to the repository, the validator proves that it locked at least a minimum stake through a service note.

-- **Declare:** A node sends a declaration that confirms its willingness to provide a specific service, which is confirmed by locking a stake above a certain threshold.
+- **Declare:** A node sends a declaration that confirms its willingness to provide a specific service, which is confirmed by locking a stake above a certain threshold in a service note.

3. The encoding production

Mantle Transaction Encoding renames the production and the two references to it. The field order, the widths and the encoded bytes of SDPDeclare and SDPWithdraw are unchanged:

-SDPDeclare    = ServiceType Locators ProviderId ZkId LockedNoteId
+SDPDeclare    = ServiceType Locators ProviderId ZkId ServiceNoteId
 ServiceType   = Byte          ; 0 = BN
 # ... unchanged productions elided
-LockedNoteId  = NoteId
+ServiceNoteId = NoteId

-SDPWithdraw   = DeclarationId Nonce LockedNoteId
+SDPWithdraw   = DeclarationId Nonce ServiceNoteId

4. The Input Gas description

Gas Cost Determination described the Input Gas as covering a check that the note is "not locked", which named one of the two kinds the spendability check rejects. It now names both, matching what Mantle asserts:

-Input gas covers the computational cost of verifying that one Note Id exists in the Ledger and is not locked.
+Input gas covers the computational cost of verifying that one Note Id exists in the Ledger and is not a service or channel note.

-- Verification that the note is unlocked: negligible.
+- Verification that the note is not a channel or service note: negligible.

The gas amounts are unchanged. Both checks were already negligible and both were already performed.

The SDP Declaration and SDP Withdraw breakdowns are the same rename applied to their bullets, with Locking the note restated as Register the note as a service note, which is the operation the bullet was already pricing.

Chores

  • Terminology alignment in Genesis Block, the service_note_id of the two Blend declaration snippets and the paragraph describing which note a Genesis declaration names.
  • Terminology alignment in Cryptoeconomics, the Minimum Stake sentence now saying that the tokens are locked in a service note.
  • Revision history rows: 1.11.1 in Mantle, 1.4.2 in SDP, 1.6.1 in Mantle Transaction Encoding, 1.5.2 in Gas Cost Determination, 1.1.5 in Genesis Block, 1.2.2 in Cryptoeconomics.

Implementation

  • Rename the ledger state and its type, locked_notes into service_notes and LockedNote into ServiceNote
  • Rename the locked_note_id field of the declaration message, the withdraw message and the stored declaration into service_note_id, including its serialization and deserialization
  • Confirm the declaration_id preimage is untouched by the field rename, the note identifier not being part of it
  • Confirm the encoded bytes of SDP_DECLARE and SDP_WITHDRAW are unchanged, the existing test vectors passing without regeneration
  • Verify the implementation matches this specification

Affected Specifications

Specification Status Note
Mantle Modified version 1.11.1, the note kind, its section anchor, the ledger state and the SDP Operations
Service Declaration Protocol Modified version 1.4.2, the service_note_id field and the two minimum stake sentences
Mantle Transaction Encoding Modified version 1.6.1, the ServiceNoteId production name only
[Analysis] Gas Cost Determination Modified version 1.5.2, the Input Gas, SDP Declaration and SDP Withdraw descriptions
Bedrock Genesis Block Modified version 1.1.5, terminology only
[Overview] Cryptoeconomics Modified version 1.2.2, terminology only
Cryptarchia v1 Unmodified flagged for reviewer attention, no occurrence on master, but the open fast bootstrapping work adds locked_notes, sdp_locked_note_hash and the LOCKED_NOTE_HASH_V1 and LOCKED_NOTE_DICT_HASH_V1 tags to the Epoch State Root

Version numbers to watch when merging: Mantle Transaction Encoding is at 1.6.0 as of the channel configuration lineage PR and Mantle at 1.11.0, so both rows renumber if another PR lands first.

@madxor madxor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants