Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
D
doc
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Model registry
Monitor
Service Desk
Analyze
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
This is an archived project. Repository and other project resources are read-only.
Show more breadcrumbs
nodes
common
doc
Commits
03ab8015
Unverified
Commit
03ab8015
authored
7 years ago
by
Éloïs
Browse files
Options
Downloads
Patches
Plain Diff
[enh] formalization of all json data with explicit typing
parent
83671c54
No related branches found
No related tags found
1 merge request
!4
RFC 4 : Duniter WS2P API v1
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
rfc/0004_ws2p_v1.md
+156
-89
156 additions, 89 deletions
rfc/0004_ws2p_v1.md
with
156 additions
and
89 deletions
rfc/0004_ws2p_v1.md
+
156
−
89
View file @
03ab8015
...
...
@@ -5,6 +5,8 @@ This document details the current specifications of WS2P v1 as they are already
## Contents
*
[
Contents
](
#contents
)
*
[
Conventions
](
#conventions
)
*
[
JSON format
](
#json-format
)
*
[
What is WS2P ?
](
#what-is-ws2p-
)
*
[
WS2P Endpoints
](
#ws2p-endpoints
)
*
[
Endpoint format
](
#endpoint-format
)
...
...
@@ -26,6 +28,28 @@ This document details the current specifications of WS2P v1 as they are already
*
[
getRequirementsPending
](
#getrequirementspending
)
*
[
List of error messages
](
#list-of-error-messages
)
## Conventions
### JSON format
All data in JSON format is presented in this RFC with explicit typing.
Types list :
Number(field description),
String(field description),
Bool(field description),
Object(field description)
Example :
{
"pubkey": String(identity pubkey in base58),
"expires_on": Number(timestamp),
"wasMember": Bool(true if the identity has already been a member at least once),
"pendingMembership" : Object(pending membership document)
]
## What is WS2P ?
...
...
@@ -119,15 +143,15 @@ for each connection attempt, the process is as follows:
JSON format :
{
auth:
'
CONNECT
'
,
pub: "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx",
challenge: "28170b84-3468-4c21-806e-cf6457d43298055df085-8e5e-43cd-9907-e5c4f9de5bc7",
sig: "wIa/gohWYcJUt10xgsMAjlBiMYhxu2DOKDJdPiEFVB3OVynFvPPW4S/gGZQE7vlxzplSHUE3dCSWfrtjGtlGCw=="
"
auth
"
:
String("
CONNECT
")
,
"
pub
"
:
String(
"D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx"
)
,
"
challenge
"
:
String(
"28170b84-3468-4c21-806e-cf6457d43298055df085-8e5e-43cd-9907-e5c4f9de5bc7"
)
,
"
sig
"
:
String(
"wIa/gohWYcJUt10xgsMAjlBiMYhxu2DOKDJdPiEFVB3OVynFvPPW4S/gGZQE7vlxzplSHUE3dCSWfrtjGtlGCw=="
)
}
pub : Local node public key
challenge
:
random string
sig
:
ed25519 signature of the RAW format message in base64.
pub :
=
Local node public key
challenge
:=
random string
sig
:=
ed25519 signature of the RAW format message in base64.
RAW format :
`WS2P:CONNECT:currency_name:pub:challenge`
...
...
@@ -138,13 +162,13 @@ RAW format of the example message above : `WS2P:CONNECT:g1:D9D2zaJoWYWveii1JRYLV
JSON format :
{
auth:
'
ACK
'
,
pub: "D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx",
sig: "wIa/gohWYcJUt10xgsMAjlBiMYhxu2DOKDJdPiEFVB3OVynFvPPW4S/gGZQE7vlxzplSHUE3dCSWfrtjGtlGCw=="
"
auth
"
:
String("
ACK
")
,
"
pub
"
:
String(
"D9D2zaJoWYWveii1JRYLVK3J4Z7ZH3QczoKrnQeiM6mx"
)
,
"
sig
"
:
String(
"wIa/gohWYcJUt10xgsMAjlBiMYhxu2DOKDJdPiEFVB3OVynFvPPW4S/gGZQE7vlxzplSHUE3dCSWfrtjGtlGCw=="
)
}
pub : Local node public key
sig
:
ed25519 signature of the RAW format message in base64.
pub :
=
Local node public key
sig
:=
ed25519 signature of the RAW format message in base64.
raw format :
`WS2P:ACK:currency_name:pub:challenge`
...
...
@@ -158,12 +182,10 @@ The challenge is not retransmitted in json format of ACK messages because the re
JSON format :
{
auth:
'OK'
,
sig
"
auth:
String("OK")
,
"
sig
": String(ed25519 signature of the RAW format message in base64)
}
sig: ed25519 signature of the RAW format message in base64.
raw format :
`WS2P:OK:currency_name:pub:challenge`
_
**Be careful**
, this time each one signs his message OK with his own challenge that he sent in his message CONNECT.
...
...
@@ -208,8 +230,8 @@ Each new head received from the same node overwrites the previous head in memory
Accepted since duniter-ts
**v1.6.0**
{
message
: "API:MESSAGE_TYPE:PUBKEY:BLOCKSTAMP",
sig
: "ZkatBTCYlp1KC/AS2TcDUYmxsWo0SaIDgkTZnhJzT2HU2OdJTqYr5s5JA+8iGCf0Qml8UgiwidscAEyeEl+WBg==""
"
message
"
:
String(
"API:MESSAGE_TYPE:PUBKEY:BLOCKSTAMP"
)
,
"
sig
"
:
String(
"ZkatBTCYlp1KC/AS2TcDUYmxsWo0SaIDgkTZnhJzT2HU2OdJTqYr5s5JA+8iGCf0Qml8UgiwidscAEyeEl+WBg==""
)
}
#### message field
...
...
@@ -228,8 +250,8 @@ sig: ed25519 signature of the message field in base64.
Accepted since duniter-ts
**v1.6.9**
{
message
: "API:MESSAGE_TYPE:1:PUBKEY:BLOCKSTAMP:WS2PID:SOFTWARE:SOFT_VERSION:POW_PREFIX,
sig
:
"MY90zXICfbYhLlz8VrL4HWPkphZEFR+bT2JWsoKdDMadgn0R0ZjsowDsnlfNqX4F4qeWeFoxhvdVgTO9VSghCA=="
"
message
"
:
String(
"API:MESSAGE_TYPE:1:PUBKEY:BLOCKSTAMP:WS2PID:SOFTWARE:SOFT_VERSION:POW_PREFIX
")
,
"
sig
": String(
"MY90zXICfbYhLlz8VrL4HWPkphZEFR+bT2JWsoKdDMadgn0R0ZjsowDsnlfNqX4F4qeWeFoxhvdVgTO9VSghCA=="
)
}
#### message field
...
...
@@ -253,11 +275,11 @@ Accepted since duniter-ts **v1.6.9**, relayed fully since duniter-ts **v1.6.15**
_Nodes with versions lower than 1.6.15 bounce a degraded version of the head, only `message` and `sig` fields are relayed._
{
message
: "API:HEAD:1:PUBKEY:BLOCKSTAMP:WS2PID:SOFTWARE:SOFT_VERSION:POW_PREFIX,
sig
: "TPh2A3NS8cHj8yrJk1Yeldx2H6bPEp46cFAGZXKfxJcNgXL2sWrlirhIOlp8pkUFSrwDawWY1zO1jlgUqMvlAg==",
messageV2: "API:HEAD:2:PUBKEY:BLOCKSTAMP:WS2PID:SOFTWARE:SOFT_VERSION:POW_PREFIX:FREE_MEMBER_ROOM:FREE_MIRROR_ROOM",
sigV2: "ta1lRrWsjGcYHcLdS75JgEW5B8ByRetFVUVVpakKNJBirhRe8HcYUHEOM7xj/+gUQGGOit6Gm5Q/lsvfsngWAQ==",
step:
0
"
message
"
:
String(
"API:HEAD:1:PUBKEY:BLOCKSTAMP:WS2PID:SOFTWARE:SOFT_VERSION:POW_PREFIX
")
,
"
sig
"
:
String(
"TPh2A3NS8cHj8yrJk1Yeldx2H6bPEp46cFAGZXKfxJcNgXL2sWrlirhIOlp8pkUFSrwDawWY1zO1jlgUqMvlAg=="
)
,
"
messageV2
"
:
String(
"API:HEAD:2:PUBKEY:BLOCKSTAMP:WS2PID:SOFTWARE:SOFT_VERSION:POW_PREFIX:FREE_MEMBER_ROOM:FREE_MIRROR_ROOM"
)
,
"
sigV2
"
:
String(
"ta1lRrWsjGcYHcLdS75JgEW5B8ByRetFVUVVpakKNJBirhRe8HcYUHEOM7xj/+gUQGGOit6Gm5Q/lsvfsngWAQ=="
)
,
"
step
"
:
Number(0)
}
#### message & messageV2 fields
...
...
@@ -315,8 +337,8 @@ All documents are sent in json format, the body format of the request is always
{
body: {
name: DOCUMENT_TYPE_ID,
[
DOCUMENT_TYPE_NAME
]
: DOCUMENT
_IN_JSON_FORMAT
name:
Number(
DOCUMENT_TYPE_ID
)
,
"
DOCUMENT_TYPE_NAME
"
:
Object(
DOCUMENT
)
}
}
...
...
@@ -335,18 +357,18 @@ With the exception of the peer format detailed below, the json format of each do
### Peer format
{
"version": 10,
"currency": CURRENCY_NAME,
"version":
Number(
10
)
,
"currency":
String(
CURRENCY_NAME
)
,
"endpoints": [
ENDPOINT
1
,
ENDPOINT
2
,
ENDPOINT3
String(
ENDPOINT
_1)
,
String(
ENDPOINT
_2)
,
...
],
"status": "UP",
"block": BLOCKSTAMP,
"signature": SIGNATURE,
"raw": RAW_FORMAT,
"pubkey": PUBKEY
"status":
String(
"UP"
)
,
"block":
String(
BLOCKSTAMP
)
,
"signature":
String(
SIGNATURE
)
,
"raw":
String(
RAW_FORMAT
)
,
"pubkey":
String(
PUBKEY
)
}
Real example :
...
...
@@ -413,16 +435,16 @@ If all conditions are satisfied, then the document is saved in the local bdd of
Specific queries can be sent via ws2p to obtain specific blocks or sandbox data.
Each type of query has a unique identifier called "name"
(Realy it's an integer)
.
Each type of query has a unique identifier called "name".
### getCurrent
JSON Message :
{
reqId: REQUESTS_UNIQUE_ID,
reqId:
String(
REQUESTS_UNIQUE_ID
)
,
body: {
name: "CURRENT",
name:
String(
"CURRENT"
)
,
params: {}
}
}
...
...
@@ -433,15 +455,15 @@ it allows the requester node to identify to which query the answers it receives
JSON response to success :
{
resId: REQUESTS_UNIQUE_ID,
body: BLOCK_IN_JSON_FORMAT
resId:
String(
REQUESTS_UNIQUE_ID
)
,
body:
Object(
BLOCK_IN_JSON_FORMAT
)
}
JSON error response :
{
resId: REQUESTS_UNIQUE_ID,
err: error
_
message
_in_string_format
resId:
String(
REQUESTS_UNIQUE_ID
)
,
err:
String(
error
message
)
}
### getBlock
...
...
@@ -449,11 +471,11 @@ JSON error response :
JSON Message :
{
reqId: REQUESTS_UNIQUE_ID,
reqId:
String(
REQUESTS_UNIQUE_ID
)
,
body: {
name: "BLOCK_BY_NUMBER",
name:
String(
"BLOCK_BY_NUMBER"
)
,
params: {
number: BLOCK_NUMBER
number:
Number(
BLOCK_NUMBER
)
}
}
}
...
...
@@ -464,15 +486,15 @@ it allows the requester node to identify to which query the answers it receives
JSON response to success :
{
resId: REQUESTS_UNIQUE_ID,
body:
BLOCK_IN_JSON_FORMAT
resId:
String(
REQUESTS_UNIQUE_ID
)
,
body:
Object(BLOCK)
}
JSON error response :
{
resId: REQUESTS_UNIQUE_ID,
err: error
_
message
_in_string_format
resId:
String(
REQUESTS_UNIQUE_ID
)
,
err:
String(
error
message
)
}
### getBlocks
...
...
@@ -484,8 +506,8 @@ JSON Message :
body: {
name: "BLOCKS_CHUNK",
params: {
count:
*
number of blocks requested
*
,
fromNumber:
*
number of the 1st block of the requested interval
*
count:
Number(
number of blocks requested
)
,
fromNumber:
Number(
number of the 1st block of the requested interval
)
}
}
}
...
...
@@ -496,10 +518,10 @@ it allows the requester node to identify to which query the answers it receives
JSON response to success :
{
resId: REQUESTS_UNIQUE_ID,
resId:
String(
REQUESTS_UNIQUE_ID
)
,
body: [
BLOCK_1_IN_JSON_FORMAT
,
BLOCK_2_IN_JSON_FORMAT
,
Object(BLOCK_1)
,
Object(BLOCK_2)
,
...
]
}
...
...
@@ -507,8 +529,8 @@ JSON response to success :
JSON error response :
{
resId: REQUESTS_UNIQUE_ID,
err:
*
error message
in string format*
resId:
String(
REQUESTS_UNIQUE_ID
)
,
err:
String(
error message
)
}
### getRequirementsPending
...
...
@@ -518,11 +540,11 @@ Requests the "requirements" of all identities that have received at least `minCe
JSON Message :
{
reqId: REQUEST
S
_UNIQUE_ID,
reqId:
String(
REQUEST_UNIQUE_ID
)
,
body: {
name: "WOT_REQUIREMENTS_OF_PENDING",
name:
String(
"WOT_REQUIREMENTS_OF_PENDING"
)
,
params: {
minCert:
*integer*
minCert:
Number()
}
}
}
...
...
@@ -533,44 +555,89 @@ it allows the requester node to identify to which query the answers it receives
JSON response to success :
{
resId: REQUESTS_UNIQUE_ID,
body: {
identities: [
"resId": REQUESTS_UNIQUE_ID,
"body": {
"identities": [
{
"certifications": [
{
"expiresIn": Number(timestamp),
"from": String(issuer pubkey in base58),
"timestamp": Number(),
"to": String(receiver pubkey in base58)
}),
...
]
"expired": Bool(),
"isSentry": Bool(),
"membershipExpiresIn": Number(),
"membershipPendingExpiresInm": Number(),
"meta": {
"timestamp": String(identity document creation blockstamp)
},
"outdistanced": Bool(),
"pendingCerts": [
{
hash: IDTY1_HASH,
member: *boolean*,
wasMember: *boolean*,
pubkey: IDTY1_PUBKEY,
uid: IDTY1_UID,
buid: IDTY1_BUID,
sig: IDTY1_SIG,
revocation_sig: IDTY1_REVOCATION_SIG,
revoked: *boolean*,
revoked_on: *integer*
"block": Number(doubloon with "block_number" field),
"block_hash": String(certification document creation block hash),
"block_number": Number(certification document creation block number),
"blockstamp": String(certification document creation blockstamp),
"expired": Number(is always zero),
"expires_on": Number(timestamp),
"from": String(issuer pubkey in base58),
"linked": Bool(is always false),
"sig": String(certification document signature in base64),
"target": String(hash of the target identity),
"to": String(receiver pubkey in base58),
"written": Bool(is always false),
"written_block": is always Null,
"written_hash": is always Null
},
IDTY2,
Object(PEDNIGN_CERT_2),
...
],
"pendingMemberships": [
{
"block": String(doubloon with "blockstamp" field),
"blockHash": String(membership document creation block hash),
"blockNumber": Number(99156),
"blockstamp": String(membership document creation blockstamp),
"certts": String(doubloon with "blockstamp" field),
"expired": Null,
"expires_on": Number(timestamp),
"fpr": String(doubloon with "blockHash" field),
"idtyHash": String(hash of the target identity),
"issuer": String(issuer pubkey in base58),
"membership": String(user request type : "IN" or "OUT"),
"number": Number(doubloon with "blockNumber" field),
"sig": String(membership document signature in base64),
"signature": String(doubloon with "sig" field),
"type": String(doubloon with "membership" field),
"userid": String(),
"written": Bool(is always false),
"written_number": Null
},
...
],
"pubkey": String(identity pubkey in base58),
"revocation_sig": String(revocation document signature in base64, empty where the identity is not revoked),
"revoked": Bool(),
"revoked_on": Number(?),
"sig":String(identity document signature in base64),
"uid": String(),
"wasMember": Bool(true if the identity has already been a member at least once)
},
Object(IDTY_2),
...
]
}
}
Fields details:
hash := sha256 of the identity document.
member :=
`true`
if the identity is a member,
`false`
otherwise.
wasMember :=
`true`
if the identity has already been a member at least once in the past,
`false`
otherwise.
pubkey := public key ed25519 of the identity
uid := Human name of identity
buid := identity document creation blockstamp
sig := signature of the identity document
revocation_sig := signature of revocation document (empty string if the revocation document has not been published)
revoked :=
`true`
if the member has been revoked,
`false`
otherwise.
revoked_on := Blockstamp when identity was revoked, or
`0`
if identity has not yet been revoked.
JSON error response :
{
resId: REQUESTS_UNIQUE_ID,
err:
*
error message
in string format*
resId:
String(
REQUESTS_UNIQUE_ID
)
,
err:
String(
error message
)
}
### List of error messages
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment