How to query your Dusk node?

Dusk Logo

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.

🫶 Dusk wallet for tips
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.

Look for generated blocks of a given provisioner

File: listen.py
"""
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]))

When the script is running, block heights generated by the provisioner will be printed in real-time:

python listen.py 'PROVISIONER_PUBLIC_KEY'

Output example of the raw response (it is the 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":[]}'

And when parsed, this JSON object is made available (it is the 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 for curl 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.