Nodes in the Chromia network
A node in the Chromia network is a computer, either a virtual or physical server, that runs the core Chromia software known as Postchain and the open-source relational database, PostgreSQL. Each node contains a unique cryptographic key pair and identifies itself on the network using its public key. Providers manage these nodes and contribute computing power to Chromia. In this section, we explore how Postchain powers the network by managing decentralized transaction processing and data storage.
Overview of Postchain
Postchain serves as the core software that controls blockchain operations and integrates them with the PostgreSQL relational database. It acts as the backbone of Chromia, enabling decentralized transaction processing and maintaining data consistency across multiple nodes.
Postchain handles several key tasks on Chromia's nodes, including:
- Transaction processing: It accepts and processes signed transactions submitted by users or applications.
- Consensus management: The system employs the eBFT (Enhanced Byzantine Fault Tolerance) consensus protocol to validate blocks and achieve agreement among nodes.
- Data storage: It interacts with PostgreSQL to store blockchain data, including the history of verified transactions and the states of each decentralized application (dapp) on its individual blockchain.
- Dapp code execution: It executes dapp-specific code written in the Rell programming language and translates operations into database actions that update the state of each dapp.
PostgreSQL integration and indexing
Postchain integrates with PostgreSQL to enable automatic data indexing, which allows Chromia to support complex relational queries directly on-chain. This integration significantly improves performance for both read and write operations, enhancing data accessibility and flexibility for developers. With these features, dapp developers can:
- Retrieve specific data points or datasets using advanced filters, thus avoiding the need to pull entire data arrays.
- Perform relational queries across multiple tables or entities, enabling complex on-chain data interactions without depending on off-chain processing.
These capabilities empower developers to build data-rich, complex dapps that leverage Chromia's on-chain database integration for optimal efficiency and functionality.
Transaction lifecycle on Postchain
The transaction lifecycle on Postchain involves several interconnected tasks that ensure proper reception, processing, and storage of each transaction. These tasks include:
Receiving transactions
To execute a transaction for a dapp on the Chromia network, a user or client can send the transaction to any node running the dapp via the node's REST API. Clients typically use a random strategy with fallback handling to distribute load across multiple nodes in the cluster and ensure high availability. This process involves sending the transaction to any available node within the cluster that hosts the dapp. Transactions follow Chromia's Generic Transaction Protocol (GTX) and consist of the following:
- The unique ID of the dapp chain on the network (known as the Blockchain RID).
- A list of operations and their corresponding arguments, which developers define in the dapp's code. This setup allows users to execute these operations through transactions and modify data, establishing the transaction's purpose.
- A list of signers along with their signatures.
Building blocks and verifying consensus
When a node receives a transaction, it quickly multicasts the transaction to all other nodes in the cluster. These nodes verify consensus using Chromia's eBFT algorithm, which is a modified version of Practical Byzantine Fault Tolerance. eBFT functions as a Proof-of-Authority (PoA) algorithm, allowing a select group of validator nodes to create new blocks. The validator nodes in the dapp's cluster work together to achieve consensus, ensuring that only valid transactions are added to the blockchain and that the network remains secure and resilient.
In the eBFT process, a node proposes a block, and the other validators accept the proposal if it receives a supermajority (more than two-thirds) of signatures. The validator nodes take turns creating the next block. This consensus process follows these steps:
- Any node in the cluster can receive transactions from clients. The primary node for the current round collects all incoming transactions within a specific (configurable) time interval and adds them to the proposed block for the current round.
- It multicasts the proposed block to all other nodes.
- Upon receiving the proposed block, the other nodes validate it by executing the transactions (without altering the database) and checking that the resulting state changes match the proposed block's state. If the block is valid, they sign it and multicast their signatures to all other nodes, including the primary node.
- Once the primary node receives signatures from more than two-thirds of the nodes, each node commits the block to its database.
The consensus algorithm can withstand nearly one-third of the nodes in a cluster acting maliciously, turning off, or isolating themselves from the rest of the network. After the network reaches consensus on a block of transactions, those transactions can be safely committed.
Dynamic block creation
Block creation in the network is dynamic and adapts to transaction activity. When transaction volume is high, blocks are produced more frequently; when activity is low, block intervals increase to reduce unnecessary block generation.
Block production is governed by three parameters:
Parameter | Description |
---|---|
minInterBlockInterval | Minimum time between two consecutive blocks. Ensures at least this much time (in milliseconds) passes between blocks. If there are pending transactions, a block is produced every minInterBlockInterval (e.g., 1 second on Economy Chain). |
maxTxDelay | Maximum time to wait after receiving the first transaction before starting block creation. If a new transaction arrives after a period of inactivity, a block is created after maxTxDelay (e.g., 1 second on Economy Chain), assuming minInterBlockInterval is satisfied. |
maxBlockTime | Maximum time to wait to create a block regardless of transaction activity. If no transactions are received, an empty block is created every maxBlockTime (e.g., 30 seconds on Economy Chain). |
These parameters are configurable per chain, allowing dapp chains to adjust block timing based on specific performance and throughput requirements.
Executing dapp code
Developers write dapps on the Chromia network using Rell, a programming language specifically designed for the platform. Rell simplifies the process of working with Chromia's relational blockchain model. When transactions occur, Postchain interprets and executes the dapp code, performing the specified operations and queries using the provided arguments in the transaction.
Updating the relational database
Each dapp on Chromia operates with its own instance of a relational database. When developers deploy a new dapp or update an existing one, Postchain interprets the dapp's code to determine the required database tables. It automatically creates the necessary tables and columns, ensuring that the dapp functions smoothly.
Postchain updates the database as transactions occur. When transactions invoke operations defined in the dapp's Rell code, Postchain translates this code into SQL queries, updating the dapp's data and state. Rell prevents developers from executing raw SQL queries directly, providing an abstraction that limits access to their own data while offering a more convenient and expressive way to interact with the database.
Additionally, Postchain stores system-level data in the relational database, including each dapp's blockchain and the history of verified transactions. If needed, developers can combine and replay this information to restore each dapp's database state at any block height, ensuring data integrity across the network.
Responding to queries
In addition to transactions that invoke operations and modify data, Chromia enables developers to perform read-only queries within decentralized applications (dapps). Similar to transactions, you typically execute queries using one of Chromia's client libraries. However, unlike transactions, nodes running Postchain quickly respond to read-only queries without needing to verify consensus. Due to Chromia's strong consensus guarantees and data integrity, querying a single node is sufficient for most applications. For specialized use cases requiring additional redundancy or when implementing custom failover strategies, you can optionally query multiple nodes and compare responses to ensure consistency.
You define queries in Rell, making them an integral part of the deployed code for a dapp. They automatically become part of the dapp's API and you can invoke them through a client library by providing the necessary arguments.
Transaction uniqueness
Each transaction has a unique RID, which is a Merkle hash of the transaction body without signatures. The EBFT consensus is used to finalize a single sequence of transactions. The RID ensures that two identical transactions cannot be included in the blockchain. All transactions are executed sequentially and atomically.
-
Merkle tree - Represents a binary tree structure used in cryptography where each leaf node contains a data block hash, and each non-leaf node contains the hash of its child nodes, enabling efficient and secure verification of data integrity.
-
Merkle hash - The resulting hash at any node in a Merkle tree, especially the root, which represents the combined hash of all underlying data blocks.
Below you can find an example of transaction data:
{
blockRID: string;
blockHeight: integer;
blockHeader: string;
witness: string;
witnesses: [string];
witnessSignatures: [string];
timestamp: integer;
txRID: string;
txHash: string;
txData: string;
}
The txRID
is the hash derived from the txData
without the signature; While the txHash
is the hash of the
transaction body with the signatures.
Chromia differs from the EVM in the following ways:
- It's impossible to change a transaction without changing its RID.
- All transactions are unique.
- There are no fees at the protocol level.
- There is no nonce at the protocol level - however, if nonce-like behavior is required at the dApp level, it can be
implemented using the
nop
operation, but that would be a separate operation which would become part of the transaction, and therefore it would already be a different transaction.
Dapp containers
Dapps on the Chromia network each receive dedicated compute and storage resources to ensure consistent performance. Each node in the network runs several instances of the core software, Postchain. The primary instance operates directly on the node machine and spawns containers (isolated virtual machines) to host specific dapps. This setup allows the main instance to efficiently route transactions and events to the relevant container. From an external perspective, each node functions as a single entity on the Chromia network, capable of accepting transactions intended for any of the dapps it hosts.
The relational database
Each dapp container hosts its own instance of a PostgreSQL relational database to support the respective dapp. This database stores:
- Dapp data, with tables corresponding to
entities
defined in the dapp's Rell code. - An individual blockchain for the dapp.
- A complete history of verified transactions related to the dapp.
- Node configuration settings, including addresses of peer nodes within the cluster.
- Replicas of the system chain.
Next up
After exploring the structure of nodes in the Chromia network, we will now examine the Chromia architecture.