1. Introduction
Welcome to the GRIDNET OS Blockchain Explorer API documentation. This API provides UI dApps running within the GRIDNET OS web-browser subsystem the ability to query and interact with the underlying decentralized blockchain state machine. It allows developers to build applications that can visualize, search, and analyze blockchain data, including blocks, transactions, domain information (accounts), and various network statistics.
This document is intended for developers building UI dApps for GRIDNET OS who need to access blockchain information. It covers the API’s architecture, core concepts, method reference, data object descriptions, and event handling mechanisms.
Resources:
- For a technical overview of an UI dApp already using this API see here
- For GRIDNE OS UI dApp best design practices see here
- For a Tutorial including sample deployment described see here
- Want to see how it works? Just launch the Blockchain Explorer UI dApp here (available from GRIDNET OS’ Start Menu).
2. Architecture Overview
The Blockchain Explorer API is primarily exposed through the CVMContext
singleton object, which acts as the central bridge between the in-browser UI dApp environment and the remote GRIDNET Core nodes forming the decentralized network.
Key Architectural Points:
- Decentralized Nature: Unlike traditional client-server models, requests are processed by the distributed network of GRIDNET Core nodes.
CVMContext
handles selecting appropriate nodes (based on proximity or randomness) and managing the connection (typically WebSocket). - CVMContext: This singleton JavaScript object is the main entry point for all interactions with the GRIDNET OS backend, including the Blockchain Explorer API.
- GridScript: Under the hood, most Blockchain Explorer API calls are translated into specific
#GridScript
commands (e.g.,context -c getBlockDetails ...
). These commands are sent to a Core node for execution within a secure, sandboxed environment. - Decentralized Processing Threads: GRIDNET OS utilizes the concept of decentralized threads. API calls can optionally target specific threads (
threadID
). If not specified, they often default to system-managed threads (like the main data thread). - Asynchronous Communication: Communication between the UI dApp and Core nodes is inherently asynchronous. The API provides both non-async (returning a Request ID immediately) and async (
A
suffix, returning a Promise) methods. - Event-Driven Responses: Results from API calls are typically delivered back to the UI dApp via events. The dApp registers specific listeners (e.g.,
addNewBlockDetailsListener
) withCVMContext
to receive and process these responses. - BER Encoding & Meta Data Protocol: Data exchanged between the browser and Core nodes (especially complex data like block or transaction details) uses the GRIDNET Meta Data Protocol, which is BER (Basic Encoding Rules) encoded for efficient and standardized data representation.
CVMContext
handles the encoding/decoding internally. - Security: Communication can be secured using end-to-end encryption and authentication mechanisms managed by
CVMContext
based on session state and configuration.
Simplified Flow:
[UI dApp] --(JS API Call)--> [CVMContext] --(GridScript/BER)--> [WebSocket] --> [GRIDNET Core Node(s)]
^ |
| (BER/Event) |
+------------------------------------------------------------------------------------+
Under the Hood: GridScript Execution and the Decentralized Paradigm
Beneath the familiar JavaScript interface of the Blockchain Explorer API lies a fundamentally decentralized execution model powered by #GridScript. When a UI dApp calls an API method like CVMContext.getBlockDetailsA(), CVMContext doesn’t query a local database or send a request to a traditional centralized backend. Instead, it seamlessly translates the JavaScript call and its parameters into a specific #GridScript command string (e.g., context -c getBlockDetails -search “<blockID>” -tx). This GridScript command, representing the data request, is then packaged using the GRIDNET OS’s BER-encoded VM Meta Data exchange protocol and dispatched via WebSocket to a connected GRIDNET Core node. The Core node routes this command to an appropriate Decentralized Processing Thread (DPT), which hosts its own sandboxed GridScript virtual machine instance. This VM executes the received command, interacting directly with the node’s local view of the decentralized blockchain state machine to retrieve the requested block details.
The results are then packaged back into a BER-encoded VM Meta Data response, sent back through the network to the originating CVMContext, which decodes it and delivers the structured data (like a CBlockDesc object) back to the UI dApp, either by resolving the corresponding Promise or triggering a registered event listener. This entire process represents a paradigm shift from traditional Service-Oriented Architectures (SOA); requests are not handled by a centralized server running PHP or .NET against a central database, but are executed decentrally across the network by capable Core nodes running GridScript. This architecture inherently supports a future where such computational or data retrieval tasks performed by nodes could be incentivized, potentially through mechanisms like off-chain cryptocurrency micropayments, truly decentralizing not just data storage but also application logic execution.
Let’s take a look at how the execution environment is structured:
Now let’s better understand involvement of BER encoding as it’s involved:
Now, let’s go with a complete Blockchain Explorer API execution Cycle:
3. Core Concepts
3.1 Synchronous vs. Asynchronous API Methods
The API offers two styles for many methods:
- Non-Async (Synchronous-like Invocation): Methods like
getBlockDetails(...)
execute the request immediately and return a uniquerequest identifier
(a number > 0) if the request was successfully sent. The actual result arrives later via an event. The UI dApp needs to register a corresponding listener (e.g.,addNewBlockDetailsListener
) to handle the response, matching it using thereqID
field in the event argument. - Async (Promise-based): Methods ending with
A
(e.g.,getBlockDetailsA(...)
) return a JavaScriptPromise
. This Promise resolves with the result data when the response is received from the network or rejects if an error or timeout occurs. This simplifies handling asynchronous operations compared to managing request IDs and listeners manually.
Recommendation: Use the asynchronous (A
suffix) methods whenever possible for cleaner code structure using async/await
or .then()/.catch()
.
3.2 Event-Driven Architecture
Responses to API calls and real-time blockchain updates are delivered through events. UI dApps must register listener functions with CVMContext
using specific add...Listener
methods.
- Listeners: Functions provided by the UI dApp to handle specific types of data (e.g., block details, search results).
- Notifiers: Internal
CVMContext
methods (notify...
) that trigger the registered listeners when relevant data arrives. - Event Arguments: Listener functions receive an argument object, typically containing:
reqID
: The original request identifier (if applicable).data
or specific properties: The payload, often an instance of a data object class (e.g.,CBlockDesc
).- Other contextual information (e.g.,
processID
,source
).
3.3 Request/Response Flow & IDs
- API Call: The UI dApp calls an API method (e.g.,
CVMContext.getTransactionDetails(...)
). - Request ID Generation:
CVMContext
generates a uniquerequest identifier
(reqID
). - GridScript Formulation: The API method formats the corresponding
#GridScript
command. - Dispatch:
CVMContext
(viaprocessGridScriptKM
) sends the command (encapsulated in Meta Data) over the network. The non-async method returns thereqID
immediately. The async method registers the Promise internally using thisreqID
. - Network Processing: GRIDNET Core nodes process the request.
- Response Delivery: The result is sent back via WebSocket, BER-encoded within the Meta Data protocol.
- Response Processing:
CVMContext
receives the message, decrypts/authenticates if necessary, parses the Meta Data, and identifies the relevant data and originalreqID
. - Notification/Resolution:
CVMContext
triggers the appropriate notifier function (e.g.,notifyNewTransactionDetails
).- The notifier function iterates through registered listeners, calling their callback functions with the response data and
reqID
. - If the request was made using an async (
A
) method,CVMContext
finds the corresponding pending Promise using thereqID
and resolves it with the data (viaresolvePendingRequest
).
3.4 Decentralized Processing Threads (threadID
)
GRIDNET OS allows operations to be executed within specific decentralized processing threads. Most Blockchain Explorer API methods accept an optional threadID
(as an ArrayBuffer
).
- If provided, the operation targets that specific thread.
- If omitted or an empty
ArrayBuffer
is provided, it usually defaults to a system-managed thread (often the main Data Thread, accessible viaCVMContext.getDataThreadID
). - The main System Thread (
CVMContext.getSystemThreadID
) handles core system operations.
3.5 Process Handles (processHandle
)
Many API methods require a processHandle
. This is typically the instance of the UI dApp’s main class (which usually extends CWindow
). It’s used for:
- Authorization: Ensuring that API calls originate from a registered, valid UI dApp process. Anonymous calls are often disallowed.
- Context: Linking the API request to the specific application making the call.
- Resource Management: Potentially used by the system to manage resources associated with the dApp’s requests.
3.6 Execution Modes (mode
)
The mode
parameter (using the eVMMetaCodeExecutionMode
enum) specifies how the underlying GridScript command should be executed and how results should be returned. For the Blockchain Explorer API:
eVMMetaCodeExecutionMode.RAW
: Typically used. Returns raw, structured data objects (likeCBlockDesc
) suitable for programmatic use.eVMMetaCodeExecutionMode.GUI
: Might return data formatted for direct display in a terminal-like UI (less common for this API).
3.7 Data Objects
The API uses specific classes to represent blockchain entities:
CBlockDesc
: Block details.CTransactionDesc
: Transaction details.CDomainDesc
: Domain/account details.CSearchResults
: Container for search results, holding multiple items of the above types.CSearchFilter
: Used to define complex search criteria.
These objects provide methods for accessing properties and often include serialization (getPackedData
) and deserialization (instantiate
) methods for BER encoding.
4. API Reference
This section details the public methods provided by CVMContext
for the Blockchain Explorer API.
4.1 Data Retrieval Methods
getRecentTransactions(size, page, includeMem, threadID, processHandle, mode, reqID)
Retrieves a list of recent transactions from the blockchain.
- Parameters:
size
{number
} [Optional, Default: 10] – Number of transactions per page.page
{number
} [Optional, Default: 1] – Page number to retrieve (1-based).includeMem
{boolean
} [Optional, Default: false] – If true, includes transactions from the memory pool (unconfirmed).threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process (required for user-mode calls).mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use (0 generates a new one).
- Returns: {
number
} – A request identifier (reqID > 0
) if the request was sent successfully, otherwise 0. - Underlying GridScript:
context -c getRecentTransactions -size <size> -page <page> [-mem]
- Response Event:
addNewSearchResultsListener
(Results delivered within aCSearchResults
object containingCTransactionDesc
instances). - Async Version:
getRecentTransactionsA(...)
->Promise<CSearchResults>
- Example (Non-Async):
const vmContext = CVMContext.getInstance();
const processHandle = this; // Assuming 'this' is the UI dApp instance
const listenerId = vmContext.addNewSearchResultsListener((event) => {
if (event.reqID === myReqId && event.results instanceof CSearchResults) {
console.log(`Received ${event.results.getResultCount()} recent transactions.`);
// Process event.results containing CTransactionDesc objects
vmContext.unregisterEventListenerByID(listenerId); // Clean up listener
}
});
const myReqId = vmContext.getRecentTransactions(20, 1, false, undefined, processHandle);
if (!myReqId) {
console.error("Failed to send request for recent transactions.");
vmContext.unregisterEventListenerByID(listenerId);
} else {
console.log("Request sent with ID:", myReqId);
}
- Example (Async):
async function fetchRecentTxs() {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
const searchResults = await vmContext.getRecentTransactionsA(20, 1, false, undefined, processHandle);
console.log(`Received ${searchResults.getResultCount()} recent transactions.`);
searchResults.getAllResults().forEach(resultData => {
if (resultData.getValue() instanceof CTransactionDesc) {
const tx = resultData.getValue();
console.log(`TX ID: ${tx.verifiableID}, Value: ${tx.value}`);
}
});
} catch (error) {
console.error("Error fetching recent transactions:", error);
}
}
fetchRecentTxs();
getRecentBlocks(size, page, sortBlocksByEnumVal, threadID, processHandle, mode, reqID)
Retrieves a list of recent blocks from the blockchain.
- Parameters:
size
{number
} [Optional, Default: 10] – Number of blocks per page.page
{number
} [Optional, Default: 1] – Page number to retrieve (1-based).sortBlocksByEnumVal
{eSortBlocksBy
} [Optional, Default:timestampDesc
] – The sorting criteria (use values fromeSortBlocksBy
enum).threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process.mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – A request identifier (reqID > 0
) if sent successfully, otherwise 0. - Underlying GridScript:
context -c getRecentBlocks -size <size> -page <page> -sort <sortBlocksByEnumVal>
- Response Event:
addNewSearchResultsListener
(Results delivered within aCSearchResults
object containingCBlockDesc
instances). - Async Version:
getRecentBlocksA(...)
->Promise<CSearchResults>
- Example (Async):
async function fetchRecentBlocks() {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
const searchResults = await vmContext.getRecentBlocksA(15, 1, eSortBlocksBy.heightDesc, undefined, processHandle);
console.log(`Received ${searchResults.getResultCount()} recent blocks.`);
searchResults.getAllResults().forEach(resultData => {
if (resultData.getValue() instanceof CBlockDesc) {
const block = resultData.getValue();
console.log(`Block Height: ${block.height}, ID: ${block.blockID}`);
}
});
} catch (error) {
console.error("Error fetching recent blocks:", error);
}
}
fetchRecentBlocks();
getTransactionDailyStats(days, includeMem, threadID, processHandle, mode, reqID)
Retrieves daily statistics about transaction activity over a specified number of days.
-
- Parameters:
days
{number
} [Optional, Default: 14] – The number of past days to retrieve statistics for.includeMem
{boolean
} [Optional, Default: false] – If true, includes unconfirmed transactions in the statistics.threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process.mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – A request identifier (reqID > 0
) if sent successfully, otherwise 0. - Underlying GridScript:
context -c getTransactionDailyStats -days <days> [-mem]
- Response Event:
addBlockchainStatsListener
(Event argumentarg.data
contains the statistics, usually an array or object with date/count/volume pairs). - Async Version:
getTransactionDailyStatsA(...)
->Promise<Object|Array>
- Example (Async):
async function fetchTxStats() {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
const stats = await vmContext.getTransactionDailyStatsA(30, false, undefined, processHandle);
// Assuming stats is { dates: [...], counts: [...], volumes: [...] }
console.log(`Received stats for ${stats.dates.length} days.`);
// Process stats for charting or display
} catch (error) {
console.error("Error fetching transaction stats:", error);
}
}
fetchTxStats();
- Parameters:
<code
getBlockchainStatus(threadID, processHandle, mode, reqID)
Retrieves the overall status of the blockchain, potentially including total supply, current heights, and network status.
- Parameters:
threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process.mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – A request identifier (reqID > 0
) if sent successfully, otherwise 0. - Underlying GridScript:
context -c getBlockchainStatus
- Response Event:
addBlockchainStatsListener
(Event argumentarg.data
contains status information liketotalSupply
,height
,keyHeight
). - Async Version:
getBlockchainStatusA(...)
->Promise<Object>
- Example (Async):
async function fetchStatus() {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
const status = await vmContext.getBlockchainStatusA(undefined, processHandle);
console.log(`Blockchain Status: Height=${status.height}, KeyHeight=${status.keyHeight}, Supply=${status.totalSupply}`);
} catch (error) {
console.error("Error fetching blockchain status:", error);
}
}
fetchStatus();
getMarketData(getMarketCap, getBalances, page, pageSize, sortType, sortOrder, threadID, processHandle, mode, reqID)
Retrieves market data, including total market capitalization and/or domain balances, with sorting and pagination.
- Parameters:
getMarketCap
{boolean
} [Optional, Default: false] – If true, retrieve total market cap (-d
flag).getBalances
{boolean
} [Optional, Default: true] – If true, retrieve domain balances (-b
flag).page
{number
} [Optional, Default: 1] – Page number for balance results.pageSize
{number
} [Optional, Default: 50] – Number of domain balances per page.sortType
{eMarketSortType
} [Optional, Default: null] – Criteria for sorting domain balances (e.g.,eMarketSortType.balance
).sortOrder
{eSortOrder
} [Optional, Default:ascending
] – Sort order (ascending
ordescending
).threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process (required).mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – A request identifier (reqID > 0
) if sent successfully, otherwise 0. - Underlying GridScript:
market [-d] [-b] -page <page> -size <pageSize> [-sort <sortTypeStr>] [-asc | -desc]
- Response Event:
addBlockchainStatsListener
(for market cap) and/oraddNewSearchResultsListener
(for domain balances, delivered inCSearchResults
containingCDomainDesc
). - Async Version:
getMarketDataA(...)
->Promise<Object>
(The resolved object structure depends ongetMarketCap
andgetBalances
flags). - Example (Async – Get Top 10 Richest Domains):
async function fetchTopDomains() {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
// Request balances, sort by balance descending, page 1, size 10
const marketResults = await vmContext.getMarketDataA(
false, // Don't need total market cap
true, // Need domain balances
1,
10,
eMarketSortType.balance,
eSortOrder.descending,
undefined,
processHandle
);
// marketResults likely contains the data within a CSearchResults structure
// accessible through the listener or directly if the promise resolves with it.
console.log(`Received ${marketResults.getResultCount()} top domains.`);
marketResults.getAllResults().forEach(resultData => {
if (resultData.getValue() instanceof CDomainDesc) {
const domain = resultData.getValue();
console.log(`Domain: ${domain.domain}, Balance: ${domain.balanceTxt}`);
}
});} catch (error) {
console.error("Error fetching market data:", error);
}
}
fetchTopDomains();
searchBlockchain(query, size, page, flags, threadID, processHandle, mode, reqID)
Performs a general search across the blockchain for blocks, transactions, or domains matching the query.
-
- Parameters:
query
{string
} – The search term (e.g., block ID, transaction ID, domain name).size
{number
} [Optional, Default: 10] – Maximum number of results per page.page
{number
} [Optional, Default: 1] – Page number for results.flags
{CSearchFilter
|number
|string
|Array<string>
} [Optional, Default: null] – Search filter. Can be:- A
CSearchFilter
instance for complex filtering. - A number representing a bitmask of standard flags (
TRANSACTIONS
,DOMAINS
,BLOCKS
). - A Base58Check encoded string representing the filter.
- An array of standard flag names (e.g.,
['TRANSACTIONS', 'BLOCKS']
). - If
null
, defaults may apply on the Core node.
- A
threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process.mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – A request identifier (reqID > 0
) if sent successfully, otherwise 0. - Underlying GridScript:
context -c searchBlockchain -search "<query>" -size <size> -page <page> [-flags <flags>]
- Response Event:
addNewSearchResultsListener
(Results delivered within aCSearchResults
object, potentially containing mixed types). - Async Version:
searchBlockchainA(...)
->Promise<CSearchResults>
- Example (Async – Search for a specific ID):
async function search(queryTerm) {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
// Search only for blocks and transactions
const filter = new CSearchFilter(CSearchFilter.NO_STANDARD); // Start with no standard flags
filter.setStandardFlags(CSearchFilter.StandardFlags.BLOCKS);
filter.setStandardFlags(CSearchFilter.StandardFlags.TRANSACTIONS);const searchResults = await vmContext.searchBlockchainA(queryTerm, 10, 1, filter, undefined, processHandle);
console.log(`Found ${searchResults.getTotalResultCount()} results.`);
// Process results (could be CBlockDesc or CTransactionDesc)
} catch (error) {
console.error(`Error searching for "${queryTerm}":`, error);
}
}
search("some_block_or_tx_id");
- Parameters:
getNetworkUtilization24h(threadID, processHandle, mode, reqID)
Retrieves the average network utilization percentage over the last 24 hours.
- Parameters: See
getBlockchainStatus
. - Returns: {
number
} – Request ID (reqID > 0
). - Underlying GridScript:
context -c getNetworkUtilization24h
- Response Event:
addBlockchainStatsListener
(Eventarg.data
contains the utilization percentage). - Async Version:
getNetworkUtilization24hA(...)
->Promise<number>
getBlockSize24h(threadID, processHandle, mode, reqID)
Retrieves the average block size in bytes over the last 24 hours.
- Parameters: See
getBlockchainStatus
. - Returns: {
number
} – Request ID (reqID > 0
). - Underlying GridScript:
context -c getBlockSize24h
- Response Event:
addBlockchainStatsListener
(Eventarg.data
contains the average size in bytes). - Async Version:
getBlockSize24hA(...)
->Promise<number>
getBlockRewards24h(threadID, processHandle, mode, reqID)
Retrieves the average block rewards (in attoGNC) over the last 24 hours.
- Parameters: See
getBlockchainStatus
. - Returns: {
number
} – Request ID (reqID > 0
). - Underlying GridScript:
context -c getBlockRewards24h
- Response Event:
addBlockchainStatsListener
(Eventarg.data
contains the average reward as BigInt). - Async Version:
getBlockRewards24hA(...)
->Promise<BigInt>
getAverageKeyBlockTime24h(threadID, processHandle, mode, reqID)
Retrieves the average time between key blocks in seconds over the last 24 hours.
- Parameters: See
getBlockchainStatus
. - Returns: {
number
} – Request ID (reqID > 0
). - Underlying GridScript:
context -c getAverageKeyBlockTime24h
(Note: CVMContext code currently usesgetAverageBlockTime24h
GridScript, might be an inconsistency). - Response Event:
addBlockchainStatsListener
(Eventarg.data
contains the average time in seconds). - Async Version:
getAverageKeyBlockTime24hA(...)
->Promise<number>
getAverageBlockTime24h(threadID, processHandle, mode, reqID)
Retrieves the average time between all blocks (data and key) in seconds over the last 24 hours.
- Parameters: See
getBlockchainStatus
. - Returns: {
number
} – Request ID (reqID > 0
). - Underlying GridScript:
context -c getAverageBlockTime24h
- Response Event:
addBlockchainStatsListener
(Eventarg.data
contains the average time in seconds). - Async Version:
getAverageBlockTime24hA(...)
->Promise<number>
getBlockDetails(blockID, includeTX, includeMem, includeSec, threadID, processHandle, mode, reqID)
Retrieves detailed information for a specific block.
- Parameters:
blockID
{string
} – The ID of the block to retrieve.includeTX
{boolean
} [Optional, Default: true] – If true, include the list of transactions within the block (-tx
flag).includeMem
{boolean
} [Optional, Default: false] – (Likely unused for block details, but present in signature) Include mempool data (-mem
flag).includeSec
{boolean
} [Optional, Default: false] – If true, include a security report related to the block/miner (-sec
flag).threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process.mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – A request identifier (reqID > 0
) if sent successfully, otherwise 0. - Underlying GridScript:
context -c getBlockDetails -search "<blockID>" [-tx] [-mem] [-sec]
- Response Event:
addNewBlockDetailsListener
(Eventarg.data
contains aCBlockDesc
instance). - Async Version:
getBlockDetailsA(...)
->Promise<CBlockDesc>
- Example (Async):
async function fetchBlock(id) {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
const blockDetails = await vmContext.getBlockDetailsA(id, true, false, false, undefined, processHandle);
console.log(`Block Height: ${blockDetails.height}`);
console.log(`Number of Transactions: ${blockDetails.transactionsCount}`);
// Access other blockDetails properties (CBlockDesc instance)
} catch (error) {
console.error(`Error fetching block ${id}:`, error);
}
}
fetchBlock("some_block_id");
getDomainHistory(address, size, page, eSortTransactionsByVal, stateID, threadID, processHandle, mode, reqID)
Retrieves the transaction history for a specific domain address.
- Parameters:
address
{string
} – The domain address to query.size
{number
} [Optional, Default: 10] – Number of transactions per page.page
{number
} [Optional, Default: 1] – Page number to retrieve.eSortTransactionsByVal
{eSortTransactionsBy
} [Optional, Default:timestampDesc
] – Sorting criteria for transactions.stateID
{string
} [Optional, Default: “”] – State ID for restoring iterators (used for deep pagination, currently experimental).threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process.mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – A request identifier (reqID > 0
) if sent successfully, otherwise 0. - Underlying GridScript:
context -c getDomainHistory -search "<address>" -size <size> -page <page> -sort <eSortTransactionsByVal> [-state "<stateID>"]
- Response Event:
addNewSearchResultsListener
(Results delivered within aCSearchResults
object containingCTransactionDesc
instances relevant to the domain). - Async Version:
getDomainHistoryA(...)
->Promise<CSearchResults>
- Example (Async):
async function fetchDomainHistory(domainAddr) {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
const historyResults = await vmContext.getDomainHistoryA(domainAddr, 25, 1, eSortTransactionsBy.timestampDesc, "", undefined, processHandle);
console.log(`Found ${historyResults.getTotalResultCount()} transactions for domain ${domainAddr}.`);
// Process historyResults containing CTransactionDesc objects
} catch (error) {
console.error(`Error fetching history for domain ${domainAddr}:`, error);
}
}
fetchDomainHistory("some_domain_address");
getDomainDetails(address, perspective, includeSec, threadID, processHandle, mode, reqID)
Retrieves detailed information about a specific domain address.
- Parameters:
address
{string
} – The domain address to query.perspective
{string
} [Optional, Default: “”] – Specifies a perspective for viewing domain state (advanced feature).includeSec
{boolean
} [Optional, Default: false] – If true, includes the operator security report (-sec
flag).threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process.mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – A request identifier (reqID > 0
) if sent successfully, otherwise 0. - Underlying GridScript:
context -c getDomainDetails -search "<address>" [-perspective "<perspective>"] [-sec]
- Response Event:
addNewDomainDetailsListener
(Eventarg.data
contains aCDomainDesc
instance). - Async Version:
getDomainDetailsA(...)
->Promise<CDomainDesc>
- Example (Async):
async function fetchDomain(domainAddr) {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
const domainDetails = await vmContext.getDomainDetailsA(domainAddr, "", false, undefined, processHandle);
console.log(`Domain: ${domainDetails.domain}`);
console.log(`Balance: ${domainDetails.balanceTxt}`);
// Access other domainDetails properties (CDomainDesc instance)
} catch (error) {
console.error(`Error fetching details for domain ${domainAddr}:`, error);
}
}
fetchDomain("some_domain_address");
getTransactionDetails(transactionID, threadID, processHandle, mode, reqID)
Retrieves detailed information about a specific transaction.
- Parameters:
transactionID
{string
} – The verifiable ID of the transaction.threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process.mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – A request identifier (reqID > 0
) if sent successfully, otherwise 0 or false iftransactionID
is invalid. - Underlying GridScript:
context -c getTransactionDetails -search "<transactionID>"
- Response Event:
addNewTransactionDetailsListener
(Eventarg.data
contains aCTransactionDesc
instance). - Async Version:
getTransactionDetailsA(...)
->Promise<CTransactionDesc>
- Example (Async):
async function fetchTxDetails(txId) {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
const txDetails = await vmContext.getTransactionDetailsA(txId, undefined, processHandle);
console.log(`Transaction Sender: ${txDetails.sender}`);
console.log(`Transaction Value: ${txDetails.valueTxt}`);
// Access other txDetails properties (CTransactionDesc instance)
} catch (error) {
console.error(`Error fetching details for TX ${txId}:`, error);
}
}
fetchTxDetails("some_transaction_id");
getLiveness(threadID, processHandle, mode, reqID)
Retrieves the current network liveness state.
- Parameters: See
getBlockchainStatus
. - Returns: {
number
} – Request ID (reqID > 0
). - Underlying GridScript:
context -c getLiveness
- Response Event:
addBlockchainStatsListener
(Eventarg.data
contains the liveness state, typically a value fromeLivenessState
enum). - Async Version:
getLivenessA(...)
->Promise<number>
getUSDTPrice(threadID, processHandle, mode, reqID)
Retrieves the current approximate price of GNC in USDT (fetched from oracle sources by Core nodes).
- Parameters: See
getBlockchainStatus
. - Returns: {
number
} – Request ID (reqID > 0
). - Underlying GridScript:
context -c getUSDTPrice
- Response Event:
addBlockchainStatsListener
(Eventarg.data
contains the price, likely as a BigInt representing atto-USDT per GNC or similar fixed-point representation). - Async Version:
getUSDTPriceA(...)
->Promise<BigInt>
getHeight(isKeyHeight, threadID, processHandle, mode, reqID)
Retrieves the current height of the blockchain (either regular block height or key block height). Includes internal caching for efficiency.
- Parameters:
isKeyHeight
{boolean
} – If true, retrieves the latest key block height; otherwise, retrieves the latest regular block height.threadID
{ArrayBuffer
} [Optional, Default: Data Thread] – The target decentralized thread ID.processHandle
{Object
} [Optional, Default: null] – Handle of the calling UI dApp process.mode
{eVMMetaCodeExecutionMode
} [Optional, Default:RAW
] – Execution mode.reqID
{number
} [Optional, Default: 0] – Specific request ID to use.
- Returns: {
number
} – Request ID (reqID > 0
) if a network request is sent, or the samereqID
(potentially generated) if returning a cached value via a scheduled event. - Underlying GridScript:
context -c getHeight [-key]
- Response Event:
addNewGridScriptResultListener
(Eventarg.data
contains the height number). The method internally uses caching (mCachedHeight
,mCachedKeyHeight
) and may return a cached value via asetTimeout
event ifallowCache
is true (in async version) and the cache is fresh. - Async Version:
getHeightA(isKeyHeight, ..., allowCache)
->Promise<number>
(TheallowCache
parameter controls cache usage). - Example (Async – Get Key Height):
async function fetchKeyHeight() {
try {
const vmContext = CVMContext.getInstance();
const processHandle = this;
const keyHeight = await vmContext.getHeightA(true, undefined, processHandle, undefined, 0, 5000, true); // Allow cache
console.log(`Current Key Block Height: ${keyHeight}`);
} catch (error) {
console.error("Error fetching key height:", error);
}
}
fetchKeyHeight();
4.2 Subscription Methods
subscribeToBlockchainUpdates(threadID, processHandle, mode, reqID)
Subscribes the current CVMContext
instance to receive real-time updates about new blocks and potentially other blockchain events from the connected Core node. Registered listeners (e.g., addNewBlockDetailsListener
, addNewTransactionDetailsListener
) will be triggered as new data arrives.
- Parameters: See
getBlockchainStatus
. - Returns: {
number
|boolean
} – A request identifier (reqID > 0
) ortrue
if already subscribed. Returnsfalse
on failure to send the request. - Underlying GridScript:
context -c startBlockchainUpdates
- Response Event: No direct response event. Success enables receiving blockchain update notifications via standard listeners.
- Async Version:
subscribeToBlockchainUpdatesA(...)
->Promise<boolean>
- Example (Non-Async):
const vmContext = CVMContext.getInstance();
const processHandle = this;
if (vmContext.subscribeToBlockchainUpdates(undefined, processHandle)) {
console.log("Subscription request sent successfully.");
// Register listeners like addNewBlockDetailsListener here
} else {
console.error("Failed to send subscription request.");
}
unsubscribeFromBlockchainUpdates(threadID, processHandle, mode, reqID)
Stops receiving real-time blockchain updates for this CVMContext
instance.
- Parameters: See
getBlockchainStatus
. - Returns: {
number
|boolean
} – A request identifier (reqID > 0
) ortrue
if already unsubscribed. Returnsfalse
on failure to send the request. - Underlying GridScript:
context -c stopBlockchainUpdates
- Response Event: No direct response event. Success stops the flow of update notifications.
- Async Version:
unsubscribeFromBlockchainUpdatesA(...)
->Promise<boolean>
- Example (Non-Async):
const vmContext = CVMContext.getInstance();
const processHandle = this;
if (vmContext.unsubscribeFromBlockchainUpdates(undefined, processHandle)) {
console.log("Unsubscription request sent successfully.");
} else {
console.error("Failed to send unsubscription request.");
}
5. Data Objects
The API uses several custom classes to represent blockchain data structures. These classes handle BER serialization/deserialization and provide convenient getters for accessing data.
5.1 CBlockDesc
Represents a blockchain block.
- Key Properties/Getters:
blockID
: {string
} Unique block identifier.height
: {number
} Block height.keyHeight
: {number
} Corresponding key block height.type
: {eBlockType
} Type of block (Key or Data).solvedAt
: {number
} Unix timestamp (seconds) when mined.minerID
: {string
} Address of the miner.parentID
: {string
} ID of the previous block.difficulty
: {number
} Mining difficulty.transactionsCount
: {number
} Number of transactions included.ergUsed
: {BigInt
} Computational units used.ergLimit
: {BigInt
} Maximum computational units allowed.blockReward
: {BigInt
} Base reward for mining the block (attoGNC).totalReward
: {BigInt
} Total reward including fees (attoGNC).transactions
: {Array<CTransactionDesc>
} Array of transaction objects included (if requested).size
: {number
} Size of the block in bytes.
- Serialization:
getPackedData()
->ArrayBuffer
(BER encoded). - Deserialization:
static instantiate(packedData)
->CBlockDesc
.
5.2 CTransactionDesc
Represents a blockchain transaction.
- Key Properties/Getters:
verifiableID
: {string
} Unique transaction identifier.blockID
: {string
} ID of the block containing the transaction (if confirmed).height
: {number
} Height of the block containing the transaction.keyHeight
: {number
} Key height of the block containing the transaction.sender
: {string
} Sender’s domain address.receiver
: {string
} Receiver’s domain address.value
: {BigInt
} Amount transferred (attoGNC).fee
: {BigInt
} Transaction fee paid (attoGNC).tax
: {BigInt
} Tax paid (attoGNC).type
: {eTXType
} Type of transaction.result
: {eTransactionValidationResult
} Validation result code.status
: {string
} Human-readable status (e.g., “Pending”, “Finalized (Safe)”). UseupdateStatus()
orrefreshStatus()
for accuracy.statusColor
: {string
} CSS color code for the status.confirmedTimestamp
: {number
} Unix timestamp (seconds) when confirmed.unconfirmedTimestamp
: {number
} Unix timestamp (seconds) when first seen.sourceCode
: {string
} GridScript source code (if applicable).log
: {Array<string>
} Execution log entries.ERGUsed
: {BigInt
} Computational units consumed.ERGLimit
: {BigInt
} Maximum computational units requested.nonce
: {number
} Sender’s transaction sequence number.size
: {number
} Size of the transaction in bytes.
- Serialization:
getPackedData()
->ArrayBuffer
(BER encoded). - Deserialization:
static instantiate(packedData)
->CTransactionDesc
. - Helper Methods:
async updateStatus()
: Asynchronously fetches current heights and updates the status.refreshStatus()
: Synchronously updates the status based on cached heights.
5.3 CDomainDesc
Represents a domain (account) on the blockchain.
- Key Properties/Getters:
domain
: {string
} The domain address.balance
: {BigInt
} Current available balance (attoGNC).lockedBalance
: {BigInt
} Balance locked in contracts or processes (attoGNC).txCount
: {number
} Total number of transactions (in + out).txInCount
: {number
} Number of incoming transactions.txOutCount
: {number
} Number of outgoing transactions.txTotalReceived
: {BigInt
} Total amount received (attoGNC).txTotalSent
: {BigInt
} Total amount sent (attoGNC).GNCTotalMined
: {BigInt
} Total GNC mined (attoGNC).identityToken
: {CIdentityToken | null
} Associated identity token object.securityInfo
: {COperatorSecurityInfo | null
} Associated security information.nonce
: {number
} Current nonce for the domain.
- Serialization:
getPackedData()
->ArrayBuffer
(BER encoded). - Deserialization:
static instantiate(packedData)
->CDomainDesc
.
5.4 CSearchResults
A container for search results returned by searchBlockchain
, getRecentBlocks
, getRecentTransactions
, and getDomainHistory
.
- Key Properties/Getters:
resultCount
/getResultCount()
: {number
} Number of results in the current page.totalResultCount
/getTotalResultCount()
: {number
} Total number of results available across all pages.currentPage
/getCurrentPage()
: {number
} The current page number.itemsPerPage
/getItemsPerPage()
: {number
} Number of items requested per page.results
/getAllResults()
: {Array<ResultData>
} Array containing the actual result items for the current page.
- Key Methods:
getResult(index)
: {ResultData
} Retrieves a specific result item by index. The item is wrapped inResultData
. Useresult.getValue()
to get the underlyingCBlockDesc
,CTransactionDesc
, orCDomainDesc
.
- Serialization:
getPackedData()
->ArrayBuffer
(BER encoded). - Deserialization:
static instantiate(packedData)
->CSearchResults
.
5.5 CSearchFilter
Used to specify detailed search criteria beyond simple keywords.
- Key Concepts:
- Standard Flags: Predefined flags for common entity types (
TRANSACTIONS
,DOMAINS
,BLOCKS
,ADDRESSES
). Use bitwise OR (|
) to combine. Access viaCSearchFilter.StandardFlags
. ConstantsCSearchFilter.NO_STANDARD
(0n) andCSearchFilter.ALL_STANDARD
are available. - Arbitrary Flags: Custom key-value pairs for backend-specific filtering.
- Standard Flags: Predefined flags for common entity types (
- Key Methods:
constructor(flags)
: Creates a filter, optionally setting initial standard flags.setStandardFlags(...flags)
: Adds one or more standard flags.setArbitraryFlag(name, value)
: Sets a custom flag and its value (value defaults to empty string if omitted, booleanfalse
removes the flag).hasStandardFlag(flag)
: Checks if a standard flag is set.hasArbitraryFlag(name)
: Checks if a custom flag exists.getArbitraryFlagValue(name)
: Gets the value of a custom flag.toBytes()
: Serializes the filter toUint8Array
.toString()
: Serializes the filter to a Base58Check encoded string (used when passing tosearchBlockchain
).
- Static Methods:
fromBytes(buffer)
: Deserializes fromUint8Array
.fromNumber(number)
: Creates a filter with only standard flags from a bitmask.
6. Event Handling
UI dApps interact with the API primarily through events. Register listeners using the add...Listener
methods on the CVMContext
instance.
Key Listener Methods for Blockchain Explorer API:
addNewSearchResultsListener(callback, appID)
: Handles responses fromsearchBlockchain
,getRecentBlocks
,getRecentTransactions
,getDomainHistory
,getMarketData
(for balances). The callback receives anevent
object whereevent.results
is aCSearchResults
instance. Matchevent.reqID
to your original request ID.addNewBlockDetailsListener(callback, appID)
: Handles responses fromgetBlockDetails
. The callback receivesevent
whereevent.data
is aCBlockDesc
instance.addNewTransactionDetailsListener(callback, appID)
: Handles responses fromgetTransactionDetails
. The callback receivesevent
whereevent.data
is aCTransactionDesc
instance.addNewDomainDetailsListener(callback, appID)
: Handles responses fromgetDomainDetails
. The callback receivesevent
whereevent.data
is aCDomainDesc
instance.addBlockchainStatsListener(callback, appID)
: Handles responses from various statistics methods likegetBlockchainStatus
,getNetworkUtilization24h
,getHeight
,getUSDTPrice
,getLiveness
, etc. Theevent
object containsevent.type
(a string identifying the statistic, e.g., ‘blockchainHeight’) andevent.data
(containing the actual statistic value(s)).addNewGridScriptResultListener(callback, appID)
: A more general listener for GridScript results. Blockchain Explorer API responses might also trigger this, often containing BER-encoded data within theevent.data
structure that needs further parsing based on the original request context (event.reqID
).
Important: Always remember to unregister listeners when they are no longer needed (e.g., when a UI component is destroyed) to prevent memory leaks, using CVMContext.unregisterEventListenerByID(listenerId)
.
7. Conclusion and Best Practices
- Use Async Methods: Prefer the
A
suffix methods (getBlockDetailsA
, etc.) withasync/await
for cleaner code. - Handle Process Context: Always pass the UI dApp’s instance (
this
) as theprocessHandle
parameter where required. - Manage Request IDs: When using non-async methods, store the returned
reqID
and use it to correlate responses in your event listeners. - Check Event Data: In listeners, always check the type of the received data (e.g.,
event.results instanceof CSearchResults
) before processing. - Unregister Listeners: Clean up listeners using
unregisterEventListenerByID
when they are no longer needed. - Error Handling: Wrap API calls in
try...catch
blocks, especially when usingawait
. Implement robust error handling in event listeners. - Use Data Object Getters: Access data using the provided getters (e.g.,
block.height
,tx.valueTxt
) on theCBlockDesc
,CTransactionDesc
, etc., objects. - Leverage Caching: Be aware that
CVMContext
performs some internal caching (e.g., forgetHeight
). Use theallowCache
parameter in async methods if you need to force a refresh. - Consult
CTools
: Utilize methods fromCTools.getInstance()
for common formatting tasks (e.g.,formatGNCValue
,formatByteSize
,transactionStatusText
).
This API provides a powerful interface for interacting with the GRIDNET blockchain. By understanding its architecture and utilizing the provided methods and data objects correctly, developers can build sophisticated and informative blockchain exploration tools within the GRIDNET OS ecosystem.
Appendix A
CSearchFilter
Class Documentation
1. Overview
The CSearchFilter
class is a fundamental component within the GRIDNET OS ecosystem for specifying criteria when searching the blockchain via the CVMContext
Blockchain Explorer API. It provides a flexible and efficient mechanism to filter search results based on both predefined standard entity types (Blocks, Transactions, Domains, Addresses) and arbitrary, developer-defined custom flags.
This class is designed for use within UI dApps to construct search parameters that are then serialized and sent to GRIDNET Core nodes for processing. Its support for both standard and dynamic flags allows for powerful and extensible search capabilities across the decentralized network.
Rationale: Instead of using complex query strings or numerous parameters, CSearchFilter
uses a combination of a bitmask for standard types and a map for custom key-value filters. This structure is easily serializable into a compact format suitable for network transmission within the GRIDNET Meta Data Protocol.
2. Key Features
- Standard Flags: Supports predefined flags for common blockchain entities (Transactions, Domains, Addresses, Blocks) using efficient bitwise operations.
- Arbitrary Flags: Allows developers to define and use custom flags (key-value pairs) for more granular or application-specific filtering processed by the backend.
- Serialization: Provides methods to serialize the filter state into:
- A compact byte array (
toBytes
). - A Base58Check encoded string (
toString
), suitable for embedding in GridScript commands used by the Blockchain Explorer API.
- A compact byte array (
- Deserialization: Allows recreating a
CSearchFilter
instance from:- A byte array (
fromBytes
). - A number representing only standard flags (
fromNumber
).
- A byte array (
- Flexibility: Combines the ease of use of standard flags with the extensibility of arbitrary flags.
- Readability: Offers a method (
getSearchDomainDescription
) to get a human-readable summary of the active filters.
3. Class Definition
import { CTools } from '/lib/tools.js';
export class CSearchFilter {
// Static properties (StandardFlags, ALL_STANDARD, etc.)
// Constructor
// Methods (setStandardFlags, setArbitraryFlag, has…, toBytes, toString, etc.)
// Static methods (fromBytes, fromNumber)
// Private validation methods
}
4. Static Properties
StandardFlags
An object containing predefined BigInt
values representing standard blockchain entity types. These flags can be combined using the bitwise OR operator (|
).
TRANSACTIONS
:1n << 0n
(Value:1n
) – Filter for transactions.DOMAINS
:1n << 1n
(Value:2n
) – Filter for domains (accounts).ADDRESSES
:1n << 2n
(Value:4n
) – Filter for addresses (often used interchangeably with domains).BLOCKS
:1n << 3n
(Value:8n
) – Filter for blocks.
NO_STANDARD
A BigInt
constant representing no standard flags set (Value: 0n
). Useful for starting with a clean slate before adding specific standard flags.
ALL_STANDARD
A BigInt
constant representing all standard flags combined (Value: 15n
). This is not the default constructor value anymore (default is NO_STANDARD
).
Constants
MAX_ARBITRARY_FLAGS
: Maximum number of arbitrary flags allowed (currently 1,000,000 – a high theoretical limit).MAX_FLAG_NAME_LENGTH
: Maximum length for an arbitrary flag name (256 characters).MAX_FLAG_VALUE_LENGTH
: Maximum length for an arbitrary flag value (1024 characters).
5. Constructor
constructor(flags = CSearchFilter.NO_STANDARD)
Creates a new CSearchFilter
instance.
- Parameters:
flags
{bigint
} [Optional, Default:CSearchFilter.NO_STANDARD
] – An initial bitmask of standard flags to set. Only bits corresponding to definedStandardFlags
are considered.
- Throws:
TypeError
: Ifflags
is not aBigInt
.Error
: Ifflags
contains bits not defined inStandardFlags
.
6. Methods
setStandardFlags(...flags)
Sets one or more standard flags on the filter instance. This method uses bitwise OR, so it adds flags without removing existing ones unless you start with NO_STANDARD
.
- Parameters:
...flags
{(keyof typeof CSearchFilter.StandardFlags | bigint)} – A variable number of arguments, each being either:- A string matching a key in
CSearchFilter.StandardFlags
(e.g.,"TRANSACTIONS"
). - A
BigInt
value corresponding to a standard flag (e.g.,CSearchFilter.StandardFlags.BLOCKS
).
- A string matching a key in
- Returns: {
CSearchFilter
} – TheCSearchFilter
instance for method chaining. - Throws:
Error
: If an invalid flag name or value is provided.TypeError
: If an argument is not a string or BigInt.
- Example:
const filter = new CSearchFilter(); // Starts with NO_STANDARD
filter.setStandardFlags("TRANSACTIONS", CSearchFilter.StandardFlags.BLOCKS);
// filter now searches for Transactions OR Blocks
setArbitraryFlag(flagName, value = '')
Sets a custom, arbitrary flag with an associated value. Arbitrary flags are used for backend-specific filtering beyond the standard types. If the value
is boolean false
, the flag is removed.
- Parameters:
flagName
{string
} – The name of the custom flag (case-sensitive). Must be non-empty and within length limits.value
{string
|number
|bigint
|boolean
|ArrayBuffer
} [Optional, Default:''
] – The value associated with the flag.- Booleans:
true
sets the flag with an empty string value,false
removes the flag. - Numbers/BigInts: Converted to strings.
- ArrayBuffers: Decoded as UTF-8 strings.
- Strings: Used directly (must be within length limits).
- Booleans:
- Returns: {
CSearchFilter
} – TheCSearchFilter
instance for method chaining. - Throws:
TypeError
: IfflagName
is not a string orvalue
is an unsupported type.Error
: IfflagName
orvalue
violates length constraints or if the maximum number of arbitrary flags is exceeded.
- Example:
const filter = new CSearchFilter();
filter.setArbitraryFlag("block_type", "key"); // Search for key blocks
filter.setArbitraryFlag("min_height", 100000); // Search blocks >= height 100000
filter.setArbitraryFlag("HAS_CODE", true); // Flag existence (value stored as '')
filter.setArbitraryFlag("HAS_CODE", false); // Removes the "HAS_CODE" flag
setArbitraryFlagBoolean(flagName, value)
A convenience method equivalent to setArbitraryFlag(flagName, value)
specifically for boolean values. true
sets the flag (with an empty string value), false
removes it.
- Parameters:
flagName
{string
} – The name of the custom flag.value
{boolean
} –true
to set the flag,false
to remove it.
- Returns: {
CSearchFilter
} – TheCSearchFilter
instance for method chaining.
getArbitraryFlags()
Returns an iterator over the arbitrary flags currently set in the filter.
- Returns: {
IterableIterator<[string, string]>
} – An iterator yielding[flagName, flagValue]
pairs.
hasStandardFlag(flag)
Checks if a specific standard flag is currently set.
- Parameters:
flag
{keyof typeof CSearchFilter.StandardFlags
|bigint
} – The standard flag to check (by name or BigInt value).
- Returns: {
boolean
} –true
if the flag is set,false
otherwise. - Throws:
Error
: If an invalid flag name or value is provided.TypeError
: If the argument is not a string or BigInt.
hasArbitraryFlag(flagName)
Checks if a specific arbitrary flag exists (regardless of its value).
- Parameters:
flagName
{string
} – The name of the arbitrary flag.
- Returns: {
boolean
} –true
if the flag exists,false
otherwise.
getArbitraryFlagValue(flagName)
Retrieves the string value associated with a specific arbitrary flag.
- Parameters:
flagName
{string
} – The name of the arbitrary flag.
- Returns: {
string
} – The value of the flag, or an empty string (''
) if the flag does not exist or was set withtrue
or an empty string.
getArbitraryFlagCount()
Returns the number of arbitrary flags currently set.
- Returns: {
number
} – The count of arbitrary flags.
getSearchDomainDescription()
Generates a human-readable string summarizing the currently active standard and arbitrary flags. Useful for logging or debugging.
- Returns: {
string
} – A comma-separated description of the search domain (e.g.,"TRANSACTIONS, BLOCKS, block_type=key"
).
toBytes()
Serializes the entire filter state (version, standard flags, arbitrary flags count, and all arbitrary flag name-value pairs) into a compact binary format.
- Returns: {
Uint8Array
} – The byte array representing the serialized filter. - Format:
[1 byte]
Version (currently 1)[8 bytes]
Standard Flags (BigUint64, little-endian)[4 bytes]
Number of Arbitrary Flags (Uint32, little-endian)[variable]
Sequence of Arbitrary Flags:[variable bytes]
Flag Name (UTF-8)[1 byte]
Null Terminator (\0
)[variable bytes]
Flag Value (UTF-8)[1 byte]
Null Terminator (\0
)- … (repeated for each flag)
toString()
Serializes the filter using toBytes()
and then encodes the resulting byte array using Base58Check encoding. This is the format expected by the CVMContext.searchBlockchain
API method’s flags
parameter.
- Returns: {
string
} – The Base58Check encoded string representation of the filter. - Dependencies: Relies on
CTools.getInstance().encodeBase58Check()
.
static fromBytes(buffer)
Deserializes a CSearchFilter
instance from a byte array previously created by toBytes()
. This method restores both standard and arbitrary flags (including names and values).
- Parameters:
buffer
{Uint8Array
} – The byte array containing the serialized filter data.
- Returns: {
CSearchFilter
} – A newCSearchFilter
instance. - Throws:
TypeError
: Ifbuffer
is not aUint8Array
.Error
: If the buffer is invalid, too short, contains an unsupported version, or exceeds limits.
static fromNumber(number)
Creates a CSearchFilter
instance setting only the standard flags based on a provided number (bitmask). Arbitrary flags are not preserved or set by this method.
- Parameters:
number
{bigint
|number
} – A number or BigInt where bits correspond to standard flags.
- Returns: {
CSearchFilter
} – A newCSearchFilter
instance with only standard flags set.
7. Custom Flag Convention
As noted in the specification, while not enforced by the CSearchFilter
class itself, a recommended convention for naming arbitrary flags when filtering based on object properties is:
OBJECT_NAME||_||PROPERTY_NAME
Where ||
denotes string concatenation.
- Examples:
block_height
: To filter blocks based on theheight
property ofCBlockDesc
.transaction_sender
: To filter transactions based on thesender
property ofCTransactionDesc
.block_keyHeight
: To filter based on thekeyHeight
property.
Adhering to this convention helps maintain consistency when interacting with backend implementations that might expect these specific flag names for property-based filtering.
8. Usage Example (API Call)
import { CSearchFilter } from './searchFilter.js'; // Adjust path as needed import { CVMContext } from './VMContext.js'; // Adjust path as needed async function performAdvancedSearch(query) { const vmContext = CVMContext.getInstance(); const processHandle = window.magicButton; // Assuming magicButton is the process handle // Create a filter: search for Transactions OR Blocks, only key blocks const filter = new CSearchFilter(CSearchFilter.NO_STANDARD); // Start empty filter.setStandardFlags("TRANSACTIONS", "BLOCKS"); // Add standard flags filter.setArbitraryFlag("block_type", "key"); // Add custom flag console.log("Search Domain:", filter.getSearchDomainDescription()); // Output: Search Domain: TRANSACTIONS, BLOCKS, block_type=key // Serialize for API call using toString() -> Base58Check(toBytes()) const filterString = filter.toString(); console.log("Serialized Filter for API:", filterString); try { // Use the async API method with the serialized filter string const searchResults = await vmContext.searchBlockchainA( query, 20, // size 1, // page filterString, // Pass the Base58Check encoded filter string undefined, // threadID (default) processHandle ); console.log(`Found ${searchResults.getTotalResultCount()} results.`); // ... process results ... } catch (error) { console.error("Blockchain search failed:", error); } } // Example usage: performAdvancedSearch("some_query_term");
9. Best Practices and Notes
- Use Standard Flags First: Leverage the predefined
StandardFlags
for common entity types (Transactions, Blocks, Domains, Addresses) as they are optimized and universally understood. - Arbitrary Flags for Extension: Use arbitrary flags for backend-specific or advanced filtering not covered by standard flags. Follow the naming convention (
OBJECT_NAME||_||PROPERTY_NAME
) where applicable. - Serialization for API: Always use the
toString()
method to get the Base58Check encoded representation when passing the filter toCVMContext.searchBlockchain
orsearchBlockchainA
. - Serialization for Storage: Use
toBytes()
if you need to store the filter’s binary representation locally or send it through other channels expecting raw bytes. UsefromBytes
to restore it. fromNumber
Limitations: Remember thatstatic fromNumber(flags)
only restores standard flags based on the provided bitmask. Arbitrary flags are lost in this conversion.- Immutability: Methods like
setStandardFlags
andsetArbitraryFlag
modify the instance in place and returnthis
for chaining.