(T, U) = Tuples of 2 elements. the 1st type T and the second type U.
A tuple is simply a concatenation of types written one after the other.
A tuple can be of any size (no maximum limit), but its size is necessarily fixed.
The different elements may be of different types, but the order cannot change.
##### [T; n]
Array of n elements of type T.
If the size of the array is variable, its size (in number of cells) is stored on 8 bytes.
| data | size in bytes | data type |
|:-----------:|--------------:|----------------:|
| cells_count | 8 | u64 |
| content* | ?*cells_count | (T1, T2, ...) |
All cells in the table are written one after the other without a separator, _like_ a tuple of `cells_count` elements of the same type.
**/*\ CAUTION: If the size of the array is static (=a literal constant) then the array is serialized without a size field. **
For example, the content of a public key ed25519 is a 32-byte array, (a [u8; 32] therefore), it is serialized directly without a size field.
##### Opt(T)
Indicates that a field is optional. The optional fields are preceded by a 1-byte boolean that indicates whether or not the field is present.
| data | size in bytes | data type |
|:---------:|--------------:|----------------:|
| is_some | 1 | u8 |
| content | ? | T |
If `is_some` is equal to `1`, field `content` is present.
If `is_some` is equal to `0`, field `content` is missing.
Any other value of `is_some` is prohibited and will invalidate the entire message.
##### String
String formatted in utf8 and [NFKC normalized](https://fr.wikipedia.org/wiki/Normalisation_Unicode#NFKC).
**/!\ CAUTION: All strings are systematically prefixed with their size, including for an empty string. The size is stored on 8 bytes as shown in the table below :**
| algorithm | code |
|:----------------------:|-------:|
| Ed25519 | 0x00 |
| Schnorr | 0x01 |
| data | size in bytes | data type |
|:---------:|--------------:|----------------:|
| str_size | 8 | u64 |
| content | str_size | [u8; str_size] |
content := String in binary utf8 with [NFKC normalization](https://fr.wikipedia.org/wiki/Normalisation_Unicode#NFKC).
If the string is empty, field `content` is missing and `str_size` is equal to zero.
##### Blockstamp
| data | size in bytes | data type |
|:----------:|--------------:|----------:|
| block_id | 4 | u32 |
| block_hash | 32 | [u8; 32] |
##### KeysAlgorithm
| algorithm | u32 |
|:----------:|----:|
| Ed25519 | 0 |
| Schnorr | 1 |
##### PubkeyBox
Contains the signatory's public key.
| data | size in bytes | data type |
|:-------:|--------------:|-------------------:|
| size | 2 | u16 |
| algo | 1 | algorithm |
| content | size - 1 | ?* |
size := Size of the whole PubkeyBox (size field excluded).
_* The type of `payload` is determined by the content of `message_type`._
ws2p_version := This field is placed first so that future versions of WS2P are not constrained on the other fields,
the only constraint will be to start the message with the version number stored in u32.
The signature is not always present, it's only present for messages_type values `0x00??`.
The signature is generated from the hash sha 256 of the message. This hash is always given to allow the receiving node to verify that it has not received corrupted datas.
currency_name := Empty string is allowed, it allow the user to synchronize his node without having to manually enter the currency on which he synchronizes. The node will then adopt the currency that is specified in the CONNECT message it will receive from the selected reference node.
### currency_code
| currency | code |
|:----------------------:|-------:|
| null* | 0x0000 |
| g1 | 0x0001 |
| Others prod currencies | 0x0??? |
| g1-test | 0x1000 |
| Others test currencies | 0x???? |
_* The type of `payload` is determined by the content of `message_type`._
_*the `null` value is essential, it allows the user to synchronize his node without having to manually enter the currency on which he synchronizes. The node will then adopt the currency that is specified in the CONNECT message it will receive from the selected reference node._
The signature is not always present, it's only present for connection negotiation messages.
The signature is generated from the hash sha 256 of the message.
This hash is always given to allow the receiving node to verify that it has not received corrupted datas.
### message_type interpretation
| message type | code | Signed | elements_count interval |
If api_size == 0 then `api_name` is an 8-bit binary value :
| API | code |
|:--------------------:|----------|
| BASIC_MERKLED_API | 0x00 |
| WS2P | 0x01 |
| GVA | 0x02 |
| DASA | 0x03 |
endpoint_version := value is `1`.
#### network_features
The 16 bits represent booleans to define the presence or absence of 16 network features. WS2Pv2 defines only 4 features, the remaining 12 are undefined and are in anticipation of future Ğfeatures.
The 16 bits represent booleans to define the presence or absence of 16 network features. WS2Pv2 defines only 2 features, the remaining 14 are undefined and are in anticipation of future Ğfeatures.
Network features :
| bit | feature |
|:---------:|----------|
| 0000_0001 | IP4 |
| 0000_0010 | IP6 |
| 0000_0100 | TLS |
| 0000_1000 | TOR |
The first two features are a bit special because they must be read to parse the endpoint, indicating if the ipv4 and ipv6 fields are present or not.
TLS := This feature indicates that the endpoint should be contacted with an SSL/TLS overlay (HTTPS or WSS).
TOR := This feature indicates that the endpoint must be contacted via the tor network (hidden service).
...
...
@@ -314,32 +344,30 @@ The utf8 format is used to display the endpoint in a human-readable format. It i
General utf8 endpoint format :
API_NAME VERSION n NF1 .. NFn n2 AF1 .. AFn2 IP4 IP6 HOST PORT PATH
API_NAME VERSION n NF1 .. NFn n2 AF1 .. AFn2 PORT HOST IP4 [IP6] PATH
@@ -465,8 +490,7 @@ WARNING: independently of all these rules, each implementation must integrate it
| flags_size | 1 | u8 |
| flags_queries | flags_size | WS2PFlags |
| peer_card | ? | Peer card |
| chunk_id* | 4 | u32 |
| chunk_hash* | 32 | [u8; 32] |
| chunkstamp | 4 | Opt(Blockstamp) |
challenge := random hash generated by the sending node of the CONNECT message, the receiving node will then have to sign this challenge and then send this signature in its ACK message to prove that it has the corresponding private key to the public key it indicates.
...
...
@@ -476,10 +500,7 @@ flags_queries := See "WS2PFlags type definition" below.
peer_card := This field is optional, if it's not present it must be replaced by 2 bytes filled with zeros. Why two bytes ? Because the first field of any peer card, `peer_card_size`, is 2 bytes long.
_*Fields `chunk_id` and `chunk_hash` are present only if flag `ASK_SYNC_CHUNK` is present in `flags_queries`._
chunk_id := Last block number of the chunk.
chunk_hash := Last block hash of the chunk.
chunkstamp := Blockstamp of the last block of the chunk. This field is present only if flag `ASK_SYNC_CHUNK` is present in `flags_queries`.
#### WS2PFlags type definition
...
...
@@ -513,8 +534,8 @@ The message is already signed at the container level, so there is no need to rep
@@ -529,50 +550,32 @@ LOW_FLOW_DEMAND := The sender node of this message indicates that it's behind a
MEMBER_PUBKEY: Indicates whether or not the member_pubkey field is present in the message.
MEMBER_PROOF := Indicates that the message contains proof that the sender node is a member. If this boolean is false, then the member_proof field must not be present.
If this boolean is true, the "member_proof" must contain a signature must sign the following datas :
| data name | size in bytes | data type |
|:--------------:|---------------|-----------|
| flags | 2 | b16 |
| prefix | 2 | u16 |
| issuer_node_id | 4 | u32 |
| m_pubkey | 32 | PubkeyBox |
| challenge* | 32 | [u8; 32] |
If this boolean is true, the "member_proof" must contain a signature of the challenge* send by other node in their CONNECT message.
_*This is the remote challenge for the signatory, and the local challenge for the verifier._
_*It's the remote challenge for the signatory, and the local challenge for the verifier._
### OK message
If payload_size == 0 :
In most cases, the OK message is empty, it simply indicates that the remote node accepts the connection establishment. If the local node has also sent an OK message, then it considers the connection as fully established.
But sometimes the OK message can also transmit additional informations, the `payload_size` value can handle these cases.
Else if payload_size == 2 :
In most cases, the OK message is empty (=3 zero-bytes), it simply indicates that the remote node accepts the connection establishment. If the local node has also sent an OK message, then it considers the connection as fully established.
But sometimes the OK message can also transmit additional informations :
prefix := In ws2p v2, member nodes have the option of not publicly communicating their prefix. It will only reveal their prefix to the node of their choice among those with which they establish a connection. For example, a member node may decide to share its prefix only with other member nodes of the same key.
If this field is zero, it means that the remote node does not want to reveal its prefix (the prefix being necessarily greater than or equal to 1).
prefix := If this field is zero, it means that the remote node does not want to reveal its prefix (the prefix being necessarily greater than or equal to 1).
target_b_number := Indicates the current block number of the message sender node. This number will be the target to reach for the node being synchronized.
target_b_hash := Indicates the current block hash of the message sender node. This hash will be the target to reach for the node being synchronized.
chunks_hashs_count := `chunks_hashs` array size
target_blockstamp := Indicates the current blockstamp of the message sender node. This blockstamp will be the target to reach for the node being synchronized.
chunks_hashs := Hash table of the last block of each chunk. We do not need the block numbers, we know them. Here the remote node sends the hashs of all these chunk, which correspond to the current hashs of all the blocks having a number in 250 module 249, in ascending order.
...
...
@@ -580,7 +583,7 @@ chunks_hashs := Hash table of the last block of each chunk. We do not need the b
| data name | size in bytes | data type |
|:---------:|---------------|-----------|
| reason | 1 | u8 |
| reason | 2 | u16 |
#### reason interpretation
...
...
@@ -601,14 +604,14 @@ Some WS2Pv1 messages are accepted within WS2Pv2 connections, here is the exhaust
* v1 requests
* responses to v1 requests
WARNING : Exception with the ABF api feature : In a WS2P connection between two nodes that both support ABF api feature, any WS2Pv1 message is rejected !
WARNING : Exception with the ABF api feature : In a WS2P connection between two nodes that both support ABF api feature, any WS2Pv1 message are rejected !
### REQUESTS
| data name | size in bytes | data type |
|:------------:|---------------|-------------|
| request_id | 4 | u32 |
| request_type | 1 | u8 |
| request_type | 4 | u32 |
| param_1 | ? | ? |
| param_2 | ? | ? |
...
...
@@ -637,19 +640,19 @@ _*This is part of the specificities of WS2P requests in binary format, which wil
| data name | size in bytes | data type |
|:----------------:|---------------|------------|
| request_id | 4 | u32 |
| response_type | 1 | u8 |
| response_type | 4 | u32 |
| response_content | ? | ? |
#### response_type interpretation
| value | significance |
|:-----:|--------------------|
| 0x00 | EMPTY_RESPONSE |
| 0xff | BAD_REQUEST |
| 0x01 | CURRENT_BLOCKSTAMP |
| 0x02 | BLOCKS_HASHS |
| 0x03 | CHUNK |
| 0x05 | WOT_POOL |
| 0 | EMPTY_RESPONSE |
| 1 | BAD_REQUEST |
| 2 | CURRENT_BLOCKSTAMP |
| 3 | BLOCKS_HASHS |
| 4 | CHUNK |
| 5 | WOT_POOL |
EMPTY_RESPONSE := `response_content` field is absent.
...
...
@@ -659,7 +662,7 @@ BAD_REQUEST := Used only in debug mode. In production, bad requests are simply i
| data name | size in bytes | data type |
|:------------:|---------------|------------|
| reason | ? | utf8 |
| reason | ? | String |
_*The total payload size of any WS2P message is indicated in the metadata, field `reason` being the only one of unknown size, its size is deduced by calculation._
...
...
@@ -673,94 +676,69 @@ _*The total payload size of any WS2P message is indicated in the metadata, field
| data name | size in bytes | data type |
|:------------:|----------------|---------------|
| hashs_count | 8 | u64 |
| hashs | 32*hashs_count | [[u8; 32]; ?] |
_*The total payload size of any WS2P message is indicated in the metadata, field `hashs` being the only one of unknown size, its size is deduced by calculation._
_*The total payload size of any WS2P message is indicated in the metadata, field `blocks` being the only one of unknown size, its size is deduced by calculation._
blocks := table of tuples (block_size, block_content)
_*The total payload size of any WS2P message is indicated in the metadata, field `folders` being the only one of unknown size, its size is deduced by calculation._
_*Durs assigns a unique integer to each member according to the order in which the identities are declared in the blocks, so it's guaranteed that all Durs nodes will always assign the same integer to any given member._