How to query your Dusk node?¶
Website: dusk.network¶
Here are several ways to query your Dusk node: GraphQL, RPC, and RUES.
Astuce
🇫🇷 French version: Communiquer avec votre nœud Dusk.
VKZpBrNtEeTobMgYkkdcGiZn8fK2Ve2yez429yRXrH4nUUDTuvr7Tv74xFA2DKNVegtF6jaom2uacZMm8Z2Lg2J
1️⃣ GraphQL¶
Overview of all available GraphQL functions and their data structures¶
curl -X POST 'https://nodes.dusk.network/on/graphql/query'
Fetch the latest block height¶
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'query { block(height: -1) { header { height } } }'
Output example:
{
"block": {
"header": {
"height": 189268
}
}
}
Fetch latest N blocks¶
Instead of retreiving too much information, here we only want the block height (height
), and the provisioner address (generatorBlsPubkey
) that validated the block.
You can tweak the blocks count at the line last: 100
(latest 100 blocks for instance).
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'fragment BlockInfo on Block { header { height, generatorBlsPubkey } }
query() { blocks(last: 100) {...BlockInfo} }'
Same as above, but using a special HTTP header to pass the number of blocks to fetch as a variable: rusk-gqlvar-XXX
(where XXX
is the vairable name).
curl 'https://nodes.dusk.network/on/graphql/query' \
-H 'rusk-gqlvar-count: 100' \
--json \
'fragment BlockInfo on Block { header { height, generatorBlsPubkey } }
query($count: Int!) { blocks(last: $count) {...BlockInfo} }'
Output example:
{
"blocks": [
{
"header": {
"generatorBlsPubkey": "xY8e71u5E8CFmSU1...",
"height": 189291
}
},
{
"header": {
"generatorBlsPubkey": "ueu27WiUjcssYMvR...",
"height": 189290
}
},
// (...)
]
}
Fetch latest N blocks with transaction data¶
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'fragment TransactionInfo on SpentTransaction { tx { callData { contractId, data, fnName }, txType }}
fragment BlockInfo on Block { header { height, generatorBlsPubkey }, transactions {...TransactionInfo} }
query() { blocks(last: 100) {...BlockInfo} }'
Output example:
{
"blocks": [
{
"header": {
"generatorBlsPubkey": "24e5SaodhsLnTpHW...",
"height": 189314
},
"transactions": [
{
"tx": {
"callData": {
"contractId": "0200000000000000000000000000000000000000000000000000000000000000",
"data": "0000000000000000b574dad75d051d3993fb9ba7c36453ca9c10d63fc48b0d924144d...",
"fnName": "stake"
},
"txType": "Moonlight"
}
}
]
},
// (...)
]
}
Fetch latest N blocks with JSON transaction data¶
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'fragment TransactionInfo on SpentTransaction { tx { json } }
fragment BlockInfo on Block { header { height, generatorBlsPubkey }, transactions {...TransactionInfo} }
query() { blocks(last: 100) {...BlockInfo} }'
Output example:
{
"blocks": [
{
"header": {
"generatorBlsPubkey": "24e5SaodhsLnTpHW...",
"height": 189314
},
"transactions": [
{
"tx": {
"json": "{\"type\":\"moonlight\",\"sender\":\"21SvzTdXggQkZpnk...\",\"receiver\":null,\"value\":0,\"nonce\":35,\"deposit\":1070000000000,\"fee\":{\"gas_price\":\"1\",\"refund_address\":\"21SvzTdXggQkZpnk...\",\"gas_limit\":\"2000000000\"},\"call\":{\"contract\":\"0200000000000000000000000000000000000000000000000000000000000000\",\"fn_name\":\"stake\",\"fn_args\":\"AAAAAAAAAAC1dNrXXQUdOZP7m6fDZFPKnBDWP8SLDZJBRN2nzm4EPSMTh16bHMpQU\"},\"is_deploy\":false,\"memo\":null}"
}
}
]
},
// (...)
]
}
And parsing the JSON data:
{
"call": {
"contract": "0200000000000000000000000000000000000000000000000000000000000000",
"fn_args": "AAAAAAAAAAC1dNrXXQUdOZP7m6fDZFPKnBDWP8SLDZJBRN2nzm4EPSMTh16bHMpQU...",
"fn_name": "stake"
},
"deposit": 1070000000000,
"fee": {
"gas_limit": "2000000000",
"gas_price": "1",
"refund_address": "21SvzTdXggQkZpnk..."
},
"is_deploy": false,
"memo": null,
"nonce": 35,
"receiver": null,
"sender": "21SvzTdXggQkZpnk...",
"type": "moonlight",
"value": 0
}
Fetch a range of blocks¶
Example with blocks 10, 11, and 12: the syntax is [10, 12]
.
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'fragment BlockInfo on Block { header { height, generatorBlsPubkey } }
query() { blocks(range: [10, 12]) {...BlockInfo} }'
Output example:
{
"blocks": [
{
"header": {
"generatorBlsPubkey": "25hxg2DMEmj1ghG8...",
"height": 10
}
},
{
"header": {
"generatorBlsPubkey": "od2bVPYstYud4N1G...",
"height": 11
}
},
{
"header": {
"generatorBlsPubkey": "nw2fQCAYb5S5v9eM...",
"height": 12
}
}
]
}
Fetch JSON transaction details of a given block¶
Lets get the block height 189314.
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'fragment TransactionInfo on SpentTransaction { tx { json } }
fragment BlockInfo on Block { transactions {...TransactionInfo} }
query() { block(height: 189314) {...BlockInfo} }'
Output example:
{
"block": {
"transactions": [
{
"tx": {
"json": "{\"type\":\"moonlight\",\"sender\":\"21SvzTdXggQkZpnk...\",\"receiver\":null,\"value\":0,\"nonce\":35,\"deposit\":1070000000000,\"fee\":{\"gas_price\":\"1\",\"refund_address\":\"21SvzTdXggQkZpnk...\",\"gas_limit\":\"2000000000\"},\"call\":{\"contract\":\"0200000000000000000000000000000000000000000000000000000000000000\",\"fn_name\":\"stake\",\"fn_args\":\"AAAAAAAAAAC1dNrXXQUdOZP7m6fDZFPKnBDWP8SLDZJBRN2nzm4EPSMTh16bHMpQU\"},\"is_deploy\":false,\"memo\":null}"
}
}
]
}
}
Fetch block, and transaction, details of a given block¶
Lets get the block height 189314.
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'fragment TransactionInfo on SpentTransaction { blockHash, blockHeight, blockTimestamp, err, gasSpent, id, tx { callData { contractId, data, fnName }, gasLimit, gasPrice, id, isDeploy, json, memo, txType } }
fragment BlockInfo on Block { header { hash, gasLimit, height, generatorBlsPubkey, prevBlockHash, seed, stateHash, timestamp, version }, fees, gasSpent, reward, transactions {...TransactionInfo} }
query() { block(height: 189314) {...BlockInfo} }'
Output example:
{
"block": {
"fees": 25973789,
"gasSpent": 25973789,
"header": {
"gasLimit": 3000000000,
"generatorBlsPubkey": "24e5SaodhsLnTpHW...",
"hash": "332799ed787002e6619f0f3c4f6b7fa05333881f50c5cf2f23fba35b80e734f7",
"height": 189314,
"prevBlockHash": "b75f26bff0c0e8e624b8d1a4b2345bd97a032e47834cb4c9625f546a37626796",
"seed": "923e8f3196ea3be10bad98d2d322f6cbfd7e8a6732d804615929561a660cea49406f795589a86a8d400d4b6f5418aa69",
"stateHash": "37150543eb1e6c3457f3219ee4535e4534eec7dbc118cae32d4b5ca3e90444c4",
"timestamp": 1738145108,
"version": 1
},
"reward": 19857400000,
"transactions": [
{
"blockHash": "332799ed787002e6619f0f3c4f6b7fa05333881f50c5cf2f23fba35b80e734f7",
"blockHeight": 189314,
"blockTimestamp": 1738145108,
"err": null,
"gasSpent": 25973789,
"id": "bc52d0247c70dde8707d8f49f5d656a9272962cc2e0dc3ca2192e6e117b40d59",
"tx": {
"callData": {
"contractId": "0200000000000000000000000000000000000000000000000000000000000000",
"data": "0000000000000000b574dad75d051d3993fb9ba7c36453ca9c10d63fc48b0d924144dd...",
"fnName": "stake"
},
"gasLimit": 2000000000,
"gasPrice": 1,
"id": "bc52d0247c70dde8707d8f49f5d656a9272962cc2e0dc3ca2192e6e117b40d59",
"isDeploy": false,
"json": "{\"type\":\"moonlight\",\"sender\":\"21SvzTdXggQkZpnk...\",\"receiver\":null,\"value\":0,\"nonce\":35,\"deposit\":1070000000000,\"fee\":{\"gas_price\":\"1\",\"gas_limit\":\"2000000000\",\"refund_address\":\"21SvzTdXggQkZpnk...\"},\"call\":{\"fn_args\":\"AAAAAAAAAAC1dNrXXQUdOZP7m6fDZFPKnBDWP8SLDZJBRN2nzm4EPSMTh16bHMpQU...\",\"contract\":\"0200000000000000000000000000000000000000000000000000000000000000\",\"fn_name\":\"stake\"},\"is_deploy\":false,\"memo\":null}",
"memo": null,
"txType": "Moonlight"
}
}
]
}
}
Fetch full history for a given address¶
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'query { fullMoonlightHistory(address: "PUBLIC_KEY", ord: "desc") { json } }'
Output example:
{
"fullMoonlightHistory": {
"json": [
{
"block_height": 188242,
"events": [
{
"data": {
"receiver": "66RS7dEhVtDgd11j...",
"sender": "uTmRVArYPTGpBiuW...",
"value": 580885000000000
},
"target": "0100000000000000000000000000000000000000000000000000000000000000",
"topic": "convert"
},
{
"data": {
"gas_spent": 25614038,
"memo": "",
"receiver": null,
"refund_info": null,
"sender": "uTmRVArYPTGpBiuW...",
"value": 0
},
"target": "0100000000000000000000000000000000000000000000000000000000000000",
"topic": "moonlight"
}
],
"origin": "f689d1948dfcd541e9038ab98a709390849332c2091aca42afd1bd667c69e469"
},
// (...)
]
}
}
Fetch Account Balance & Nonce¶
Ajouté dans la version 1.0.2.
curl -X POST 'https://nodes.dusk.network/on/account:PUBLIC_KEY/status'
Output example:
{
"balance": 260292192764359648,
"nonce": 260
}
2️⃣ RPC¶
Get the list of all provisioners¶
curl -X POST 'https://nodes.dusk.network/on/node/provisioners'
Output example:
[
{
"amount": 37000000000000,
"eligibility": 4320,
"faults": 0,
"hard_faults": 0,
"key": "mAkcDzY2uVvqbEv6...",
"locked_amt": 0,
"owner": {
"Account": "mAkcDzY2uVvqbEv6..."
},
"reward": 924095468388
},
// (...)
]
3️⃣ RUES¶
RUES for Rusk Universal Event System is a mechanism for handling real-time communication with an event-driven approach.
This is some Python code, and you will need to install requests, and websockets, modules first. When the script is running, block heights generated by the provisioner will be printed in real-time: Output example of the raw response (it is the And when parsed, this JSON object is made available (it is the Look for generated blocks of a given provisioner¶
"""
This was part of Dusk Node Monitoring until commit 832e35ef5b30bc953ea41cf57f279993cedda6a4.
Source: https://github.com/BoboTiG/dusk-monitor
"""
import json
import requests
import websockets
async def listen_to_accepted_blocks(provisioner: str) -> None:
ws_url = "wss://nodes.dusk.network/on"
blocks_accepted_url = "https://nodes.dusk.network/on/blocks/accepted"
async with websockets.connect(ws_url) as wss:
# Get a session ID
session_id = await wss.recv()
# Subscribe to the accepted blocks topic
with requests.get(blocks_accepted_url, headers={"Rusk-Session-Id": session_id}) as req:
req.raise_for_status()
while "listening":
raw = await wss.recv()
raw = raw[raw.find(b'{"header"') :]
block = json.loads(raw)
if block["header"]["generator_bls_pubkey"] == provisioner:
print(block["header"]["height"])
if __name__ == "__main__":
import asyncio
import sys
asyncio.run(listen_to_accepted_blocks(sys.argv[1]))
python listen.py 'PROVISIONER_PUBLIC_KEY'
raw
variable in the script) :b'k\x00\x00\x00{"Content-Location":"/on/blocks:a9e42d231967df49dba9ab1fdf5d40d68287c3af715b53cff841c7a8703bf6d2/accepted"}{"header":{"event_bloom":"000...","failed_iterations":[],"faultroot":"000...","gas_limit":3000000000,"generator_bls_pubkey":"22JbHtrL93fhFDvY...","hash":"a9e...","height":191574,"iteration":0,"prev_block_cert":{"ratification":{"aggregate_signature":"ac5...","bitset":106597789095414875},"result":{"Valid":"7e1..."},"validation":{"aggregate_signature":"844...","bitset":2232142576123535}},"prev_block_hash":"7e1...","seed":"942...","signature":"a32...","state_hash":"be8...","timestamp":1738167716,"txroot":"000...","version":1},"transactions":[]}'
block
variable in the script) :{
"header": {
"event_bloom": "000...",
"failed_iterations": [],
"faultroot": "000...",
"gas_limit": 3000000000,
"generator_bls_pubkey": "22JbHtrL93fhFDvY...",
"hash": "a9e...",
"height": 191574,
"iteration": 0,
"prev_block_cert": {
"ratification": {
"aggregate_signature": "ac5...",
"bitset": 106597789095414875
},
"result": {
"Valid": "7e1..."
},
"validation": {
"aggregate_signature": "844...",
"bitset": 2232142576123535
}
},
"prev_block_hash": "7e1...",
"seed": "942...",
"signature": "a32...",
"state_hash": "be8...",
"timestamp": 1738167716,
"txroot": "000...",
"version": 1
},
"transactions": []
}
📜 Changelog¶
- 2025-02-14
Add the GraphQL section Fetch Account Balance & Nonce (rusk
1.0.2
).- 2025-02-03
Prefer using the
--json
argument forcurl
calls instead of--data-raw
.- 2025-01-30
Add the GraphQL section Overview of all available GraphQL functions and their data structures.
Add the GraphQL section Fetch full history for a given address.
- 2025-01-29
First draft.