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.