NCOG Earth Chain Documentation

Decentralized Database (DDB) Data Contract Specification

Estimated reading: 33 minutes 53 views

Overview and Objectives

NCOG Earth Chain introduces JSON-based data contracts to define and manage off-chain SQL database state within the blockchain ecosystem. These data contracts integrate a decentralized PostgreSQL database (DDB) with the blockchain, allowing complex data operations (via SQL) under blockchain consensus guarantees. Each data contract is an on-chain artifact (identified by a unique address) that specifies:

  • The database schema (tables, columns, etc.) and allowed stored procedures (with conditional logic) which are compiled to PostgreSQL SQL/PLpgSQL.
  • Access control roles (e.g. admin, writer, reader) to restrict who can invoke particular procedures, enforced at the blockchain execution layer.
  • Gas metering policy to track and charge for resource consumption of database operations.
  • Upgradability provisions for versioning and schema evolution in a controlled, deterministic manner.
  • Deterministic execution rules to ensure all validators reach the same results for consensus (via a dual-consensus process).
  • Sandboxed operation, so each contract’s procedures affect only its own database state (no cross-contract or cross-database side effects).

This specification defines the standard JSON structure for NCOG data contracts and the rules governing their execution. The goal is to provide a clear, future-proof contract format that ensures security, determinism, and scalability by leveraging NCOG’s dual-consensus architecture (local DDB consensus + global chain consensus).

JSON Contract Structure

Each data contract is represented as a JSON object with well-defined fields. An example outline is shown below (keys and nesting illustrated):

{
  “contractName”: “YourContractName”,
  “contractAddress”: “NCOGXXXXXXXXXXXXXXXX”,
  “version”: 1,
  “author”: “NCOGYYYYYYYYYYYYYYYY”,
  “schema”: { … },
  “procedures”: [ … ],
  “permissions”: { … },
  “gasPolicy”: { … },
  “metadata”: { … }
}

Table 1. Top-Level JSON Fields

FieldTypeDescription
contractNamestringHuman-readable name of the contract (unique identifier for convenience).
contractAddressstringUnique on-chain address or ID of this contract. Used to reference the contract in transactions.
versionnumber or stringContract version number. Incremented for upgrades (supports schema evolution).
authorstringIdentifier of the contract creator (e.g. author’s chain account or public key).
schemaobjectDefinition of database schema (tables, columns, types, indexes, etc.) for this contract’s Postgres database.
proceduresarrayList of stored procedure definitions (allowed operations on the data).
permissionsobjectRoles and access control rules (who can call which procedures).
gasPolicyobjectGas metering and fee policy for operations under this contract.
metadataobjectOptional metadata (descriptions, tags, etc.) not critical to execution.

Each of these fields is detailed in the sections below. The JSON format is designed to be extensible – new fields may be added in future without breaking compatibility (unknown fields should be ignored by implementations). All fields necessary for execution and verification are included on-chain for transparency, meaning anyone can inspect a contract’s JSON to understand its data model and allowed actions.

Contract Identification (Name, Address, Version, Author)

contractName: A descriptive name for the contract. This is primarily for human reference (e.g., “UserDirectory” for a user database). It does not impact execution, but must be unique enough to distinguish contracts in practice.

contractAddress: The blockchain address or identifier for the contract. This is the reference used in transactions when calling the contract’s procedures. The address is set at deployment (for instance, derived from a hash of the contract or assigned by the system) and is immutable for the life of that contract. Every database transaction on the DDB includes the contract’s ID/address and the procedure being invoked, ensuring that all changes are tied to a specific contract and logged on-chain.

version: A version indicator for the contract’s schema and logic. This supports upgradability (see the Upgradability section). Typically an integer or semantic version string, it should increment with each deployed update. Combined with contractAddress, the <address, version> pair uniquely identifies the contract definition. If the contract is upgraded in-place (same address), the version is bumped. In a replacement upgrade (new contract deployment), a new address might be used, but referencing the prior contract in metadata (for example, via a prevContract link in metadata).

author: The chain account or identity of the contract’s author or deploying entity. This could be a public key or address (e.g., the account that signed the deploy transaction). This field establishes provenance and can also be used to verify who has upgrade privileges (often the author or an admin role is required to authorize upgrades).

Schema Definition

The schema field defines the relational database schema that this contract manages. It outlines the tables, columns, data types, and any constraints or indexes to be created in the decentralized PostgreSQL instance for this contract. By using a JSON schema description, the contract can precisely specify the structure of data it will store, and this description is compiled into SQL DDL (Data Definition Language) statements on the DDB.

A typical schema object might look like:

“schema”: {
  “tables”: [
    {
      “name”: “Users”,
      “columns”: [
        { “name”: “id”, “type”: “INT”, “constraints”: [“PRIMARY KEY”, “NOT NULL”] },
        { “name”: “name”, “type”: “TEXT”, “constraints”: [“NOT NULL”] },
        { “name”: “balance”, “type”: “INT”, “constraints”: [“DEFAULT 0”] }
      ],
      “indexes”: [
        { “name”: “idx_users_name”, “on”: [“name”] }
      ]
    },
    {
      “name”: “Transactions”,
      “columns”: [
        { “name”: “tx_id”, “type”: “INT”, “constraints”: [“PRIMARY KEY”] },
        { “name”: “user_id”, “type”: “INT”, “constraints”: [“NOT NULL”, “REFERENCES Users(id)”] },
        { “name”: “amount”, “type”: “INT” },
        { “name”: “timestamp”, “type”: “TIMESTAMPTZ” }
      ]
    }
  ]
}

In the above example, the contract defines two tables: Users and Transactions, with specified columns and simple constraints (primary keys, foreign key reference, etc.). When this contract is deployed, these definitions are translated into CREATE TABLE statements on the Postgres DDB for the contract’s own database namespace.

Key points:

  • The schema can contain multiple tables and may include column constraints (NULL/not NULL, default values, primary keys, foreign keys) and indexes. Only definitions allowed by the contract JSON can exist – no tables outside this schema can be created by the contract’s procedures.
  • The contract’s schema is isolated to a dedicated database or schema namespace within the DDB. This ensures that one contract’s tables never collide with or access another contract’s tables. Execution is sandboxed to the contract’s own data domain – cross-database or cross-contract mutations are disallowed by design (a contract cannot issue SQL that touches a table it didn’t define). This sandboxing is enforced both at the DDB level and by the blockchain execution layer.
  • The schema is published on-chain as part of the contract, providing transparency. All validators and users can see the exact structure of data allowed for that contract.
  • Determinism: The schema defines the state layout, and any changes to it (through upgrades) must be carefully managed. Schema definitions should avoid non-deterministic defaults or expressions. For example, using a default of NOW() for a timestamp column might be non-deterministic across nodes – such usage is discouraged unless the determinism is guaranteed by the execution engine (e.g., the leader node supplies the timestamp via WAL so others use the same value).

Stored Procedures

The procedures array contains the definitions of all stored procedures (or database functions) that the contract allows. These procedures encapsulate the permitted operations on the data (inserts, updates, deletes, queries, etc.) and include any conditional logic needed. No arbitrary SQL outside these defined procedures can be executed – this contract acts as the gatekeeper for database operations. By restricting operations to those in the contract, the system prevents unauthorized or unintended queries and ensures all state changes are validated.

Each procedure entry is a JSON object with fields such as:

  • name: (string) Procedure name (unique within this contract).
  • params: (array) Parameters accepted by the procedure, each with a name and data type (and possibly mode if needed).
  • body: (string or object) The procedure logic. This can be a high-level pseudo-code or domain-specific language representation that will be compiled to actual SQL/PLpgSQL. Conditional logic (e.g. IF/THEN/ELSE, loops) is permitted within the body, as the underlying PostgreSQL supports PL/pgSQL procedures.
  • returns: (optional, string) The return type or shape of data returned (if the procedure produces a result set or value).
  • role: (string) The minimum role or specific role required to execute this procedure (see Permissions). This field ties into the access control model (for example, “role”: “writer” means only users with writer or higher privilege can invoke it).

For example, a procedures list might include:

“procedures”: [
  {
    “name”: “createUser”,
    “params”: [
      {“name”: “userName”, “type”: “TEXT”}
    ],
    “body”: “INSERT INTO Users(name, balance) VALUES ($userName, 0);”,
    “returns”: “INT”,
    “role”: “admin”
  },
  {
    “name”: “updateBalance”,
    “params”: [
      {“name”: “userId”, “type”: “INT”},
      {“name”: “delta”, “type”: “INT”}
    ],
    “body”: “UPDATE Users SET balance = balance + $delta WHERE id = $userId;”,
    “returns”: “VOID”,
    “role”: “writer”
  },
  {
    “name”: “getUser”,
    “params”: [
      {“name”: “userId”, “type”: “INT”}
    ],
    “body”: “SELECT id, name, balance FROM Users WHERE id = $userId;”,
    “returns”: “RECORD”,
    “role”: “reader”
  }
]

In this example: – createUser inserts a new user with a default balance, and might return the new user’s ID. It is restricted to the admin role (only an admin can create users). – updateBalance modifies a user’s balance by a delta amount, allowed for writer role (writers or admins can do this update). – getUser reads a user’s data and is allowed for reader role (anyone with read access, as well as higher roles, can query).

Compilation to SQL: On deployment, each procedure is converted into an actual Postgres stored procedure or function in the DDB. The body may be provided as pure SQL/PLpgSQL or a higher-level representation. The system ensures that the compiled SQL is safe and deterministic. For instance, references to table names or columns not present in the schema would be rejected at compile time. Any conditional logic or loops in the procedure must ultimately translate to deterministic operations on the given state.

Determinism & Side Effects: Procedures must not perform any external calls or non-deterministic actions. They run entirely within the database context. All state changes occur via SQL statements which produce a write-ahead log (WAL) that is replicated to other validators for deterministic replay. This means that even if a procedure has complex logic, the outcome (the set of SQL writes) is captured and agreed upon. To maintain determinism, the following guidelines apply:

  • Use of random number generators, current timestamps, or any node-local volatile state in procedure logic is disallowed unless the value is passed in as an input or the same result is guaranteed to be applied on all nodes (e.g., provided via the leader’s WAL). This ensures all nodes see the same effects.
  • No direct DDL (schema changes) can be performed by procedures at runtime. Schema changes happen only via upgrades, not during normal transactions.
  • No cross-contract calls are allowed within a procedure. A procedure in Contract A cannot directly invoke a procedure in Contract B’s database as part of the same transaction. If cross-database interactions are needed, they must be orchestrated at the chain level as separate calls with a global transaction that coordinates both (such as a multi-contract atomic transaction requiring both contracts’ endorsements). This keeps each contract’s execution atomic and isolated.

By defining all allowed operations upfront in procedures, the contract provides a transparent, auditable interface to the off-chain database. Every call will specify which procedure is being invoked, and observers can verify that the procedure exists and what it is supposed to do. This significantly enhances security and auditability, as arbitrary or malicious SQL cannot be introduced outside these defined procedures.

Permissions and Access Control (Roles)

The permissions section of the contract defines role-based access control for procedure calls. It specifies what roles exist (and their hierarchy, if any), which blockchain accounts are assigned to those roles, and which procedures each role is allowed to invoke. These permissions are enforced by the execution layer before a transaction is executed in the DDB – if a user without sufficient privilege attempts to call a procedure, the call will be rejected or fail authorization.

We adopt a simple default role model with three standard roles: admin, writer, and reader (these are examples; the system may allow custom roles, but all contracts should support at least this basic set for consistency). Additional roles or fine-grained permissions can be introduced as needed, but the standard roles mean:

  • admin – Full control. Typically can perform any operation, including contract upgrades, management of other users’ roles, and all writer/read operations. Usually reserved for the contract creator or governing entity.
  • writer – Write access. Can execute procedures that modify state (inserts, updates, deletes) and also any read-only queries.
  • reader – Read access only. Can execute read-only/query procedures that do not alter state.

A sample permissions structure:

“permissions”: {
  “roles”: [“admin”, “writer”, “reader”],
  “assignments”: {
    “admin”: [“NCOG1QLDS…”],      // addresses with admin rights
    “writer”: [“NCOG1XYZ…”],     // addresses with writer rights
    “reader”: []                   // (could list addresses, or empty if all can read)
  },
  “procedureAccess”: {
    “admin”: [“*”],                // admin can call all procedures
    “writer”: [“updateBalance”, “…”],  // writer can call listed procedures (and implicitly any read ones)
    “reader”: [“getUser”, “…”]   // reader can only call read-only procedures
  }
}

Role Definitions: roles is an array listing the role names used. The standard expectation is that admin > writer > reader in terms of privilege hierarchy (admin includes writer and reader rights; writer includes reader rights). The contract can enforce this implicitly (for example, if a procedure requires “writer” role, an admin can also call it because admin is higher).

Assignments: assignments maps each role to a list of user addresses that initially hold that role. For instance, the contract author’s address might appear under admin. These assignments can potentially be changed through special admin-only procedures (for example, an addWriter(address) procedure could be included to grant writer role to new users, etc.). If the list for a role is empty, it implies no one initially holds that role (and it would have to be granted later), or in the case of reader, it could imply that read access is public (anyone can call read procedures, if the execution layer treats absence of a restriction as open access).

Procedure Access Rules: procedureAccess explicitly enumerates which procedures each role is allowed to invoke. This provides clarity and easy enforcement: when a transaction calls procedure X on this contract, the system checks the caller’s address role against these lists. A shorthand “*” can denote all procedures. In many cases, one can omit an explicit map and instead specify required roles in each procedure (as the role field in the procedure definition, as shown earlier). The implementation may derive procedureAccess from the procedures’ metadata; however, including it in the contract JSON can make the policy explicit. For example, if a procedure has “role”: “writer”, then effectively any address with role writer or higher (admin) can call it; an address with only reader role cannot.

Enforcement: The blockchain execution layer will verify the user’s signature and role before endorsing the operation: – Every transaction includes the caller’s identity. The contract’s permission data is checked to ensure the caller’s address is in a role that is authorized for the target procedure. – If not, the transaction is rejected ab initio (it never even reaches the point of execution on the DDB). This prevents unauthorized operations from even being attempted in the database. – Because permissions are enforced at protocol level, one cannot bypass them by directly interacting with the database; all writes must come through the contract interface (which includes this check). In effect, the data contract is the only gateway to mutate the database, and it will only allow those mutations that pass the access rules.

Role Management: Typically, the contract will include admin-only procedures to manage assignments (e.g., add or remove a writer or reader). The JSON standard does not dictate how roles are managed at runtime, only how they are initially defined and how enforcement is structured. But it is recommended that contracts provide means to update role assignments (especially for long-lived contracts). For instance, the admin might call a procedure grantRole(“writer”, targetAddress) to update the assignments internally (such procedures would themselves produce on-chain events or state changes reflecting the new permissions, possibly by updating an internal roles table rather than the immutable contract JSON).

Gas Policy and Resource Metering

Every database transaction executed via a data contract is gas-metered to prevent abuse and to integrate with the chain’s economic model. Similar to how smart contract platforms (like Ethereum) charge gas for computational steps, NCOG Earth Chain charges gas for database operations. The gasPolicy section of the contract describes how gas costs are determined for this contract’s operations and any contract-specific limits or parameters.

Key components that a gas policy may include:

  • Base Cost: a fixed gas cost per procedure invocation. This accounts for the overhead of handling a transaction, even if it’s a small read.
  • Per-Operation Costs: costs for specific types of operations, e.g.:
  • Per row read or scanned in a SELECT.
  • Per row inserted/updated/deleted.
  • Per index used or index entry updated.
  • Cost per SQL statement executed within a procedure (if a procedure has multiple statements).
  • Resource Weights: coefficients reflecting relative resource usage (CPU, I/O, memory). For example, one might specify that each returned row = 1 gas unit, each updated row = 5 gas units, each index lookup = 2 units, etc., based on the expected resource consumption.
  • Gas Limit: an optional maximum gas that any single call can consume (to force early termination of overly heavy transactions, akin to a block gas limit per tx).
  • Gas Distribution: although not contract-specific, this can note how the gas fee is allocated (e.g., what portion goes to the DDB validator nodes as reward for executing the SQL, versus the general validators or burned). This is usually a protocol-level parameter, but we document it for completeness: in NCOG, DDB fees are paid in the native token and may reward the DDB subset for their extra work.

An example gasPolicy (illustrative only):

“gasPolicy”: {
  “baseCost”: 100,              // flat cost per call
  “perRowRead”: 1,              // gas per row read
  “perRowWritten”: 5,           // gas per row inserted/updated/deleted
  “perIndexUsed”: 2,            // gas per index usage in a query
  “maxGasPerTx”: 100000         // absolute upper bound per transaction to abort runaway queries
}

Metering Execution: When a user calls a stored procedure, a DDB validator node will execute it and track resource usage. For example, it might count the number of rows affected, etc. This usage is then converted into a gas amount using the policy parameters. The process is analogous to Ethereum’s gas metering of opcodes, but applied to database operations.

After execution: – The actual gas cost is deducted from the user’s account balance (in the same way gas for a smart contract call would be). This deduction is recorded as part of the transaction’s effects, so all validators agree on it. – If a transaction would exceed the available gas (either the user-specified gas limit or a protocol-imposed maxGasPerTx), the execution is aborted partway (and any partial changes rolled back) to avoid DoS attacks or runaway queries. This is equivalent to an “out of gas” failure in Ethereum, ensuring a malicious or accidental expensive query cannot stall the network indefinitely. – The gas pricing serves as an economic guard: any heavy transaction has a proportional cost, disincentivizing spam. A user must pay for the CPU/IO workload their query imposes, which naturally regulates usage.

Consensus on Gas: Because the execution happens on potentially one node first (the one that leads the local consensus for that tx), it will calculate the gas used. That gas usage is included in the endorsement record. Other DDB validators either re-run the procedure or apply the provided WAL and verify that the reported gas usage matches the operations performed (for determinism, the gas metering itself must yield the same result on all honest nodes). The global chain consensus then deducts that amount from the user’s account as part of finalizing the transaction.

Thus, gasPolicy is partly informational (telling users/devs the expected costs) and partly normative (some values may be used by validators in executing the metering). The actual pricing model might be standardized across contracts by the protocol, but this field allows contracts to declare any custom multipliers or requirements if, say, a certain contract’s procedures are known to have different cost characteristics. In general, conservative defaults are used to ensure security.

Example: If updateBalance touches 1 row, and the policy is as above, the gas might be base 100 + 5 per row written = 105 gas. If getUser reads 1 row, cost might be 100 + 1 = 101 gas. This cost will be charged to the caller’s account in $NEC and logged with the transaction.

Upgradability and Schema Evolution

NCOG Earth Chain data contracts are designed to be upgradable so that schemas and procedures can evolve over time. Upgrades must be done in a controlled, transparent manner to avoid breaking consensus or allowing unauthorized changes. The contract JSON includes features to support versioning and migration:

  • Version Field: The version at the top level (as described earlier) indicates the iteration of the contract. A new version of a contract can be deployed when changes are needed (e.g., adding a new table or procedure, modifying logic). The blockchain can either treat this as a new contract (with a link to the old one) or update the existing contract’s definition in place (if a governance mechanism for contract upgrade exists). In either case, the version number must increment, and old versions remain available for audit.
  • Upgrade Authorization: Usually, only an admin (or a designated upgrade manager) of the contract can initiate an upgrade. This might involve a special transaction or on-chain governance proposal. The permissions can reflect this by treating contract upgrades as an admin-only action.
  • Schema Evolution: Changes to the schema are allowed but with constraints:
  • Backwards-compatible changes (like adding a new column with a default, adding a new table, or adding a new index) are straightforward: they can be described in a new contract version’s schema. The deployment of the new version will execute the necessary DDL on the DDB (e.g., an ALTER TABLE … ADD COLUMN or CREATE TABLE for new table).
  • Incompatible changes (removing or renaming columns, changing data types) require careful handling. The upgrade process should include migration logic to transform or migrate existing data to fit the new schema. This might be facilitated by special migration procedures. In practice, the upgrade could be a two-step process: (1) deploy new contract version, (2) run a migration procedure (possibly defined in the new contract or as part of upgrade transaction) to move data from old structure to new.
  • The specification allows an optional prevVersion reference or migration script in the metadata to describe how to port data. For example, metadata.migrationFrom = “v1” could indicate that the contract knows how to import state from version 1 (if, say, it added a column, it might fill it with a default or transform data).
  • State Continuity: The contract’s address ideally remains the same through an upgrade (so that external references to the contract are continuous). If a completely new contract address is used for the upgraded version, then the system should provide a way to atomically switch the active contract and retire the old one. In either approach, the old data must carry over. NCOG’s design anticipates that upgrades would be infrequent and possibly handled via special governance transactions if not an in-place upgrade.
  • Example Upgrade Scenario: Suppose version 1 of a contract lacks a certain table that is needed later. To upgrade: the admin deploys version 2 JSON, which includes the new table in the schema and perhaps new procedures. The deployment transaction for v2 is endorsed by the DDB validators (which will apply the schema changes under consensus) and finalized on-chain like any transaction. The contract’s definition is updated to v2. If data migration is needed (e.g., populating the new table with some derived data from existing tables), the admin might then call a special procedure (in v2) to perform that migration. All of this is auditable: the chain will show an event that contract at address X moved from v1 to v2 at block Y, with the new schema and code published.
  • Immutable vs Mutable Contracts: Simpler designs might treat contracts as immutable (no upgrades, only new deployments). NCOG supports upgradability for flexibility, but it is recognized that with great power comes responsibility: upgrades should be done carefully to avoid undermining trust. It is recommended that major contracts use multi-signature admin control or on-chain voting to authorize upgrades, to prevent a single compromised key from altering the contract arbitrarily. The upgrade process itself could require a dual-consensus: e.g., an upgrade transaction might need endorsement from the DDB committee (to ensure they can apply the new schema) and global consensus to be finalized, similar to normal operations but possibly with stricter checks.

The standard ensures that schema evolution is deterministic and agreed-upon. A schema change is treated as a state transition that all validators endorse, just like a data change. Thus, an upgrade cannot result in divergent schema across nodes – the DDB endorsement phase for the upgrade will guarantee that either all DDB nodes apply the new schema or none do (if the upgrade fails). In effect, it’s like a migration transaction under consensus.

Finally, because version and author are recorded, clients can always verify they are interacting with the correct version of a contract. If a contract is upgraded, users should retrieve the latest contract JSON from the blockchain to understand the current schema/procedures.

Execution Model and Deterministic Consensus

NCOG Earth Chain employs a dual-consensus architecture to execute data contract transactions. Each operation goes through two phases: a local consensus among the DDB nodes to agree on the database state changes, followed by inclusion in the global blockchain consensus for finality. The contract standard is designed to support this with deterministic outcomes. Below is the typical flow of a transaction invoking a data contract procedure:

  1. Transaction Submission: A user or dApp submits a transaction to the network, specifying the contract address, the procedure name to call, and the input parameters (along with the user’s signature and a proposed gas limit/fee). This transaction enters the DDB mempool (since it’s recognized as a database operation).
  2. Local Endorsement Phase: A subset of validators responsible for the DDB (the DDB validators) picks up the transaction for execution. One of them (e.g., the leader for this round) executes the stored procedure on its local PostgreSQL instance. This execution uses the current state of that contract’s database. The result of execution includes:
  3. The set of data changes (WAL entries consisting of inserts/updates/deletes to the contract’s tables).
  4. The output (return value or result set, if any, or a hash of it if the result is large or needs privacy).
  5. The gas used for the execution.
  6. A state hash or Merkle root representing the new state of the contract’s database (or incremental state change hash) after the transaction.

The executing node then proposes this transaction result to the other DDB validators. All DDB validators run a Byzantine Fault Tolerant (BFT) consensus (Phase 1) to endorse the result. They do this by either: – Replaying the exact WAL (write-ahead log) provided by the leader to apply the same changes, or – Independently re-executing the procedure using the contract’s schema and comparing the outcome.

If the majority (2f+1 out of 3f+1, etc., per BFT rules) agree on the result and state hash, they sign an endorsement. This endorsement proves that the transaction was valid, executed deterministically, and resulted in a certain new state. 3. Global Inclusion Phase: The endorsed result (including the procedure ID, hashed parameters, state hash, and validator signatures) is then packaged into a transaction for the global blockchain. The global validators (which include all nodes, even those not running the full database) run the main chain consensus (e.g., DAG-based BFT, the Forest Protocol) to order this transaction in a new block. Because the transaction comes with proof of execution (the DDB endorsements), the global layer does not need to re-run the SQL; it simply verifies the signatures and that the DDB committee approved it. The global consensus gives finality: once in a block and finalized, the transaction is irrevocably part of the ledger. 4. Commit and Finalization: Upon global finality, the transaction is considered committed. The DDB validators, seeing the transaction finalized, will commit the changes to the database permanently. (In practice, the local phase might have tentatively applied them, awaiting finality to commit). At this point, the contract’s database state is updated on all DDB nodes to the new version, and the changes are reflected in the globally agreed state hash. The gas fee is deducted from the user’s account as part of this final step, and any event logs or state hash are recorded on-chain. 5. Result Availability: If the procedure had a return value or output (say it was a query), the user can obtain this output from the node that executed it (or any that reproduced it). Since the procedure and its inputs are recorded, any observer could re-execute the read on their synced replica to get the result, or the result could be included in the endorsement (if not sensitive). For privacy, outputs may be hashed or encrypted on-chain, but the mechanism for private data is beyond this spec’s scope.

This dual-consensus approach ensures deterministic behavior and consistency: – The heavy lifting of SQL execution is done in a smaller circle of nodes (improving efficiency), but they cannot cheat because their result is double-checked by peers and anchored to the main chain. – By the time the global network sees the transaction, it has a definitive outcome (or it would have been rejected by the DDB phase). There is no chance for different global validators to apply the transaction differently — they all rely on the agreed result from DDB. – Any attempt by a malicious DDB node to produce an incorrect result would fail endorsement (honest nodes would catch a mismatch). Similarly, a malicious global validator cannot alter the outcome because the global chain requires the DDB signatures as proof. – Execution is order-deterministic because the global consensus provides a single ordering of transactions. Even though many transactions can be processed in parallel (thanks to the DAG and multi-mempool architecture), conflicting transactions on the same contract will be ordered by the time they reach finality, and the database state will reflect that serial order. The WAL replication ensures that if two transactions affect the same rows, their order of commits is consistent across all nodes.

No Cross-DB Side Effects: As noted, each data contract corresponds to one logical database. If a use case requires touching multiple contracts (databases) in one atomic action, the current approach is to break it into two transactions (one for each contract) coordinated by the main chain (possibly using a higher-level atomic commit protocol that the chain oversees). But one contract’s stored procedures cannot directly read or write another contract’s tables – this guarantees that the execution of a contract is self-contained and thus deterministic within its own context. Cross-database consistency, if needed, is achieved via on-chain coordination (e.g., a transaction that invokes two procedures in different contracts would need endorsements from both and then a global commit, as an atomic batch).

Consensus Determinism: Because one node’s execution results (WAL) are taken as the source of truth and endorsed, we avoid nondeterministic behavior across nodes – even if minor differences in execution (say, different query plan choices) could occur, they lead to the same final state which is codified in the WAL. All honest nodes end up with identical state or they would not sign off on the endorsement. The usage of PostgreSQL’s WAL for replication was chosen specifically to leverage its determinism in state application. The WAL records every data change explicitly, so applying the WAL yields the exact same result everywhere, regardless of how the operation was derived.

Future-Proofing and Extensibility

This JSON-based data contract standard is built with future-proofing in mind. As NCOG Earth Chain and its ecosystem evolve, the contract format and execution model can accommodate new features with minimal disruption:

  • Extensible Schema: The JSON structure can be extended with new fields. For instance, future versions might introduce a “triggers” section or a “views” section to define database triggers or SQL views as part of the contract. The current format allows adding such fields in a backward-compatible way. Implementations should ignore unknown fields, enabling smooth addition of features.
  • Multiple Database Shards: While presently a contract corresponds to one set of tables (one database instance), the architecture supports multiple DDBs (shards) in the network. The contract format could be extended to specify shard placement or to indicate if a contract’s data is split across shards. The dual-consensus approach remains effective even as more shards are added, and cross-shard (cross-contract) operations can be handled at the chain level.
  • Interoperability: Using standard PostgreSQL as the backend means we inherit a robust ecosystem of tools and data types. JSON data, full-text search, GIS types, etc., can be leveraged as needed. The contract format could incorporate these (e.g., allowing column type “JSONB” for a JSON field, or specifying an index of type GIN for full-text). This makes the platform adaptable to many use cases without custom solutions. It also means external applications (analytical tools, ORMs) can connect to a read-only replica of the DDB and use the schema directly.
  • Upgradable Design: As described, the versioning system allows for protocol upgrades. The network governance can evolve the rules for contracts (for example, introducing new permission types, or new system stored procedures for maintenance) by recognizing new JSON fields or new behaviors. The modular architecture of NCOG separates consensus, execution, and data layers, so improvements in one area (like a new consensus algorithm, or a new cryptographic primitive for signatures) can be integrated without redesigning the contract format. The contract acts as a well-defined interface between the blockchain layer and the SQL layer.
  • Deterministic Virtual Machine: In the future, NCOG might support alternative execution environments or languages for writing stored procedures (for example, a WASM runtime or a domain-specific language with formal verification). The contract JSON could be extended with a field indicating the procedure language (e.g., “language”: “PLpgSQL” or “language”: “WASM”), and possibly include the compiled bytecode. The design already anticipates adding support for more on-chain/off-chain blend, such as triggers that call back to on-chain logic. The JSON format can accommodate these by adding new sections or fields without breaking existing ones.
  • Security Upgrades: If new security features are needed (for example, marking certain data as confidential, with encryption that only certain nodes can decrypt), the contract metadata might include public keys or encryption flags for columns. Future versions of this specification could allow a “confidential”: true attribute on a column to indicate it’s stored encrypted in the DDB (and only readable by authorized parties via their Data Wallet). The current format is flexible enough to add such flags.
  • Inter-Contract Calls and Composition: While presently contracts operate in isolation, a future extension might allow one contract’s procedure to be invoked from another contract’s context (with proper consensus handling). The JSON could include an ABI-like description of callable interfaces. Until such features mature, the recommendation is to keep contracts separate and compose at the application layer or via multi-call transactions.

In summary, the data contract format and the NCOG Earth Chain architecture are built for longevity and adaptability. New stored procedures can be added and new data structures introduced as applications grow. By leveraging JSON and SQL – both widely-used, expressive standards – developers can transition their Web2 data models into Web3 with minimal friction, while the blockchain ensures security, integrity, and consensus.

Flexibility & Interoperability: The design choice of JSON for contract definition and Postgres for the database means that the system can interoperate with existing tools and standards. For example, JSON Schema validation could be applied to inputs, ORMs can map to the defined schema, and SQL queries can be optimized by the mature Postgres engine. The contract acts as a verifiable API for data operations: one can imagine blockchain explorers or dashboards reading the contract JSON and automatically generating documentation: “This contract provides procedures to create users, update balances, etc.”, along with the allowed parameters and required roles. This self-documenting nature aids developers and auditors alike.

Conclusion

NCOG Earth Chain’s JSON-based data contracts enable a powerful fusion of blockchain and relational database technology. By formalizing database schemas and stored procedures in an on-chain JSON specification, NCOG ensures that data-intensive applications can run with the benefits of SQL (rich queries, structured data) while retaining the trustlessness and transparency of blockchain. The standard structure outlined here – including contract metadata, schema, procedures, permissions, gas policy, and versioning – provides a clear, secure framework for developers to define their application’s data logic.

This specification emphasizes security (no unauthorized queries), determinism (all nodes agree on outcomes), scalability (offloading work to the DDB with parallel consensus) and governance (controlled upgrades), aligning with NCOG’s mission to support industrial-scale, data-heavy decentralized applications. As the platform evolves, this data contract standard can evolve as well, remaining backward-compatible and extensible to new functionalities. By following this specification, developers and the network collectively ensure that each data contract executes as a reliable, sandboxed “micro-database” service within the blockchain, with its behavior agreed by all and its state anchored on-chain for posterity.

Share this Doc

Decentralized Database (DDB) Data Contract Specification

Or copy link

CONTENTS