Talking to the Blockchain — CVMContext Deep Dive

I. What CVMContext Is — And Why It Matters

Every revolution needs a bridge between worlds. The steam engine needed the drive shaft. The internet needed the browser. And GRIDNET OS — the world’s first fully decentralized operating system — needs CVMContext.

CVMContext (defined in /lib/VMContext.js) is the singular JavaScript singleton that connects your UI dApp, running inside a Shadow DOM in the user’s browser, to the entire decentralized stack beneath: the blockchain state machine, the decentralized filesystem, cryptographic identity, WebRTC swarms, consensus tasks, and more. It is not merely an API wrapper. It is the beating heart of every GRIDNET OS application — the central nervous system through which all signals flow.

If you are a web developer building on GRIDNET OS, this is the document you need. Every method. Every event. Every pattern. From first connection to final commit.

The architecture is deceptively simple. Your dApp is standard HTML, CSS, and JavaScript — skills you already have. CVMContext bridges that familiar world to the decentralized one. It communicates with GRIDNET Core full-nodes over WebSocket, serializing commands through the VM Meta Data Protocol (BER-encoded ASN.1) and the DFS Protocol for filesystem operations. The result is that your JavaScript code can navigate directories, read files, send value, deploy contracts, and subscribe to blockchain events — all through a clean, event-driven API.

// The most important line in any GRIDNET OS dApp
const ctx = CVMContext.getInstance();

That single call returns the global singleton. There is only ever one CVMContext — it manages the WebSocket connection, the session key negotiation, the filesystem abstraction, the swarm manager, the channels manager, the keychain, and all event dispatch. Everything flows through it.

II. Connection Lifecycle — From Boot to Ready

Connection lifecycle from WebSocket handshake to session establishment
The connection lifecycle: WebSocket establishment, cryptographic handshake, session key negotiation, and VM thread spawning.

When GRIDNET OS boots in the browser, the bootloader instantiates CVMContext with one or more full-node URIs. What follows is a carefully orchestrated dance of connection, cryptography, and state synchronization.

Phase 1: WebSocket Connection

The CVMContext constructor stores the provided node URIs and starts an internal controller thread (a JavaScript interval at ~2000ms) that manages state transitions. When the context enters the active state, it selects a node URI — either the “closest” one (based on a time-seeded hash heuristic) for the first connection, or a random one for reconnections — and opens a WebSocket.

// The bootloader does this internally:
const ctx = new CVMContext(['wss://node1.gridnet.org:26039', 'wss://node2.gridnet.org:26039']);
ctx.initialize();

Phase 2: Hello Handshake & Key Exchange

Once the WebSocket opens, CVMContext automatically sends a Hello Request containing a CSessionDescription with the browser’s ephemeral X25519 public key and a random challenge. The full-node responds with its own CSessionDescription. Through ECDH (Elliptic Curve Diffie-Hellman), both parties derive a shared session key used for all subsequent communication via ChaCha20-Poly1305 AEAD encryption.

Phase 3: System Thread Spawning

After the session key is established, the full-node spawns a System Thread — a dedicated decentralized processing thread for this connection. The thread ID is communicated back to CVMContext, which stores it. From this point, all GridScript commands execute within this thread’s context.

Connection States

The connection progresses through states defined by eConnectionState:

// Monitor connection state changes
CVMContext.getInstance().addConnectionStatusChangedListener(function(state) {
    switch(state) {
        case eConnectionState.disconnected:
            console.log('Disconnected from GRIDNET Core');
            break;
        case eConnectionState.connecting:
            console.log('Connecting...');
            break;
        case eConnectionState.connected:
            console.log('Connected and ready!');
            break;
        case eConnectionState.aboutToShutDown:
            console.log('Connection weakening (keepalive timeout approaching)');
            break;
    }
}, this.mID);

CVMContext handles reconnection autonomously. If the connection drops, the controller thread detects it and initiates a new connection to a randomly selected node. For keychain-based logins, the user session persists across reconnections — only QR-based sessions require re-authentication.

VM States

The virtual machine on the full-node also transitions through states tracked by eVMState:

// All eVMState values (from /lib/enums.js):
// eVMState.initializing          = 0  — VM is booting up
// eVMState.ready                 = 1  — VM is ready for commands
// eVMState.aboutToShutDown       = 2  — VM is about to shut down
// eVMState.disabled              = 3  — VM thread is disabled / unavailable
// eVMState.limitReached          = 4  — Resource limit reached
// eVMState.errored               = 5  — VM encountered an error
// eVMState.synced                = 6  — VM has been synchronized
// eVMState.newPerspectiveAvailable = 7 — New blockchain perspective available

CVMContext.getInstance().addVMStateChangedListener(function(arg) {
    // arg.state contains the eVMState value
    // arg.extended — if true, additional fields are available:
    //   arg.vmFlags, arg.vmID, arg.terminalID, arg.conversationID
    // arg.threadID — the thread this state applies to
    
    switch(arg.state) {
        case eVMState.initializing:
            console.log('VM is initializing...');
            break;
        case eVMState.ready:
            console.log('VM is ready — you can now execute commands');
            break;
        case eVMState.aboutToShutDown:
            console.log('VM is about to shut down');
            break;
        case eVMState.disabled:
            console.log('VM thread has been disabled');
            break;
        case eVMState.limitReached:
            console.log('Resource limit reached');
            break;
        case eVMState.errored:
            console.log('VM encountered an error');
            break;
        case eVMState.synced:
            console.log('VM synchronized');
            break;
        case eVMState.newPerspectiveAvailable:
            console.log('New perspective available — refresh state');
            break;
    }
}, this.mID);

III. Navigation API — cd, ls, pwd, and Domain Resolution

Decentralized filesystem navigation and operations
Navigating the decentralized filesystem: state domains as root directories, hierarchical paths, and familiar shell commands.

GRIDNET OS organizes all data into State Domains — analogous to user accounts or home directories — stored in Merkle Patricia Tries on the blockchain. Navigation within this filesystem feels intentionally familiar: it uses the same commands as Linux/DOS shells.

The filesystem is accessed through CVMContext.getInstance().getFileSystem, which returns the CFileSystem singleton. All filesystem operations ultimately compile to GridScript commands sent to the full-node.

Changing Directory: cd

const fs = CVMContext.getInstance().getFileSystem;

// Navigate to a state domain (like a user's home directory)
fs.doCD('/alice.gridnet', true, false, false, threadID);

// Navigate to a subdirectory
fs.doCD('documents', true, false, false, threadID);

// Navigate to root
fs.doCD('/', true, false, false, threadID);

The doCD(path, updatePWD, isAbsolute, silent, threadID) method sends a cd GridScript command to the full-node. The path can be absolute (starting with /) or relative. Each State Domain is a top-level directory under /.

Listing Directory Contents: ls

// List current directory
const reqID = fs.doLS(threadID);

// Listen for the result
CVMContext.getInstance().addNewDFSMsgListener(function(dfsMsg) {
    // DFS message contains VM Meta Data with directory listing
    // Parse entries from the response
}, this.mID);

Listing State Domains: csds

// List all state domains on the blockchain (like listing all user accounts)
// Executed as raw GridScript
CVMContext.getInstance().processGridScript('csds', threadID, processHandle);

Processing GridScript Commands Directly

For navigation and other operations, you can execute any GridScript command through the processGridScript() method:

const ctx = CVMContext.getInstance();

// Full signature:
// processGridScript(cmd, threadID, processHandle, mode, reqID)
//   cmd          — GridScript command string (default: "")
//   threadID     — Decentralized thread ID (default: system thread)
//   processHandle — Calling CWindow/process (REQUIRED for user-mode)
//   mode         — eVMMetaCodeExecutionMode (default: RAW)
//   reqID        — Request ID (default: 0, auto-generated)

// User-mode method (requires a valid process handle)
ctx.processGridScript('cd /alice.gridnet', threadID, myProcessHandle);
ctx.processGridScript('ls', threadID, myProcessHandle);
ctx.processGridScript('pwd', threadID, myProcessHandle);

// With explicit mode (e.g., for terminal-style output)
ctx.processGridScript('ls', threadID, myProcessHandle, eVMMetaCodeExecutionMode.GUITerminal);

Important: processGridScript() is a user-mode method that requires a valid process handle. Anonymous calls will be rejected. This is a security feature — every operation on the decentralized state machine must be attributable to a registered process. For kernel-mode usage (system processes), use processGridScriptKM() which accepts additional parameters including register and promiseInfo for async promise integration. There is also processGridScriptA() which returns a Promise for async/await usage.

IV. File Operations — Full CRUD on the Decentralized Filesystem

The decentralized filesystem supports complete CRUD operations. Each operation maps to a GridScript codeword that the full-node executes against the Merkle Patricia Trie state.

touch — Create an Empty File

// Create a new empty file
ctx.processGridScript('touch myfile.txt', threadID, processHandle);

write — Write Data to a File

// Write content to a file
ctx.processGridScript('write myfile.txt', threadID, processHandle);
// Note: content is provided through the DFS protocol's data fields

For file uploads, the FileManager dApp uses the DFS (Decentralized File System) protocol directly:

const fs = CVMContext.getInstance().getFileSystem;

// The DFS protocol handles file content through specialized messages
// Files can be stored as eternal (permanent) or voted (crowd-funded) storage
fs.doCommit(false, threadID); // Commit changes to blockchain

cat — Read File Contents

// Read a file's contents
ctx.processGridScript('cat myfile.txt', threadID, processHandle);

// Result arrives via GridScript result listener
ctx.addNewGridScriptResultListener(function(result) {
    if (result.reqID === myReqID) {
        // result.data contains the file content
        // result.types contains data type information
        console.log('File content:', result.data);
    }
}, this.mID);

mkdir — Create a Directory

ctx.processGridScript('mkdir documents', threadID, processHandle);

rm — Remove a File or Directory

ctx.processGridScript('rm myfile.txt', threadID, processHandle);

head / tail — Read Portions of Files

ctx.processGridScript('head myfile.txt', threadID, processHandle);
ctx.processGridScript('tail myfile.txt', threadID, processHandle);

Access Control: chown, setfacl, getfacl

// Change ownership of a file (base58-encoded address)
ctx.processGridScript('chown <base58address> myfile.txt', threadID, processHandle);

// Set access control list
ctx.processGridScript('setfacl <base58address> myfile.txt', threadID, processHandle);

// Get current ACL
ctx.processGridScript('getfacl myfile.txt', threadID, processHandle);

The DFS Commit Cycle

All filesystem modifications are transactional. Changes are staged locally and then committed to the blockchain through the DFS protocol. The commit cycle follows this pattern:

const fs = CVMContext.getInstance().getFileSystem;

// 1. Make changes (cd, mkdir, touch, write, rm...)
// 2. Synchronize
fs.doSync();

// 3. Commit changes to blockchain
fs.doCommit(false, threadID);

// 4. Listen for commit result
CVMContext.getInstance().addVMCommitStateChangedListener(function(state) {
    switch(state) {
        case eCommitState.prePending:
            console.log('Commit lock acquired locally');
            break;
        case eCommitState.pending:
            console.log('Full-node confirmed commit is pending');
            break;
        case eCommitState.success:
            console.log('Commit successful! Changes are on the blockchain.');
            break;
        case eCommitState.aborted:
            console.log('Commit was aborted');
            break;
    }
}, this.mID);

V. Transaction API — BT/CT, Sending Value, Deploying Contracts

Transaction lifecycle with BT and CT
The transaction lifecycle: BEGIN TRANSACTION (BT), execute operations, authenticate, COMMIT TRANSACTION (CT) — mapping directly to familiar SQL transaction semantics.

GRIDNET OS uses a transaction model that will feel instantly familiar to any database developer. BT (Begin Transaction) opens a transaction context, and CT (Commit Transaction) finalizes it. Between them, you can send value, deploy smart contracts, and modify blockchain state. This maps directly to SQL’s BEGIN/COMMIT paradigm.

Sending Value (GNC Transfer)

GRIDNET OS supports two transaction modes:

1. Remote Mode (Decentralized Threads API) — Commands are sent as GridScript to the full-node for compilation and execution:

// Remote transaction: full-node compiles and executes
const ctx = CVMContext.getInstance();

// The Wallet dApp constructs the GridScript command sequence:
let cmd = '';
cmd += 'BT ';                           // Begin Transaction
cmd += 'send ' + amount + ' ' + recipientAddress;  // Transfer value
cmd += ' CT';                            // Commit Transaction

ctx.processGridScript(cmd, threadID, processHandle, eVMMetaCodeExecutionMode.RAW);

// Authentication happens via QR code or local keychain signing
// The full-node sends a QRIntentAuth request that CVMContext handles

2. Local Mode (Trustless Browser Compilation) — The transaction bytecode is compiled locally using GridScriptCompiler and sent pre-compiled:

import { GridScriptCompiler } from '/lib/GridScriptCompiler.js';
import { CTransaction } from '/lib/Transaction.js';

// Compile GridScript locally
const compiler = new GridScriptCompiler();
const script = 'send ' + amount + ' ' + recipientAddress;
const result = await compiler.compile(script);

if (result.success) {
    // Create and sign the transaction locally
    const tx = new CTransaction();
    tx.setBytecode(result.bytecode);
    // ... set other transaction fields ...
    
    // Submit pre-compiled transaction
    const result = await ctx.submitPreCompiledTransactionA(
        tx.getPackedData(),
        processHandle,  // process handle (required)
        threadID,       // thread ID (optional)
        30000           // timeout in ms
    );
}

The Commit Lock Mechanism

Before any commit, your dApp must acquire the commit lock. This prevents multiple applications from attempting simultaneous commits:

const ctx = CVMContext.getInstance();

// 1. Try to acquire the commit lock
if (ctx.tryLockCommit(processHandle)) {
    // Lock acquired — proceed with commit
    
    // 2. Execute the commit
    ctx.commit(processHandle, false, 'system');
    
    // 3. The Magic Button UI changes to "committing" state
    // 4. Full-node sends commitPending → commitSuccess/commitAborted
} else {
    console.log('Another application is currently committing');
}

The lock has a timeout (mCommitLockTime, default 60 seconds). If the full-node doesn’t confirm within the timeout, CVMContext automatically retries up to 3 times with exponential backoff, then breaks the lock and sends an abort notification.

The submitPreCompiledTransactionA() Method

/**
 * Submits a pre-compiled transaction to the network (user-mode, async)
 * @param {Uint8Array|ArrayBuffer} txData - BER-encoded transaction bytecode
 * @param {Object} processHandle - Calling process (CWindow instance, required)
 * @param {ArrayBuffer} [threadID=new ArrayBuffer()] - Thread to execute on (default: system thread)
 * @param {number} [timeoutMS=30000] - Timeout in milliseconds
 * @returns {Promise} - Resolves with result on success
 */
async submitPreCompiledTransactionA(txData, processHandle, threadID = new ArrayBuffer(), timeoutMS = 30000)

VI. Identity & Authentication

Identity and authentication mechanisms
Two authentication paths: QR code scanning with the mobile app, or headless local keychain signing for seamless browser-only authentication.

Authentication on GRIDNET OS is cryptographic, not password-based. Your identity is your key pair. CVMContext provides two authentication pathways:

QR Code Authentication

The traditional flow: a QR code is displayed containing the connection’s conversation ID, the full-node’s address, and a random challenge. The user scans it with the GRIDNET Token mobile app, which signs the challenge with their private key and sends the signature back through the full-node.

// Trigger QR login
ctx.requestQRLogon();

// Listen for login
ctx.addUserLogonListener(function(sessionDesc) {
    console.log('User logged in:', ctx.getUserID);
}, this.mID);

Local Keychain Authentication (Headless)

The newer, browser-only flow. Users can store encrypted keychains locally (protected by a master password). On login, CVMContext decrypts the keychain and uses it to sign authentication challenges without any mobile device:

// Request login — automatically detects available keychains
await ctx.requestLoginChoice();

// Or directly request keychain login
await ctx.requestKeychainLogin();

// Check login status
if (ctx.isLoggedIn) {
    console.log('Logged in as:', ctx.getUserID);
    console.log('Keychain login:', ctx.mIsKeychainLogin);
}

Identity Properties

// Get current user ID (State Domain name / address)
ctx.getUserID              // → "alice.gridnet" or "Anonymous4521"

// Get full State Domain ID
ctx.getUserFullID          // → full state domain identifier

// Check if logged in
ctx.isLoggedIn             // → true/false

// Get user session description (contains pubkey, address, etc.)
ctx.getUserSessionDescription  // → CSessionDescription object

// Get key chain manager for programmatic key operations
ctx.getKeyChainManager     // → CKeyChainManager instance

Session Management

// Logout
await ctx.logout();

// Switch identity (keychain logins only)
await ctx.switchIdentity();

// Lock screen
await ctx.lockScreen();

VII. GridScript Compilation — The GridScriptCompiler

GridScript compilation pipeline
The GridScriptCompiler transforms human-readable GridScript source into V2 bytecode with keyword hash chains — enabling trustless browser-side transaction compilation.

The GridScriptCompiler is a pure JavaScript implementation that compiles GridScript source code into bytecode compatible with GRIDNET Core’s C++ VM. This enables local, trustless transaction compilation — your browser can construct valid blockchain transactions without relying on the full-node for compilation.

import { GridScriptCompiler } from '/lib/GridScriptCompiler.js';

const compiler = new GridScriptCompiler();

// Compile a simple value transfer
const result = await compiler.compile('send 100 recipientAddress');

if (result.success) {
    console.log('Bytecode:', result.bytecode);  // Uint8Array
    console.log('No errors');
} else {
    console.log('Compilation errors:', result.errors);
}

Bytecode Format

The compiler generates V2 bytecode by default:

V2: [VERSION_BYTE][32_BYTE_HASH][OPCODES...]

- VERSION_BYTE: 194 (0xC2) for V2
- 32_BYTE_HASH: SHA-256 keyword image hash chain
- OPCODES: Encoded codeword instructions

The keyword hash chain provides integrity verification: H₀ = SHA256("GRIDSCRIPT_V2_KEYWORD_IMAGE"), then Hₙ = SHA256(Hₙ₋₁ || keyword) for each compiled keyword. This ensures the bytecode hasn’t been tampered with.

Opcode Encoding

- ID ≤ 127: Single byte [ID]
- ID > 127: Two bytes [HIGH_BYTE | 0x80][LOW_BYTE] (little-endian with bit 7 set)

Key Codewords for dApp Developers

Codeword Opcode Description
cd 162 Change directory
ls 174 List directory contents
mkdir 165 Create directory
touch 262 Create empty file
rm 263 Remove file/directory
write 233 Write to file
cat 104 Read file contents
send 195 Transfer value (2 inline params)
balance 198 Query balance
chown 225 Change ownership (base58)
setfacl 223 Set access control (base58)
getfacl 227 Get access control
call 152 Call smart contract
echo 157 Output text
whoami 235 Current identity
info 199 Domain information

Encoding Utilities: CTools

The full CTools class is exported from /lib/tools.js and provides a comprehensive set of utilities — encoding, formatting, BigInt conversion, logging, GNC value formatting, and much more. This is the CTools that CVMContext itself uses internally.

Important distinction: /lib/GridScriptCompiler.js also exports a class named CTools, but it is a stripped-down, environment-agnostic version containing only crypto and encoding utilities (SHA-256, Base58Check, Base64Check). This lightweight version exists so the compiler can run in both browser and Node.js environments without DOM dependencies. If you need the full toolkit (GNC formatting, path parsing, byte vector comparison, logging, etc.), import from /lib/tools.js.

// Full CTools — used by CVMContext and most dApps
import { CTools } from '/lib/tools.js';
const tools = CTools.getInstance();

// Base58Check encode/decode (for addresses)
const encoded = await tools.encodeBase58Check(binaryData);
const decoded = await tools.decodeBase58Check(encodedString);

// Base64Check encode/decode
const b64 = await tools.encodeBase64Check(binaryData);

// SHA-256
const hash = await tools.sha256(data);

// String ↔ Bytes
const bytes = tools.stringToBytes('hello');
const str = tools.bytesToString(bytes);

// GNC value formatting
const formatted = tools.formatGNCValue(valueInAttoGNC, 5); // → "1.5 GNC"

// --- Stripped-down CTools for compiler/Node.js use ---
// import { CTools } from '/lib/GridScriptCompiler.js';
// Only has: encodeBase58Check, decodeBase58Check, encodeBase64Check,
//           decodeBase64Check, sha256, stringToBytes, bytesToString

VIII. The Event System — Subscriptions and State Notifications

Event-driven architecture with listeners
The event-driven architecture: register listeners, receive callbacks. Every state change, every network message, every block — all dispatched through a unified notification system.

CVMContext’s architecture is fundamentally event-driven. Rather than polling for state changes, you register callback functions that fire when specific events occur. Every listener method returns a unique listener ID that can be used for later removal.

Complete Event Listener Registry

Method Event
addConnectionStatusChangedListener(cb, appID) WebSocket connection state changes
addVMStateChangedListener(cb, appID) Decentralized VM state transitions
addVMCommitStateChangedListener(cb, appID) Commit operation state changes
addContextStateChangedListener(cb, appID) CVMContext internal state changes
addNewNetMsgListener(cb, appID) Raw network messages (CNetMsg)
addNewDFSMsgListener(cb, appID) DFS protocol messages
addVMMetaDataListener(cb, appID) VM Meta Data protocol messages
addNewGridScriptResultListener(cb, appID) GridScript execution results
addNewTerminalDataListener(cb, appID) Terminal I/O data
addNewAppDataListener(cb, appID) Application-specific data
addUserLogonListener(cb, appID) User login events
addUserActionRequestListener(cb, appID) User interaction requests (QR, password)
addUserNotificationsListener(cb, appID) System notifications
addNewKeyBlockListener(cb, appID) New key blocks appended to chain
addNewDataBlockListener(cb, appID) New data blocks appended to chain
addNewConsensusActionListener(cb, appID) Consensus task updates
addSessionKeyAvailableListener(cb, appID) Session key established
addOperationStatusListener(cb, appID) Operation status notifications
addNewSwarmSDPMsgListener(cb, appID) WebRTC SDP signaling messages
addDFSRequestCompletedListener(cb, appID) DFS request completion
addNewSearchResultsListener(cb, appID) Blockchain search results
addNewBlockDetailsListener(cb, appID) Block detail responses
addNewDomainDetailsListener(cb, appID) Domain detail responses
addNewTransactionDetailsListener(cb, appID) Transaction detail responses
addBlockchainStatsListener(cb, appID) Blockchain statistics

Pattern: Register → Listen → Unregister

class MyDApp extends CWindow {
    constructor() {
        super(/* ... */);
        
        // Register listeners — store the IDs for cleanup
        this.vmListenerID = CVMContext.getInstance()
            .addVMStateChangedListener(this.onVMStateChanged.bind(this), this.mID);
        this.dfsListenerID = CVMContext.getInstance()
            .addNewDFSMsgListener(this.onDFSMessage.bind(this), this.mID);
    }
    
    onVMStateChanged(arg) {
        if (arg.state === eVMState.ready) {
            this.loadData();
        }
    }
    
    onDFSMessage(dfsMsg) {
        // Process filesystem responses
    }
    
    // Clean up when window closes
    closeWindow() {
        CVMContext.getInstance().unregisterEventListenersByAppID(this.mID);
        super.closeWindow();
    }
}

Critical: Always unregister your listeners when your dApp window closes. Use unregisterEventListenersByAppID(appID) for bulk cleanup, or unregisterEventListenerByID(id) for individual removal.

IX. WebRTC Swarms — Cross-Browser Communication

WebRTC swarm mesh network
WebRTC Swarms: browsers communicate directly through peer-to-peer data channels, using GRIDNET Core nodes for ICE signaling.

GRIDNET OS includes a built-in WebRTC Swarms system that enables direct browser-to-browser communication without relying on the full-node for data transfer. The full-node serves only as the signaling server for ICE negotiation.

const ctx = CVMContext.getInstance();
const swarms = ctx.getSwarmsManager; // CSwarmsManager instance

// Join the global swarm
const swarmID = ctx.getMainSwarmID; // 'global'

// Listen for SDP signaling messages
ctx.addNewSwarmSDPMsgListener(function(sdpEntity) {
    // Handle WebRTC signaling
    // sdpEntity contains offer/answer/ICE candidates
}, this.mID);

// Get ICE server configuration
const iceServers = ctx.ICEServers;

The Messenger dApp demonstrates the full WebRTC pattern: SDP offer/answer exchange through the GRIDNET signaling infrastructure, ICE candidate gathering, and direct peer data channel establishment. This enables real-time messaging, file sharing, and collaborative features between browsers.

X. Blockchain Explorer API

CVMContext provides a comprehensive set of methods for querying blockchain data. Each method comes in two variants: a callback-based version (returns a request ID) and an async/Promise-based version (suffixed with A).

Async API Examples

const ctx = CVMContext.getInstance();

// Get blockchain status
const status = await ctx.getBlockchainStatusA(threadID, processHandle);

// Get recent blocks
const blocks = await ctx.getRecentBlocksA(10, 1, eSortBlocksBy.timestampDesc, 
    threadID, processHandle);

// Get recent transactions
const txs = await ctx.getRecentTransactionsA(10, 1, false, threadID, processHandle);

// Search the blockchain
const results = await ctx.searchBlockchainA('alice', 10, 1, null, 
    threadID, processHandle);

// Get domain details
const domain = await ctx.getDomainDetailsA('alice.gridnet', '', false, 
    threadID, processHandle);

// Get domain transaction history
const history = await ctx.getDomainHistoryA('alice.gridnet', 10, 1, 
    eSortTransactionsBy.timestampDesc, '', threadID, processHandle);

// Get block details
const block = await ctx.getBlockDetailsA(blockID, true, false, false, 
    threadID, processHandle);

// Get transaction details
const tx = await ctx.getTransactionDetailsA(txID, threadID, processHandle);

// Get blockchain height
const height = await ctx.getHeightA(false, threadID, processHandle);
const keyHeight = await ctx.getHeightA(true, threadID, processHandle);

// Get USDT price
const price = await ctx.getUSDTPriceA(threadID, processHandle);

// Get market data
const market = await ctx.getMarketDataA(true, true, 1, 50, null, 
    eSortOrder.ascending, threadID, processHandle);

// Subscribe to real-time updates
await ctx.subscribeToBlockchainUpdatesA(threadID, processHandle);

XI. Advanced Features — Token Pools, State-Less Channels, DFS

Advanced blockchain features
Advanced features: Multi-Dimensional Token Pools for custom tokens, State-Less Channels for instant off-chain payments, and DFS for decentralized file storage.

Token Pools

GRIDNET OS supports Multi-Dimensional Token Pools — custom tokens that can be deployed on the blockchain. The CStateLessChannelsManager and related classes handle token pool operations:

const ctx = CVMContext.getInstance();
const channels = ctx.getChannelsManager; // CStateLessChannelsManager

// User's token pools are tracked
const pools = ctx.getUserTokenPools;

// Token pool operations use GridScript:
// regPool — register a token pool
// getPool — query pool state
// xTT — transfer tokens
// poll — poll for updates

State-Less Channels

State-Less Channels provide instant, off-chain payment channels. They work by establishing a cryptographic commitment between parties that can be settled on-chain at any time:

const channels = CVMContext.getInstance().getChannelsManager;
// CStateLessChannelsManager handles channel lifecycle
// CStateLessChannel represents individual channels
// CTransmissionToken represents off-chain payment proofs

Process & Thread Management

// Create a JavaScript thread (runs in browser)
const threadID = ctx.createJSThread(
    myFunction,         // function to execute
    processID,          // owning process
    1000,              // interval in ms
    true,              // auto-start
    false              // kernel mode
);

// Stop a thread
ctx.stopJSThread(threadID);

// Create a decentralized thread (runs on full-node)
const reqID = ctx.createThread(threadID, processID);

// Free a decentralized thread
ctx.freeThread(threadID, processID);

// Send data to a thread
ctx.sendDataToThread(threadID, data);

Terminal Integration

// Send a line to the terminal
ctx.sendLine('ls -la\r\n', processID);

// Send a keystroke
ctx.sendKeyStroke(13, processID, threadID); // Enter key

// Send terminal dimensions
ctx.sendTerminalDimensions(24, 80, processID);

XII. Complete CVMContext Method Reference

Complete API reference
The complete CVMContext API — every method, property, and accessor available to your dApp.

Core Singleton & Identity

Method/Property Returns Description
CVMContext.getInstance(...nodeURIs) CVMContext Get or create the singleton instance
initialize() void Initialize all subsystems (called by bootloader)
genRequestID() number Generate a unique request ID
get getUserID string Current user identifier
set setUserID void Set user identifier
get getUserFullID string Full state domain identifier
get isLoggedIn boolean Whether a user session is active
get getUserSessionDescription CSessionDescription Current user session details
requestLoginChoice() void Show login method selection dialog
requestQRLogon() void Show QR code for mobile app login
requestKeychainLogin() Promise Login via local keychain
logout() Promise Logout and clear session
switchIdentity() Promise Switch sub-identity (keychain only)
lockScreen() Promise Lock screen requiring re-auth

Connection & State

Method/Property Returns Description
get getConnectionState eConnectionState Current WebSocket connection state
get getVMState eVMState Current VM state
get getState eContextState Context internal state
get getCommitState eCommitState Current commit operation state
get getFullNodeIP string Current full-node IP address
get getCurrentNodeURI string Current WebSocket URI
get getSessionKey ArrayBuffer Current session encryption key
get getConversationID ArrayBuffer Local conversation identifier
get getSystemThreadID ArrayBuffer System decentralized thread ID
get getIsCommiting boolean Whether a commit is in progress
forceNode(nodeURI) void Force connection to specific node
clearForcedNode() void Clear forced node selection
endConnection() void Terminate current connection

GridScript Execution

Method Returns Description
processGridScript(cmd, threadID, processHandle, mode?, reqID?) boolean|reqID Execute GridScript (user-mode, requires process handle). Defaults: mode=RAW, reqID=auto
processGridScriptA(cmd, threadID, processHandle, mode?, reqID?, timeoutMS?) Promise Execute GridScript (async/Promise-based, user-mode)
processGridScriptKM(cmd, threadID, processHandle, mode?, reqID?, register?, promiseInfo?) number|false Execute GridScript (kernel-mode, returns reqID)
submitPreCompiledTransactionA(txData, processHandle, threadID?, timeoutMS?) Promise Submit pre-compiled transaction bytecode (user-mode, async)
processVMMetaData(generator, processHandle) boolean Send VM Meta Data (user-mode)

Filesystem & Subsystems

Property Returns Description
get getFileSystem CFileSystem Decentralized filesystem interface
get getSwarmsManager CSwarmsManager WebRTC swarms manager
get getChannelsManager CStateLessChannelsManager State-less channels manager
get getKeyChainManager CKeyChainManager Local keychain manager
get getCryptoFactory CX25519 Cryptographic operations (ECDH, signing)
get getLocalDataStore CLocalDataStore Browser-local storage
get getWindowManager CWindowManager Window management
get getPackageManager CPackageManager dApp package management
get getSettingsManager CSettingsManager Per-user settings
get getDNS CDNS DNS resolution
get getMagicButton CMagicButton Magic Button (commit UI control)
get getMetaParser CVMMetaParser VM Meta Data parser
get getMetaGenerator CVMMetaGenerator VM Meta Data generator

Transaction & Commit

Method Returns Description
tryLockCommit(appHandle, breakLock) boolean Attempt to acquire commit lock
commit(appHandle, breakLock, threadID) boolean Execute commit operation
breakCommitLock(wasSuccess) void Release the commit lock
syncVM(breakCommit, processHandle) boolean Synchronize with VM state (user-mode)
syncVMKF(breakCommit, processHandle) boolean Synchronize with VM state (kernel-mode)
scopeSystemThread(scopeCommitTarget, scopeHomeDir) boolean Scope system thread to user’s domain
set setCommitTarget void Set target network (TestNet/MainNet)
get getCommitTarget eBlockchainMode Current target network
get getTotalPendingOutgressTransfer BigInt Total pending outgoing value

Thread & Process Management

Method Returns Description
createJSThread(funcPtr, processID, intervalMS, autoRun, isKernelMode) number Create a browser-side JS thread
stopJSThread(threadID) boolean Stop a JS thread
createThread(threadID, processID) number Create decentralized thread on full-node
freeThread(threadID, processID) boolean Free a decentralized thread
sendDataToThread(threadID, data, netMsgType) boolean Send data to a specific thread
getThreadByID(id) CThread|null Find thread by ID across all processes
getNewProcessID() number Generate new user-mode process ID
getNewThreadID(isKernelMode) number Generate new thread ID
registerProcessByWinHandle(windowHandle) boolean Register a CWindow as a process
unregisterProcess(processID) boolean Unregister a process
getProcessByID(id) CProcess Find process by ID
getProcessByThreadID(id) CProcess|null Find process owning a thread

Blockchain Explorer API

Method Returns Description
getRecentTransactions(size, page, includeMem, ...) reqID Get recent transactions (callback)
getRecentTransactionsA(size, page, ...) Promise<CSearchResults> Get recent transactions (async)
getRecentBlocks(size, page, sort, ...) reqID Get recent blocks (callback)
getRecentBlocksA(size, page, ...) Promise Get recent blocks (async)
searchBlockchain(query, size, page, flags, ...) reqID Search blockchain (callback)
searchBlockchainA(query, ...) Promise Search blockchain (async)
getBlockDetails(blockID, includeTX, ...) reqID Get block details (callback)
getBlockDetailsA(blockID, ...) Promise Get block details (async)
getDomainDetails(address, perspective, ...) reqID Get domain details (callback)
getDomainDetailsA(address, ...) Promise Get domain details (async)
getDomainHistory(address, size, page, ...) reqID Get domain tx history (callback)
getDomainHistoryA(address, ...) Promise Get domain tx history (async)
getTransactionDetails(txID, ...) reqID Get transaction details (callback)
getTransactionDetailsA(txID, ...) Promise Get transaction details (async)
getBlockchainStatus(...) reqID Get blockchain status (callback)
getBlockchainStatusA(...) Promise Get blockchain status (async)
getHeight(isKeyHeight, ...) reqID Get chain height (callback, cached)
getHeightA(isKeyHeight, ...) Promise<number> Get chain height (async, cached)
getUSDTPrice(...) reqID Get USDT price (callback)
getUSDTPriceA(...) Promise Get USDT price (async)
getLiveness(...) reqID Get liveness state (callback)
getLivenessA(...) Promise Get liveness state (async)
getTransactionDailyStats(days, ...) reqID Get daily tx stats (callback)
getTransactionDailyStatsA(days, ...) Promise Get daily tx stats (async)
getNetworkUtilization24h(...) reqID 24h network utilization (callback)
getNetworkUtilization24hA(...) Promise 24h network utilization (async)
getBlockSize24h(...) reqID 24h avg block size (callback)
getBlockSize24hA(...) Promise 24h avg block size (async)
getBlockRewards24h(...) reqID 24h avg rewards (callback)
getBlockRewards24hA(...) Promise 24h avg rewards (async)
getAverageBlockTime24h(...) reqID 24h avg block time (callback)
getAverageBlockTime24hA(...) Promise 24h avg block time (async)
getAverageKeyBlockTime24h(...) reqID 24h avg key-block time (callback)
getAverageKeyBlockTime24hA(...) Promise 24h avg key-block time (async)
getMiningDifficulty(count, start, end, ...) reqID Mining difficulty stats (callback)
getMiningDifficultyA(count, ...) Promise Mining difficulty stats (async, cacheable)
getMarketData(getMarketCap, getBalances, ...) reqID Market data (callback)
getMarketDataA(getMarketCap, ...) Promise Market data (async)
subscribeToBlockchainUpdates(...) boolean Subscribe to real-time updates
subscribeToBlockchainUpdatesA(...) Promise<boolean> Subscribe to updates (async)
unsubscribeFromBlockchainUpdates(...) boolean Unsubscribe from updates
unsubscribeFromBlockchainUpdatesA(...) Promise<boolean> Unsubscribe from updates (async)

Networking & Security

Method/Property Returns Description
sendNetMsg(msg, breakCommit, UINotifyOnError) boolean Send authenticated/encrypted CNetMsg
sendDFSMsg(msg, breakCommit) boolean Send DFS protocol message
notifyMobileToken(status, scope, reqID) boolean Send notification to mobile app via onion routing
notifyOperationStatus(status, scope, reqID) boolean Notify operation status to peer
get getKeyPair Object Ephemeral X25519 key pair
get ICEServers Array WebRTC ICE server configuration
set setDoSignOutgressMsgs void Enable/disable message signing
get publicIPAddress string Auto-detected public IP

UI & Logging

Method/Property Returns Description
logAppEvent(info, process, entryType, priority) void Log a user-mode application event
set setLoggingEnabled void Enable/disable logging
set setLogVMStatus void Enable/disable VM status logging
set setLogNetPackets void Enable/disable network packet logging
set setLogVMmeta void Enable/disable VM Meta Data logging
set setLogTerminalPackets void Enable/disable terminal packet logging
set setLogAppEvents void Enable/disable app event logging
addGUITask(task, dispatchNotifications) boolean Add a task to the GUI task queue
playSound(sound) void Play a system sound
enterFullscreen() void Enter fullscreen mode
exitFullscreen() void Exit fullscreen mode
set setGamingModeEnabled void Toggle performance/gaming mode

Consensus Tasks

Method Returns Description
addConsensusTask(task, isLocal) void Add a consensus task to the queue
getConsensusTaskByDescription(desc, subDesc) CConsensusTask|null Find task by description
get getConsensusTasks Array All pending consensus tasks
get getConsensusTasksCount number Number of pending tasks
clearPendngConsensusTasks() void Clear all pending tasks

XIII. Putting It All Together — A Complete dApp Pattern

Here is the canonical pattern for a GRIDNET OS UI dApp that uses CVMContext:

import { CWindow } from '/lib/window.js';

class MyDApp extends CWindow {
    
    static getPackageID() {
        return 'org.example.mydapp';
    }
    
    static getIcon() {
        return '/images/mydapp-icon.png';
    }
    
    constructor(x, y, w, h) {
        super(x, y, w, h, myHTMLBody, 'My dApp', MyDApp.getIcon(), false);
        
        const ctx = CVMContext.getInstance();
        
        // 1. Register for events
        ctx.addVMStateChangedListener(this.onVMStateChanged.bind(this), this.mID);
        ctx.addNewDFSMsgListener(this.onDFSMessage.bind(this), this.mID);
        ctx.addNewGridScriptResultListener(this.onGridScriptResult.bind(this), this.mID);
        ctx.addConnectionStatusChangedListener(this.onConnectionChanged.bind(this), this.mID);
        ctx.addVMCommitStateChangedListener(this.onCommitStateChanged.bind(this), this.mID);
    }
    
    onVMStateChanged(arg) {
        if (arg.state === eVMState.ready) {
            // VM is ready — safe to execute commands
            this.loadInitialData();
        }
    }
    
    onConnectionChanged(state) {
        if (state === eConnectionState.disconnected) {
            this.showDisconnectedUI();
        }
    }
    
    async loadInitialData() {
        const ctx = CVMContext.getInstance();
        
        if (ctx.getConnectionState !== eConnectionState.connected) {
            this.showNotConnectedError();
            return;
        }
        
        // Navigate to user's home directory
        const fs = ctx.getFileSystem;
        fs.doCD('/' + ctx.getUserID, true, false, false, this.getThreadID);
        fs.doLS(this.getThreadID);
    }
    
    onDFSMessage(dfsMsg) {
        // Handle filesystem responses
    }
    
    onGridScriptResult(result) {
        // Handle GridScript execution results
    }
    
    onCommitStateChanged(state) {
        // Handle commit lifecycle
    }
    
    // CRITICAL: Clean up listeners on close
    closeWindow() {
        CVMContext.getInstance().unregisterEventListenersByAppID(this.mID);
        super.closeWindow();
    }
}

XIV. Conclusion — The Bridge Is Open

CVMContext is not just an API — it is the philosophical bridge between the familiar world of web development and the uncharted territory of decentralized computing. Through it, every HTML form submission can become a blockchain transaction. Every file save can become an immutable state change. Every chat message can traverse a peer-to-peer mesh without touching a central server.

The design philosophy is clear: meet developers where they are. You don’t need to learn a new language. You don’t need to understand Merkle Patricia Tries. You don’t need to implement cryptographic protocols. CVMContext handles all of that. You write JavaScript. You subscribe to events. You call methods. The decentralized world opens up.

This is Article 4 in our UI dApp Developer Series. With the foundation laid in previous articles on Shadow DOM architecture and the WebUI framework, and with this deep dive into CVMContext, you now possess the knowledge to build production-grade decentralized applications on GRIDNET OS.

The bridge is open. Start building.

— The Wizards of GRIDNET OS

GRIDNET

Author

GRIDNET

Up Next

Related Posts