Overview
Makes JSON-RPC calls with quorum consensus verification. The function cross-checks results from multiple nodes before returning, ensuring data consistency and reliability for critical operations.
This is particularly useful for operations where data integrity is crucial, such as checking balances before transfers or verifying transaction status.
Function Signature
export const callWithQuorum = async <T = any>(
method: string,
params: any[] | object = [],
quorum = 2
): Promise<T>
Parameters
The API method name (e.g., 'condenser_api.get_accounts', 'condenser_api.get_dynamic_global_properties')
params
any[] | object
default:"[]"
Parameters for the API method as an array or object. Most Hive API methods expect an array of parameters.
The number of nodes that must return the same result to reach consensus. Default is 2 (recommended minimum).Must be less than or equal to the total number of configured nodes.
Return Type
Returns a Promise that resolves to the API response once consensus is reached. The response type can be specified using TypeScript generics.
How It Works
The quorum consensus mechanism:
- Random Node Selection: Nodes are randomly shuffled for better security
- Parallel Batch Calls: Makes parallel calls to
quorum number of nodes
- Result Comparison: Compares results using JSON serialization
- Consensus Check: Returns when
quorum nodes agree on the result
- Retry Logic: If consensus fails, tries the next batch of nodes
- Error on Failure: Throws error if all nodes are exhausted without reaching consensus
When to Use callWithQuorum
Use callWithQuorum for critical operations where data consistency is paramount:
- Financial Operations: Checking balances before transfers
- Transaction Verification: Confirming transaction inclusion
- Critical State Queries: Getting account recovery status
- Security-Sensitive Data: Verifying account authorities
For general queries and non-critical operations, use callRPC instead for better performance.
Examples
Basic Usage with Default Quorum
import { callWithQuorum } from 'hive-tx'
// Uses default quorum of 2 nodes
const accounts = await callWithQuorum(
'condenser_api.get_accounts',
[['alice']]
)
console.log(accounts)
Verify Account Balance Before Transfer
import { callWithQuorum } from 'hive-tx'
// Use quorum to ensure accurate balance
const accounts = await callWithQuorum(
'condenser_api.get_accounts',
[['alice']],
3 // Require 3 nodes to agree
)
const balance = parseFloat(accounts[0].balance)
if (balance >= 10.000) {
// Proceed with transfer
console.log('Sufficient balance')
}
Check Transaction Confirmation
import { callWithQuorum } from 'hive-tx'
// Verify transaction was included in blockchain
const block = await callWithQuorum(
'condenser_api.get_block',
[blockNumber],
2
)
const txFound = block.transactions.some(
tx => tx.transaction_id === targetTxId
)
console.log('Transaction confirmed:', txFound)
Get Dynamic Global Properties with Consensus
import { callWithQuorum } from 'hive-tx'
const props = await callWithQuorum(
'condenser_api.get_dynamic_global_properties',
[],
2
)
console.log('Current block:', props.head_block_number)
console.log('Block time:', props.time)
Higher Quorum for Critical Operations
import { callWithQuorum } from 'hive-tx'
// Require 4 nodes to agree for extra security
const account = await callWithQuorum(
'condenser_api.get_accounts',
[['critical-account']],
4
)
// Verify account recovery status
const recoveryAccount = account[0].recovery_account
console.log('Recovery account:', recoveryAccount)
With TypeScript Type Safety
import { callWithQuorum } from 'hive-tx'
interface DynamicGlobalProperties {
head_block_number: number
time: string
current_witness: string
// ... other fields
}
const props = await callWithQuorum<DynamicGlobalProperties>(
'condenser_api.get_dynamic_global_properties',
[],
2
)
// props is typed as DynamicGlobalProperties
console.log(props.head_block_number)
Error Handling
import { callWithQuorum } from 'hive-tx'
try {
const result = await callWithQuorum(
'condenser_api.get_accounts',
[['alice']],
3
)
console.log(result)
} catch (error) {
if (error.message === "Couldn't reach quorum.") {
console.error('Failed to get consensus from nodes')
} else if (error.message === 'No more nodes available.') {
console.error('All nodes failed to respond')
} else if (error.message === 'quorum > config.nodes.length') {
console.error('Not enough nodes configured for requested quorum')
} else {
console.error('Unexpected error:', error)
}
}
- Slower than callRPC: Makes multiple parallel calls to reach consensus
- Network Overhead: Requires more bandwidth and API calls
- Best for Critical Data: Use only when data consistency is crucial
- Quorum Size: Higher quorum = more reliability but slower response
Comparison with callRPC
import { callRPC, callWithQuorum } from 'hive-tx'
// Fast but single node (potential inconsistency)
const quick = await callRPC('condenser_api.get_accounts', [['alice']])
// Slower but verified by multiple nodes (consistent)
const verified = await callWithQuorum('condenser_api.get_accounts', [['alice']], 2)
Behavior
- Randomly shuffles nodes for better security distribution
- Makes parallel calls to multiple nodes in batches
- Compares results using JSON string comparison
- Returns first result that reaches quorum threshold
- Automatically retries with new nodes if consensus fails
- Throws error if quorum exceeds available nodes
- Each node gets one retry attempt on network failure
Configuration Requirements
import { config } from 'hive-tx'
// Ensure enough nodes are configured for your quorum
config.update({
nodes: [
'https://api.hive.blog',
'https://api.hivekings.com',
'https://anyx.io',
'https://api.openhive.network',
// Add more nodes for higher quorum values
]
})
// Now you can use quorum up to 4
const result = await callWithQuorum('method', params, 4)
See Also