Solution blueprint


Cedalio is a platform that uses blockchain technology to build apps with information verifiability that is auditable by default. With Cedalio, the data used in your application can be traced back to its origin for verification and validation. Even more, with us you can give your users real ownership and portability of their data across different applications.
The platform architecture is designed in a way that developers and users can reap the benefits of decentralized data storage while maintaining the performance and convenience associated with conventional databases.

High level architecture

1 - GraphQL request

To initiate any GraphQL operation, begin with a standard GraphQL request using a GraphQL client of your choice. GraphQL operations are sent to a specific graph or database that lives within a project. The project owner defines the database schema using the GraphQL schema definition language. Then all databases created under such project use the same schema. GraphQL operations are sent to the database deployment GraphQL server under a URL similar to https://{project_id}.gtw.cedalio.io/deployments/{deployment_id}/graphql . Any valid GraphQL operation can be sent either in JSON or GraphQL format.
Request usually require authentication using a valid JWT (JSON Web Token) unless the database you want to access is configured in a publicly accessible mode (read more about access modes here). Upon receiving the request, our gateway proceeds to validate its JWT and then parse the GraphQL operation to check that it is an operation defined in the schema.

2 - JWT validation

The JWT validation consists of two steps. First, the system verifies that the JWT is not expired and it's properly signed. If the JWT is expired or incorrectly signed, the request is rejected, and the user must obtain a renewed JWT. Otherwise, it checks if the signed-in user has the right access capabilities (extracting them from the JWT claims) to send a request to the target gateway endpoint. If the request is a GraphQL operation sent to a database deployment's GraphQL server at /deployments/{deployment_id}/graphql , then it processed to verify with the on-chain access control layer if the operation is allowed.
If you want to know more about how to implement the authentication flow and how to obtain a valid JWT to talk to the GraphQL gateway, check out the Auth section.

3 - On-chain access control validation

After validating the request's JWT and parsing the GraphQL operation, the gateway converts the operation into a smart-contract database access request. Which means that the operation is translated into a method call sent to smart-contract where the authorization rules exist. Database owners can define different access rules, for example:
  • Address X can read object Y's fields A, B and C
  • Address Z can read all objects and can write all object T's fields
Therefore the GraphQL gateway checks with the smart-contract associated with the database being accessed that the received operation is allowed to be executed by the sender, identified by the wallet address located within the JWT. If the smart-contract does not allow the operation, the requester gets an "Unauthorized" error. Otherwise, the operation is sent to the database layer for execution.
Our smart contract should run on any EVM compatible networks but we are currently optimized for the Polygon Network, for different network integrations please contact us.

4 - Execute GraphQL operation

Once the authorization on-chain layer allows the GraphQL operation to be executed, it then gets converted into the proper database operations. Currently, we are using DynamoDB as the database behind the GraphQL server, but this is completely abstracted away (it is an implementation detail). The GraphQL operation, with all of its execution context (sender address, smart-contract address, gateway version, etc) gets sent to our operation log service, to be later committed into the database smart-contract and (optionally) backed up in a persistent decentralized storage solution like Filecoin or Arweave.

5 - Building the operation log

The operation service listens to the operations that were allowed to be executed by the on-chain authorization layer and (asynchronously) creates an operation log entry. The log entry is basically the raw GraphQL operation payload that was sent to server with extra contextual information. This contextual information is necessary to be able to re-execute and validate the operation at any point in time. The operation log entry is stored on the IPFS network. Operation log entries also include the CID of the previous entry, effectively linking each operation, making the operation order canonical.
Currently the operation log entry is stored as plain text but in the next version we will encrypt them allowing only the database smart-contract owner and delegate to decrypt it. The operation log service is also responsible for computing the database merkle root hash (created from each object field). It does this by first computing the hash of each object's field and the computing the intermediate merkle root paths until it gets a root hash for all the object's fields. Then it repeats this process for each object within and object type (or table). Finally it repeats this process again for each object type hash, effectively computing the database merkle root hash.

6 - Commit operation log entries

The operation log service is also responsible for committing the operation log entries into the database smart-contract (the same contract that stores the access control rules for a given graph database). It does it by sending a transaction to the smart-contract with the CID of the operation log entry and the smart-contract database access request generated in step 3. Then the smart-contract validates that database access request is valid and can be executed by the original sender and then stores the operation log entry CID. Therefore pointing to the latest entry.
The database owner, at any moment, can follow the operation log pointed by the smart-contract, decrypt each entry and execute them in reverse order to recreate the database and then validate that the database merkle root hash equals the one pointed by the smart-contract.
The frequency at which operation log entries are committed to the smart-contract is configurable. Currently we are committing each operation at a time immediately after receiving them. But an application developer could decide to configure the project to commit every 10 operations or every minute.

7 - Persistent decentralized backup

Optionally, project owners can configure operation log entries (that live on IPFS) to be backed up on a persistent decentralized storage network like Filecoin or Arweave. This ensure that data remains accessible even if Cedalio and its IPFS nodes cease to exist.