Communiquer avec votre nœud Dusk¶
Site web : dusk.network¶
Voici différentes manières de questionner votre nœud Dusk : GraphQL, RPC et RUES.
Astuce
🇬🇧 Version anglaise : How to query your Dusk node?
VKZpBrNtEeTobMgYkkdcGiZn8fK2Ve2yez429yRXrH4nUUDTuvr7Tv74xFA2DKNVegtF6jaom2uacZMm8Z2Lg2J
1️⃣ GraphQL¶
Lister les fonctions GraphQL disponibles et leurs structures de données¶
curl -X POST 'https://nodes.dusk.network/on/graphql/query'
Récupérer le dernier numéro de bloc¶
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'query { block(height: -1) { header { height } } }'
Exemple de réponse :
{
"block": {
"header": {
"height": 189268
}
}
}
Récupérer les N derniers blocs¶
Plutôt que de récupérer trop d’informations, ici, nous ne voulons que le numéro du bloc (height
) et l’adresse du nœud (generatorBlsPubkey
) qui l’a validé.
Vous pouvez modifier le nombre de blocs à la ligne last: 100
(pour les 100 derniers blocs, par exemple).
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'fragment BlockInfo on Block { header { height, generatorBlsPubkey } }
query() { blocks(last: 100) {...BlockInfo} }'
Le même type de requête peut être effectué en spécifiant le nombre de blocs dans un entête HTTP spécial rusk-gqlvar-XXX
(où XXX
est le nom de la variable) :
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} }'
Exemple de réponse :
{
"blocks": [
{
"header": {
"generatorBlsPubkey": "xY8e71u5E8CFmSU1...",
"height": 189291
}
},
{
"header": {
"generatorBlsPubkey": "ueu27WiUjcssYMvR...",
"height": 189290
}
},
// (...)
]
}
Récupérer les N derniers blocs avec les détails des transactions¶
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} }'
Exemple de réponse :
{
"blocks": [
{
"header": {
"generatorBlsPubkey": "24e5SaodhsLnTpHW...",
"height": 189314
},
"transactions": [
{
"tx": {
"callData": {
"contractId": "0200000000000000000000000000000000000000000000000000000000000000",
"data": "0000000000000000b574dad75d051d3993fb9ba7c36453ca9c10d63fc48b0d924144d...",
"fnName": "stake"
},
"txType": "Moonlight"
}
}
]
},
// (...)
]
}
Récupérer les N derniers blocs avec les détails des transactions au format JSON¶
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} }'
Exemple de réponse :
{
"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}"
}
}
]
},
// (...)
]
}
Et en parsant les données JSON, on obtient ceci :
{
"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
}
Récupérer un ensemble de blocs¶
Exemple avec la récupération des blocs 10, 11 et 12 : la syntaxe est [10, 12]
.
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'fragment BlockInfo on Block { header { height, generatorBlsPubkey } }
query() { blocks(range: [10, 12]) {...BlockInfo} }'
Exemple de réponse :
{
"blocks": [
{
"header": {
"generatorBlsPubkey": "25hxg2DMEmj1ghG8...",
"height": 10
}
},
{
"header": {
"generatorBlsPubkey": "od2bVPYstYud4N1G...",
"height": 11
}
},
{
"header": {
"generatorBlsPubkey": "nw2fQCAYb5S5v9eM...",
"height": 12
}
}
]
}
Récupérer les données JSON des transactions pour un bloc donné¶
Le bloc en question est le numéro 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} }'
Exemple de réponse :
{
"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}"
}
}
]
}
}
Récupérer toutes les données d’un bloc, détails des transactions inclus, pour un bloc donné¶
Le bloc en question est le numéro 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} }'
Exemple de réponse :
{
"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"
}
}
]
}
}
Récupérer tout l’historique d’une adresse¶
curl 'https://nodes.dusk.network/on/graphql/query' --json \
'query { fullMoonlightHistory(address: "PUBLIC_KEY", ord: "desc") { json } }'
Exemple de réponse :
{
"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"
},
// (...)
]
}
}
Récupérer la balance et le nonce d’un compte¶
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¶
Récupérer la liste des nœuds validateurs¶
curl -X POST 'https://nodes.dusk.network/on/node/provisioners'
Exemple de réponse :
[
{
"amount": 37000000000000,
"eligibility": 4320,
"faults": 0,
"hard_faults": 0,
"key": "mAkcDzY2uVvqbEv6...",
"locked_amt": 0,
"owner": {
"Account": "mAkcDzY2uVvqbEv6..."
},
"reward": 924095468388
},
// (...)
]
3️⃣ RUES¶
RUES pour Rusk Universal Event System est un système permettant d’écouter la blockchain pour récupérer les évènements en temps réel.
Voici du code écrit en Python, et il est nécessaire d’installer les modules requests et websockets avant d’aller plus loin. Une fois le script en fonctionnement, les numéros de blocs générés par le nœud apparaitront en temps réel : Exemple de réponse brute (il s’agit du contenu de la variable Et une fois parsée, l’objet JSON suivant apparait (il s’agit du contenu de la variable Lister les blocs validés par un nœud spécifique¶
"""
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
dans le 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
dans le 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": []
}
📜 Historique¶
- 2025-02-14
Ajout de la section GraphQL Récupérer la balance et le nonce d’un compte (rusk
1.0.2
).- 2025-02-03
Remplacement de l’argument
--data-raw
par--json
pour les appels àcurl
.- 2025-01-30
Ajout de la section GraphQL Lister les fonctions GraphQL disponibles et leurs structures de données.
Ajout de la section GraphQL Récupérer tout l’historique d’une adresse.
- 2025-01-29
Premier jet.