diff --git a/SWIPs/assets/swip-27/README.md b/SWIPs/assets/swip-27/README.md new file mode 100644 index 0000000..8ebe617 --- /dev/null +++ b/SWIPs/assets/swip-27/README.md @@ -0,0 +1,146 @@ +# Protocol Improvements Report: Old vs. New Swarm Protobufs + +## Table of Contents + +| Protocol | Description | +|----------|-------------| +| [common.proto](./common.proto) | Common types used across multiple protocols | +| [handshake.proto](./handshake.proto) | Node connection establishment protocol | +| [headers.proto](./headers.proto) | Protocol for transmitting metadata headers | +| [hive.proto](./hive.proto) | Peer discovery and sharing protocol | +| [pingpong.proto](./pingpong.proto) | Simple connectivity testing protocol | +| [pricing.proto](./pricing.proto) | Payment threshold announcement protocol | +| [pseudosettle.proto](./pseudosettle.proto) | Lightweight settlement protocol | +| [pullsync.proto](./pullsync.proto) | Protocol for syncing chunks between nodes | +| [pushsync.proto](./pushsync.proto) | Protocol for distributing new chunks | +| [retrieval.proto](./retrieval.proto) | Protocol for retrieving chunks | +| [status.proto](./status.proto) | Node status reporting protocol | +| [swap.proto](./swap.proto) | Token-based settlement protocol | + +## Executive Summary +The new Swarm protocol definitions represent a significant evolution from the older versions, with improvements in organization, consistency, error handling, and documentation. These changes enhance maintainability, interoperability, and developer experience. + +## Key Improvements + +### 1. Unified Message Type System +**Before**: Protocol messages were defined independently with inconsistent structures. +**After**: Introduction of a common `Chunk` message type in `common.proto` that standardizes chunk representation across all protocols. + +```diff +- // Different chunk representations in each protocol +- message Delivery { +- bytes Address = 1; +- bytes Data = 2; +- bytes Stamp = 3; +- } + ++ // Standardized chunk representation ++ message Chunk { ++ ChunkType chunk_type = 1; ++ uint32 version = 2; ++ bytes header = 3; ++ bytes payload = 4; ++ bytes proof = 5; ++ } +``` + +### 2. Consistent Error Handling +**Before**: Error handling varied across protocols with string-based errors (`string Err`). +**After**: Standardized error model with a common `Error` type that includes both error codes and messages. + +```diff +- // String-based error handling +- message Receipt { +- // ... +- string Err = 4; +- } + ++ // Structured error handling ++ message Error { ++ uint32 code = 1; ++ string message = 2; ++ } +``` + +### 3. Message Type Hierarchies +**Before**: Flat message structures without protocol organization. +**After**: Introduction of message type enums and wrapper messages, creating clear protocol hierarchies. + +```diff +- // Flat message structures +- message Payment { /* ... */ } +- message PaymentAck { /* ... */ } + ++ // Organized message hierarchies ++ enum PseudoSettleMessageType { ++ PAYMENT = 0; ++ PAYMENT_ACK = 1; ++ } ++ ++ message PseudoSettleMessage { ++ PseudoSettleMessageType type = 1; ++ oneof message { ++ Payment payment = 2; ++ PaymentAck payment_ack = 3; ++ } ++ } +``` + +### 4. Field Naming Standardization +**Before**: Inconsistent field naming with mixed case (e.g., `bytes Address`). +**After**: Standardized lowercase snake_case field names following protobuf best practices (e.g., `bytes chunk_addr`). + +### 5. Field Separation and Specialization +**Before**: Mixed functionality in single messages. +**After**: Clear separation of concerns with specialized subtypes. + +```diff +- // Mixed success/error in one message +- message Receipt { +- bytes Address = 1; +- bytes Signature = 2; +- bytes Nonce = 3; +- string Err = 4; +- } + ++ // Clear separation with oneof ++ message Receipt { ++ bytes chunk_addr = 1; ++ oneof result { ++ ReceiptSuccess success = 2; ++ swarm.common.Error error = 3; ++ } ++ } +``` + +### 6. Documentation and Comments +**Before**: Minimal documentation beyond copyright notices. +**After**: Enhanced message and field documentation with explanatory comments. + +```diff ++ // ChunkType enum defines the different chunk formats ++ enum ChunkType { ++ CAC = 0; // Content-addressed chunk ++ SOC = 1; // Single-owner chunk ++ } +``` + +### 7. Result Handling with 'oneof' +**Before**: Results and errors mixed in a single message structure. +**After**: Clear use of `oneof` for mutually exclusive fields like success/error responses. + +### 8. Domain Model Clarity +**Before**: Some domain concepts were unclear from the protocol definition. +**After**: Better expression of domain concepts with dedicated types and enums. + +## Conclusion + +The new protocol definitions represent a substantial improvement in design quality. Key benefits include: + +1. **Improved maintainability** through consistent naming and structure +2. **Better error handling** with standardized error types and codes +3. **Enhanced clarity** through proper message hierarchies and documentation +4. **Reduced duplication** by centralizing common types like `Chunk` and `Error` +5. **Proper use of protobuf features** like enums, oneofs, and nested messages + +These improvements will lead to more reliable implementations, easier debugging, and a better developer experience across different Swarm clients. diff --git a/SWIPs/assets/swip-27/common.proto b/SWIPs/assets/swip-27/common.proto new file mode 100644 index 0000000..a45ed19 --- /dev/null +++ b/SWIPs/assets/swip-27/common.proto @@ -0,0 +1,76 @@ +syntax = "proto3"; + +package swarm.common; + +import "google/protobuf/any.proto"; + +option go_package = "pb"; + +// ChunkType enum defines the different chunk formats +// This follows the type information preservation principle +// by explicitly encoding the chunk type for protocol handlers +enum ChunkType { + CAC = 0; // Content-addressed chunk + SOC = 1; // Single-owner chunk +} + +// Chunk represents a data chunk in the Swarm network +// This follows the type information preservation principle by +// including explicit type and version fields that inform handlers +// how to interpret the remaining fields +message Chunk { + // Chunk type identifier + ChunkType chunk_type = 1; + + // Chunk format version + uint32 version = 2; + + // Chunk type-specific header + bytes header = 3; + + // Chunk data payload (serialized based on chunk_type) + bytes payload = 4; + + // Optional proof of chunk authenticity (from a system perspective) + bytes proof = 5; +} + +// PostageStamp represents a stamp proving chunk postage payment +message PostageStamp { + // The batch ID of the stamp + bytes batch_id = 1; + + // The index of the stamp within its batch + uint32 index = 2; + + // Timestamp of the stamp + uint64 timestamp = 3; + + // Signature validating the stamp + bytes signature = 4; +} + +// BzzAddress contains addressing information for a Swarm node +message BzzAddress { + // Underlay network address bytes + bytes underlay = 1; + + // Cryptographic signature of handshake + bytes signature = 2; + + // Nonce used for overlay address generation + bytes nonce = 3; + + // Overlay address bytes (optional) + bytes overlay = 4; +} + +// Error represents a standardized error response +// This implements the explicit error handling principle +message Error { + // The error code + uint32 code = 1; + + // An optional error message + string message = 2; +} diff --git a/SWIPs/assets/swip-27/handshake.proto b/SWIPs/assets/swip-27/handshake.proto new file mode 100644 index 0000000..a3e63b3 --- /dev/null +++ b/SWIPs/assets/swip-27/handshake.proto @@ -0,0 +1,57 @@ +syntax = "proto3"; + +package swarm.handshake; + +import "common.proto"; + +option go_package = "pb"; + +// HandshakeMessageType indicates the type of handshake message +enum HandshakeMessageType { + SYN = 0; + ACK = 1; + SYN_ACK = 2; +} + +// HandshakeMessage is the wrapper for all handshake protocol messages +message HandshakeMessage { + // The type of handshake message + HandshakeMessageType type = 1; + + // Only one of the following messages should be set based on the type + oneof message { + Syn syn = 2; + Ack ack = 3; + SynAck syn_ack = 4; + } +} + +// Syn message is sent to initiate a handshake +message Syn { + // The observed underlay address of the peer + bytes observed_underlay = 1; +} + +// Ack message is sent in response to a Syn +message Ack { + // The sender's Swarm address + swarm.common.BzzAddress address = 1; + + // Network ID to ensure peers are on the same network + uint64 network_id = 2; + + // Indicates if the node is a full node + bool full_node = 3; + + // Optional welcome message (max 140 chars) + string welcome_message = 99; +} + +// SynAck message combines Syn and Ack for efficiency +message SynAck { + // The Syn part of the message + Syn syn = 1; + + // The Ack part of the message + Ack ack = 2; +} diff --git a/SWIPs/assets/swip-27/headers.proto b/SWIPs/assets/swip-27/headers.proto new file mode 100644 index 0000000..2cc2ad8 --- /dev/null +++ b/SWIPs/assets/swip-27/headers.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package swarm.headers; + +import "common.proto"; + +option go_package = "pb"; + +// Headers contains a collection of protocol headers +// This implements the strongly typed messages principle by using +// explicit message types rather than generic byte arrays +// This is also the message that is sent in response to a Headers request +// and is infallible. +message Headers { + // List of header entries + repeated Header headers = 1; +} + +// Header represents a single key-value header +message Header { + // The header key + string key = 1; + + // The header value as bytes + bytes value = 2; +} diff --git a/SWIPs/assets/swip-27/hive.proto b/SWIPs/assets/swip-27/hive.proto new file mode 100644 index 0000000..a7baaf0 --- /dev/null +++ b/SWIPs/assets/swip-27/hive.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package swarm.hive; + +import "common.proto"; + +option go_package = "pb"; + +// Peers message contains a list of peer addresses to be shared with other nodes +// This is an infallible response as the protocol can return an empty list +// when no peers are available +message Peers { + // List of peer addresses + repeated swarm.common.BzzAddress peers = 1; +} diff --git a/SWIPs/assets/swip-27/pingpong.proto b/SWIPs/assets/swip-27/pingpong.proto new file mode 100644 index 0000000..23e2296 --- /dev/null +++ b/SWIPs/assets/swip-27/pingpong.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package swarm.pingpong; + +option go_package = "pb"; + +// Ping message sent to test connectivity +// This is an infallible request that cannot fail to be constructed +message Ping { + // Optional greeting text + string greeting = 1; +} + +// Pong message sent in response to a Ping +// This is an infallible response as PingPong is a basic connectivity test +message Pong { + // Response text + string response = 1; +} diff --git a/SWIPs/assets/swip-27/pricing.proto b/SWIPs/assets/swip-27/pricing.proto new file mode 100644 index 0000000..1701834 --- /dev/null +++ b/SWIPs/assets/swip-27/pricing.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +package swarm.pricing; + +option go_package = "pb"; + +// AnnouncePaymentThreshold message announces the payment threshold to peers +// This is an infallible message as it simply declares a value +message AnnouncePaymentThreshold { + // The payment threshold value in bytes as this may be up to u256. + bytes payment_threshold = 1; +} diff --git a/SWIPs/assets/swip-27/pseudosettle.proto b/SWIPs/assets/swip-27/pseudosettle.proto new file mode 100644 index 0000000..e979160 --- /dev/null +++ b/SWIPs/assets/swip-27/pseudosettle.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +package swarm.pseudosettle; + +option go_package = "pb"; + +// PseudoSettleMessageType indicates the type of pseudosettle message +enum PseudoSettleMessageType { + PAYMENT = 0; + PAYMENT_ACK = 1; +} + +// PseudoSettleMessage is the wrapper for all pseudosettle protocol messages +// This implements the stateful protocol pattern with explicit message types +message PseudoSettleMessage { + // The type of pseudosettle message + PseudoSettleMessageType type = 1; + + // Only one of the following messages should be set based on the type + oneof message { + Payment payment = 2; + PaymentAck payment_ack = 3; + } +} + +// Payment message represents a settlement payment +message Payment { + // The payment amount in bytes (big.Int) + bytes amount = 1; +} + +// PaymentAck acknowledges receipt of a payment +message PaymentAck { + // The accepted payment amount in bytes (big.Int) + bytes amount = 1; + + // The timestamp of the payment + int64 timestamp = 2; +} diff --git a/SWIPs/assets/swip-27/pullsync.proto b/SWIPs/assets/swip-27/pullsync.proto new file mode 100644 index 0000000..eca61dc --- /dev/null +++ b/SWIPs/assets/swip-27/pullsync.proto @@ -0,0 +1,113 @@ +syntax = "proto3"; + +package swarm.pullsync; + +import "common.proto"; + +option go_package = "pb"; + +// +// PullSync Subprotocol Messages +// + +// PullSyncMessageType indicates the type of pullsync message +enum PullSyncMessageType { + GET = 0; + OFFER = 1; + WANT = 2; + DELIVERY = 3; +} + +// PullSyncMessage is the wrapper for all pullsync protocol messages +// This implements the stateful protocol pattern with explicit message types +message PullSyncMessage { + // The type of pullsync message + PullSyncMessageType type = 1; + + // Only one of the following messages should be set based on the type + oneof message { + Get get = 2; + Offer offer = 3; + Want want = 4; + Delivery delivery = 5; + } +} + +// Get message requests chunks from a specific bin +message Get { + // The bin to retrieve chunks from + int32 bin = 1; + + // The starting position + uint64 start = 2; +} + +// Reference to a chunk in an offer, without the full chunk data +message ChunkReference { + // The chunk address + bytes chunk_addr = 1; + + // The batch ID + bytes batch_id = 2; + + // The stamp hash + bytes stamp_hash = 3; +} + +// Offer message offers chunks to the peer +message Offer { + // Topmost chunk position + uint64 topmost = 1; + + // List of available chunks + repeated ChunkReference chunks = 2; +} + +// Want message requests specific chunks from an offer +message Want { + // Bit vector indicating wanted chunks + bytes bit_vector = 1; +} + +// Delivery message delivers a requested chunk +message Delivery { + // The full chunk data + swarm.common.Chunk chunk = 1; +} + +// +// Cursors Subprotocol Messages +// + +// CursorsMessageType indicates the type of cursors message +enum CursorsMessageType { + SYN = 0; + ACK = 1; +} + +// CursorsMessage is the wrapper for all cursors protocol messages +// This implements the stateful protocol pattern with explicit message types +message CursorsMessage { + // The type of cursors message + CursorsMessageType type = 1; + + // Only one of the following messages should be set based on the type + oneof message { + Syn syn = 2; + Ack ack = 3; + } +} + +// Syn message initiates cursor synchronisation +message Syn { + // No fields needed for Syn message +} + +// Ack message responds with current cursors +message Ack { + // List of bin cursors + repeated uint64 cursors = 1; + + // Current epoch + uint64 epoch = 2; +} diff --git a/SWIPs/assets/swip-27/pushsync.proto b/SWIPs/assets/swip-27/pushsync.proto new file mode 100644 index 0000000..17ef8e4 --- /dev/null +++ b/SWIPs/assets/swip-27/pushsync.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; + +package swarm.pushsync; + +import "common.proto"; + +option go_package = "pb"; + +// Delivery message contains a chunk to be stored +message Delivery { + // The full chunk data + swarm.common.Chunk chunk = 1; +} + +// Receipt is a wrapper message that contains either a successful receipt +// or an error response +// This implements the explicit error handling principle for fallible operations +message Receipt { + // The chunk address + bytes chunk_addr = 1; + + // Only one of the following should be set + oneof result { + // Success receipt information + ReceiptSuccess success = 2; + + // Error information + swarm.common.Error error = 3; + } +} + +// ReceiptSuccess contains the signature and nonce for a successful receipt +message ReceiptSuccess { + // The signature of the receipt + bytes signature = 1; + + // The nonce + bytes nonce = 2; +} diff --git a/SWIPs/assets/swip-27/retrieval.proto b/SWIPs/assets/swip-27/retrieval.proto new file mode 100644 index 0000000..719c0c9 --- /dev/null +++ b/SWIPs/assets/swip-27/retrieval.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; + +package swarm.retrieval; + +import "common.proto"; + +option go_package = "pb"; + +// Request message requests a chunk by address +message Request { + // The address of the requested chunk + bytes chunk_addr = 1; +} + +// Delivery message delivers a requested chunk +// This implements the explicit error handling principle for fallible operations +// by using a oneof field to handle the success or error cases +message Delivery { + // Only one of the following should be set + oneof result { + // The full chunk data + swarm.common.Chunk chunk = 1; + + // Error information when the chunk cannot be delivered + swarm.common.Error error = 2; + } +} diff --git a/SWIPs/assets/swip-27/status.proto b/SWIPs/assets/swip-27/status.proto new file mode 100644 index 0000000..4b2a734 --- /dev/null +++ b/SWIPs/assets/swip-27/status.proto @@ -0,0 +1,50 @@ +syntax = "proto3"; + +package swarm.status; + +import "common.proto"; + +option go_package = "pb"; + +// Get message indicates interest in receiving a node Snapshot +// This is an infallible request with no fields +message Get { + // No fields needed for Get message +} + +// Snapshot message is a response to the Get message +// This operation is infallible, as this just returns the current state of the node +message Snapshot { + // The total reserve size + uint64 reserve_size = 1; + + // The current pullsync rate + double pullsync_rate = 2; + + // The storage radius + uint32 storage_radius = 3; + + // The number of connected peers + uint64 connected_peers = 4; + + // The size of the neighbourhood + uint64 neighborhood_size = 5; + + // The mode of the bee node + string bee_mode = 6; + + // The batch commitment + uint64 batch_commitment = 7; + + // Indicates if the node is reachable + bool is_reachable = 8; + + // The reserve size within the storage radius + uint64 reserve_size_within_radius = 9; + + // The last synced block + uint64 last_synced_block = 10; + + // The committed depth + uint32 committed_depth = 11; +} diff --git a/SWIPs/assets/swip-27/swap.proto b/SWIPs/assets/swip-27/swap.proto new file mode 100644 index 0000000..563d123 --- /dev/null +++ b/SWIPs/assets/swip-27/swap.proto @@ -0,0 +1,36 @@ +syntax = "proto3"; + +package swarm.swapprotocol; + +option go_package = "pb"; + +// SwapMessageType indicates the type of swap message +enum SwapMessageType { + EMIT_CHEQUE = 0; + HANDSHAKE = 1; +} + +// SwapMessage is the wrapper for all swap protocol messages +// This implements the stateful protocol pattern with explicit message types +message SwapMessage { + // The type of swap message + SwapMessageType type = 1; + + // Only one of the following messages should be set based on the type + oneof message { + EmitCheque emit_cheque = 2; + Handshake handshake = 3; + } +} + +// EmitCheque message contains a signed cheque +message EmitCheque { + // The serialised cheque + bytes cheque = 1; +} + +// Handshake message for swap protocol initialisation +message Handshake { + // The beneficiary address + bytes beneficiary = 1; +} diff --git a/SWIPs/swip-27.md b/SWIPs/swip-27.md new file mode 100644 index 0000000..c6e5d88 --- /dev/null +++ b/SWIPs/swip-27.md @@ -0,0 +1,238 @@ +--- +swip: 27 +title: Wire-Level Protocol Standardisation with Strongly Typed Messages +status: Draft +type: Standards Track +category: Networking +author: mfw78 (@mfw78) +created: 2025-03-03 +requires: 26 +--- + +## Simple Summary +This SWIP proposes standardised, strongly typed message formats for Swarm network protocols to enhance security, interoperability, and maintainability. + +## Abstract +This SWIP defines a comprehensive approach to standardising Swarm's wire-level protocols using strongly typed messages. It addresses current inconsistencies in protocol message formats, enhances type safety, and introduces a consistent pattern for stateful protocols. Building upon SWIP-26's chunk type framework, this proposal enforces the principle that each stream should write and read only one specific message type, creating clearer protocol boundaries and reducing implementation errors. + +## Motivation +Swarm's current protocol implementations suffer from several wire-level issues: + +1. **Weak Type Safety**: Generic byte arrays are used for complex data structures, increasing security risks. + +2. **Message Type Confusion**: Streams often handle multiple message types, leading to parsing errors and state confusion. + +3. **Inconsistent Conversation Patterns**: Stateful protocols lack clear message flow structures. + +4. **Duplicated Logic**: Common types are represented differently across protocols. + +This SWIP addresses these issues by standardising message formats and enforcing single-message-type streams. + +## Specification + +### Core Principles + +1. **One Message Type Per Stream**: Each writing or reading stream should handle exactly one message type. + +2. **Strongly Typed Messages**: All messages must use explicit types rather than generic byte arrays. + +3. **Common Type Definitions**: Shared structures like addresses and chunks must use consistent definitions. + +4. **Explicit Protocol State**: Stateful protocols must use wrapper messages with explicit type enums. + +5. **Explicit Error Handling**: Operations that can fail must explicitly model error responses using `oneof` fields. + +6. **Type Information Preservation**: Messages must either be strictly typed or provide sufficient type information to allow proper handling. + +### Message Structure + +#### 1. Stateful Protocols + +Stateful protocols shall use wrapper messages with type enums and oneof fields: + +``` +message ProtocolMessage { + MessageType type = 1; + + oneof message { + MessageType1 message_type1 = 2; + MessageType2 message_type2 = 3; + } +} +``` + +#### 2. Stateless Protocols + +Simple request/response protocols shall use direct message types: + +``` +// Stream 1: Client writes Request, Server reads Request +message Request { + field1_type field1 = 1; +} + +// Stream 2: Server writes Response, Client reads Response +message Response { + field2_type field2 = 1; +} +``` + +#### 3. Fallible Operations + +For any operation that may fail, the response message must use a `oneof` to explicitly handle the error case: + +``` +message Response { + oneof result { + SuccessData success = 1; + Error error = 2; + } +} +``` + +#### 4. Type Information Preservation + +All messages must either: +- Be strictly typed with explicit field types, or +- Include type and version information sufficient for the protocol handler to interpret the data correctly + +For example, chunk messages must include the chunk type and version: + +``` +message Chunk { + ChunkType chunk_type = 1; + uint32 version = 2; + bytes header = 3; + bytes payload = 4; + // ... +} +``` + +### Protocol Classifications + +1. **Stateful Protocols**: + - `handshake` + - `pullsync` (including `cursors` subprotocol) + - `swap` + - `pseudosettle` + +2. **Stateless Protocols**: + - `hive` + - `headers` + - `pingpong` + - `pricing` + - `pushsync` + - `retrieval` + - `status` + +### Protocol Versioning + +This SWIP introduces new major versions for all protocols: + +1. All protocols will advertise new libp2p protocol versions (e.g., upgrading from `/swarm/hive/1.0.0/hive` to `/swarm/hive/2.0.0/hive`) +2. The new protocol versions will use the standardized message formats outlined in this SWIP +3. Node implementations must support both old and new protocol versions during the transition period + +### Reference Implementation + +A complete set of Protocol Buffer definitions implementing this proposal is available in the [assets directory](./assets/swip-27/). This includes a comprehensive [overview of improvements](./assets/swip-27/README.md) compared to the previous protocol definitions, as well as detailed protocol definitions for all Swarm network protocols. + +## Rationale + +The proposed approach: + +1. **Reduces Complexity**: By limiting each stream to one message type, we simplify parsing and state management. + +2. **Improves Security**: Strong typing and clear message boundaries reduce the attack surface. + +3. **Enhances Maintainability**: Standardised patterns make code more maintainable and easier to audit. + +4. **Clarifies Protocols**: Explicit message types make protocol documentation and implementation clearer. + +5. **Facilitates Testing**: Well-defined message boundaries make unit testing more effective. + +6. **Explicit Error Handling**: By using `oneof` for fallible operations, we make error paths explicit and force protocol implementers to handle errors properly. + +7. **Type Information Preservation**: By requiring sufficient type information, we ensure protocol handlers can correctly interpret the message contents. + +The single-message-type principle is particularly important because it: +- Prevents type confusion attacks +- Makes protocol state transitions explicit +- Reduces parsing errors +- Creates cleaner API boundaries + +## Backwards Compatibility + +This proposal introduces significant changes to message formats but provides a structured migration path: + +1. **Dual Protocol Support**: All nodes must support both old and new protocol versions during the transition period, with the underlying node logic remaining unchanged. + +2. **Version Preference**: Nodes should prefer using the new protocol versions when communicating with peers that support them. + +3. **Advertised Capabilities**: New protocol versions will be advertised through libp2p protocol version strings. + +4. **Phased Adoption**: This approach allows for progressive network upgrades without immediate disruption. + +5. **Hard Deadline**: At a predetermined block height or timestamp, support for old protocol versions will be discontinued through a mandatory `handshake` version upgrade. + +## Implementation + +Implementation will proceed in phases: + +1. **Protocol Definition**: Define the new protocol message formats using Protocol Buffers. + +2. **Dual Support Implementation**: Update node software to support both old and new protocol versions simultaneously, with no changes to the underlying business logic. + +3. **Version Negotiation**: Enhance connection handling to detect and prefer new protocol versions when available. + +4. **Network Monitoring**: Track adoption rates of the new protocol versions across the network. + +5. **Hard Cutoff**: At a predetermined network milestone (e.g., a specific block height), enforce the exclusive use of new protocol versions by upgrading the `handshake` version, requiring all nodes to support the new message formats. + +6. **Legacy Code Removal**: After the hard cutoff date, remove support for legacy protocol versions, simplifying the codebase. + +This approach provides a balance between network stability and progressive improvement, allowing node operators to upgrade at their convenience until the hard deadline. + +## Test Cases + +Testing should focus on: + +1. **Message Boundaries**: Verify each stream handles exactly one message type in the new protocol versions. + +2. **Type Safety**: Confirm no generic byte arrays for complex structures in the new protocol versions. + +3. **Protocol State**: Test correct state transitions in stateful protocols. + +4. **Dual Version Support**: Verify nodes correctly handle both old and new protocol versions during the transition period. + +5. **Version Preference**: Confirm nodes prefer new protocol versions when both peers support them. + +6. **Handshake Enforcement**: Test that nodes properly enforce the new protocol versions after the hard cutoff date. + +7. **Error Handling**: Verify that fallible operations properly handle error cases through the defined `oneof` fields. + +8. **Type Information**: Test that messages provide sufficient type information for proper handling. + +## Security Considerations + +This standardisation significantly improves security by: + +1. **Preventing Type Confusion**: Strong typing reduces misinterpretation of message data. + +2. **Limiting Attack Surface**: Clear message boundaries reduce opportunities for exploitation. + +3. **Enabling Static Analysis**: Well-defined types allow better static analysis tools. + +4. **Simplifying Validation**: Structured messages enable more thorough validation. + +5. **Clarifying Protocol States**: Explicit message types make unexpected state transitions easier to detect. + +6. **Explicit Error Handling**: Clear error paths prevent error condition mishandling. + +7. **Type Information Preservation**: Sufficient type information prevents misinterpretation of message contents. + +8. **Coordinated Transition**: The phased migration approach reduces security risks associated with network fragmentation. + +## Copyright Waiver + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).