Revise SWIP-39 for clarity and detail enhancement#87
Conversation
Refine the SWIP-39 document to clarify the protocol mechanism for balanced neighbourhood registry and node assignment. Enhance sections on architecture, model, and data structure to improve understanding of the system's operational principles.
There was a problem hiding this comment.
Pull request overview
This PR rewrites SWIP-39 to more clearly specify the balanced neighbourhood registry mechanism, focusing on formalizing the model, the enforced structural invariant, and the protocol flow for assignment and rebalancing.
Changes:
- Replaces the previous “Architecture/Specification” narrative with a more formal “Model and Notation” plus an explicit structural invariant.
- Specifies a trie-based data structure with subtree counters to support logarithmic-time assignment and donor selection.
- Adds clearer sections for entropy derivation, deregistration/rebalancing, depth reduction, and protocol diagrams (mermaid).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| b_i\gg=7-(d\mod 8) | ||
| \rho = H(\text{blockhash}(h+1) \parallel a^\Xi \parallel h), | ||
| $$ | ||
|
|
There was a problem hiding this comment.
The hash function H is used in the entropy definition but never defined in the document. Please explicitly specify what H is (e.g., Keccak-256 over ABI-encoded values) so the randomness derivation is unambiguous and reproducible across implementations.
| Here, $H$ denotes the Keccak-256 hash function applied to the byte string obtained by ABI-encoding and concatenating $\text{blockhash}(h+1)$, $a^\Xi$, and $h$ in that order. |
| The system enforces the condition | ||
|
|
||
| #### Deposit | ||
| In order for a node to get its address registered, an amount of ${\$_a}$ must be deposited which is non-refundable. | ||
| $$ | ||
| \forall i, \quad I[2i] \neq 0 \;\lor\; I[2i+1] \neq 0, | ||
| $$ | ||
|
|
||
| #### Uniqueness | ||
| In order to prevent repeated trials, each node must be registered only once. | ||
| which ensures that every prefix of length $d-1$ contains at least one node. This invariant defines the admissible states of the system. |
There was a problem hiding this comment.
The structural invariant quantifies over i without defining its domain. To avoid ambiguity, constrain i to the valid pair-index range (e.g., i ∈ {0, …, 2^{d-1}-1}) and clarify that I[2i]/I[2i+1] correspond to the two leaf slots sharing the same (d-1)-bit prefix.
| Let $M = 2^d - N$ denote the number of free slots. A node computes | ||
|
|
||
| $$ | ||
| \forall\ 0\leq i < |R_d|,\quad R_d[i]=2i+1-b_i | ||
| k = \rho \bmod M. | ||
| $$ | ||
|
|
||
| The assigned index is determined by descending the trie. At a node $v$, let $F(v_L)$ denote the number of free slots in the left subtree. If $k < F(v_L)$, the traversal continues to the left child. Otherwise, the traversal continues to the right child with updated rank $k \leftarrow k - F(v_L)$. This procedure terminates at a leaf index $i$ such that $I[i] = 0$. |
There was a problem hiding this comment.
In the assignment section, M = 2^d - N can be 0 when N = 2^d, making k = ρ mod M undefined. The spec should state the precondition N < 2^d for running assignment (and that d must be increased before accepting another node), or otherwise define how d/M are updated to ensure M ≥ 1.
| ## Interface | ||
|
|
||
| #### Checking the overlay | ||
| | Function | Description | | ||
| |----------|------------| | ||
| | Register(a) | Records commitment and blockheight | | ||
| | GetPrefix(a) | Returns assigned index | | ||
| | Validate(a,o) | Verifies overlay matches assigned index | | ||
| | Insert(a,o) | Inserts node and updates structure | | ||
| | Deregister(a) | Initiates removal | | ||
| | Remove(i) | Removes node from index | | ||
| | Rebalance(i) | Repairs invariant | | ||
|
|
||
| The overlay (obtained by mining the nonce) is checked to fall in the correct neighbourhood r: | ||
| The check validates the address $a^O_n$ if and only if: | ||
| --- | ||
|
|
||
| $$ | ||
| r=a^O_n\gg(255-d) | ||
| $$ | ||
| ## Sequence Diagram | ||
|
|
||
| ```mermaid | ||
| sequenceDiagram | ||
| participant Client | ||
| participant Registry | ||
| participant Trie | ||
|
|
||
| Client->>Registry: Register(a) | ||
| Registry-->>Client: prefix | ||
| Client->>Registry: Validate(a,o) | ||
| Registry->>Trie: update(F,E) | ||
| Client->>Registry: Deregister(a) | ||
| Registry->>Trie: check invariant | ||
| Registry->>Trie: select donor | ||
| Registry->>Trie: update | ||
| ``` |
There was a problem hiding this comment.
The Interface table says Register(a) only records commitment, but the Sequence Diagram shows Register(a) returning a prefix. Either update the interface description to reflect the returned value, or adjust the sequence to call GetPrefix(a) explicitly so the protocol flow is consistent.
There was a problem hiding this comment.
@copilot open a new pull request to apply changes based on this feedback
Refine the SWIP-39 document to clarify the protocol mechanism for balanced neighbourhood registry and node assignment. Enhance sections on architecture, model, and data structure to improve understanding of the system's operational principles.