diff --git a/rfc/0003 RFC GraphQL API for Duniter Client.md b/rfc/0003 RFC GraphQL API for Duniter Client.md index 3d6d0c8eee13ced726785341e99b1930369059ff..be052dcc0123953dab439332a90d159bba290353 100644 --- a/rfc/0003 RFC GraphQL API for Duniter Client.md +++ b/rfc/0003 RFC GraphQL API for Duniter Client.md @@ -22,6 +22,15 @@ The WS2P API is dedicated for the inter-node communication. We propose here a new API Module dedicated to client software. It should deliver efficiently all information needed without slowing down the Duniter node. +## Duniter Ecosystem + +As you know, there are two types of clients in Duniter ecosystem : + +- Naive clients : These clients trust a given node and only one node. It trusts the administrator of the node. In case of cheating or in case of a bug, the client can be mistaken. The advantage of this behaviour is that the client is really smooth and fast. It doesn’t consume too much bandwith, and is compatible with small ressources endpoints. +- Simplified Verification clients : These clients trust the data they get because they request many nodes. They requests nodes identified by an identity, and as such, they are not sybillizable. The advantage of this behaviour is safety : the client request any data against multiple nodes. If one is cheating or buggy, its data wont match the data of other nodes. In such a case, this data will be ignored + +The problem with current API (Basic Merkled API) is that it’s not really merklized : when you require data, you can only get every things, to its smallest details. The consequence is that when you need to verify data, you can only request it again and again against multiple nodes, resulting in endless loading. + ## API standard It is important that we use an already known standard to avoid difficulty in contribution. And to get all the evolution and ideas coming from the community supporting the standard. @@ -69,12 +78,177 @@ Why ? - We make data changes **Verification** - This is an **API** ;-) -## Merckle Tree verification system +## Requests and answers proposal -To speed up the queries, we need to use intensively the Merckle Tree comparison system. +### Requests process -To do +1. The client sends a “Data Request” to a given node. It gets its answer, formed as a tree of data. +2. The client builds the Merkled Tree corresponding to this tree +3. The client send a “Verification request” to N given nodes. The verification request returns the root of the merkle tree. +4. The client compares the Root received by the verification nodes to the one he built, and validate or unvalidate the data + +These requests can be done in parallel. They should be sent to nodes that are on the same blockchain HEAD. + +Verification only concerns written state of data. Validity of the data can be insured thanks to hashes and signatures. + +### General form of the requests + +- The requests should be done using GraphQL (via HTTP or Websockets) +- The URI endpoint is unique. +- The Query should handle : + + The type of data requested + + The source of data : from the pools or from the blockchain. Data from the pools cannot be verified using a merkle tree : there are not guarantees that they are the same on every nodes. + + Filters (range, uid, pubkey, blockstamp, txhash…) + + The type of request (Data request or Verification) + +### State requests + +These requests have a merkle tree associated. They should be used to verify the state of a given data. + +They can be used on data in the blockchain or in the pool, as below : + +- If the data is found in the blockchain, its written field has a value and the hash is computed depending on this value +- If the data is found in the pool, its written field is empty. The hash is the hash of an empty string : e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +- If the data is not found, it returns a 404 (fixme: replace with GraphQL empty response) + +## Types + +We explore here each type of document to request. + +### Identity + +#### Identities data + +These datas are requested for a given triplet of `(uid/pubkey/blockstamp)`. + +These data are not the raw data of an Identity. Only the convenient data for a client software. + +The data we need when we request Identity informations are : + + Is it a member ? + Its signature + Its blockchain state : written or not-written + Its distance state : outdistanced or not + Its sentry state : sentry or not + Its membership state : if a document was sent, which one (IN or OUT) + If IN document + at which block + at which timestamp + Its revokation state : revoked or not revoked + If revoked : + at which block + at which timestamp + +**GraphQL Request:** + +Parameters are mandatory, this is the key to retrieve the Indentity. +Fields are optional like in any GrahQL query. + +```javascript + { + Identity(uid: "john", pubkey: "z7rDt7...", blockstamp: "22765-1AD84...") { + member + signature + written + outdistanced + sentry + MembershipState + RevokeState + } + } +``` + +**GraphQL Response:** + +```javascript +{ + "data": { + "member": True, + "signature": "c4zYpECnNa99xc8Np/6NXXSo6bK7eGVAdG8QcZE8ZhFZeZjCv0F1Zzeub1ZDnWm4/TvKK9PjpuQBv9tBn9hcAA==", + "written": True + "outdistanced": False, + "sentry": True, + "MembershipState": { + "type": "IN", + "blockstamp": "22965-7FD42...", + "timestamp": "229658678", + }, + "RevokeState": { + "revoked": True, + "blockstamp": "22965-7FD42...", + "timestamp": "229658678", + } + } +} +``` + +To get the full raw document type: + +```javascript +{ + IdentityRaw(uid: "john", pubkey: "z7rDt7...", blockstamp: "22765-1AD84...") +} +``` + +Returns: + +```javascript +{ + "data": { + "IdentityRaw": "Version: 10\n + Type: Identity\n + Currency: CURRENCY_NAME\n + Issuer: PUBLIC_KEY\n + UniqueID: USER_ID\n + Timestamp: BLOCK_UID\n + SIGNATURE" + } +} +``` + +**Calculate the Merckle Root Hash:** + +To be able to change version or add fields easily on data fields more often than raw document, +merckle check is done on raw document fields. + +```javascript +{ + result: Hash( + Hash(Hash(member), + + Hash(Hash(revocation.blockstamp), + Hash(revocation.timestamp), + Hash(revocation.signature) + Hash(Hash(revocation.written.blockstamp), + Hash(revocation.written.timestamp))? + )?, + Hash(expired), + Hash(outdistanced), + Hash(sentry)), + Hash(Hash(issuance.blockstamp),Hash(issuance.timestamp)), + Hash(Hash(written.blockstamp),Hash(written.timestamp)) + ) +} +``` + +Send the verification request: + +```javascript +{ + IdentityMerckleTree(uid: "john", pubkey: "z7rDt7...", blockstamp: "22765-1AD84...") +} +``` + +Return the root of the merckle tree: + +```javascript +{ + "data": { + "IdentityMerckleTree": "478D46A98F75..." + } +} +``` -## The server GraphQL Schema +## The GraphQL server code To do