@@ -10,14 +10,16 @@ pub mod graphql;
10
10
use std:: collections:: HashMap ;
11
11
use std:: sync:: Arc ;
12
12
13
+ use dusk_bytes:: DeserializableSlice ;
14
+ use dusk_core:: signatures:: bls:: PublicKey as BlsPublicKey ;
13
15
use dusk_core:: transfer:: data:: { BlobData , BlobSidecar } ;
14
16
use dusk_core:: transfer:: Transaction as ProtocolTransaction ;
15
17
use dusk_vm:: execute;
16
18
use node:: database:: rocksdb:: MD_HASH_KEY ;
17
19
use node:: database:: { self , Ledger , LightBlock , Mempool , Metadata , DB } ;
18
20
use node:: mempool:: MempoolSrv ;
19
21
use node:: vm:: VMExecution ;
20
- use node_data:: ledger:: Transaction ;
22
+ use node_data:: ledger:: { SpendingId , Transaction } ;
21
23
22
24
use async_graphql:: {
23
25
EmptyMutation , EmptySubscription , Name , Schema , Variables ,
@@ -62,6 +64,7 @@ impl HandleRequest for RuskNode {
62
64
( "network" , _, "peers" ) => true ,
63
65
( "network" , _, "peers_location" ) => true ,
64
66
( "node" , _, "info" ) => true ,
67
+ ( "account" , Some ( _) , "status" ) => true ,
65
68
( "blocks" , _, "gas-price" ) => true ,
66
69
( "blobs" , Some ( _) , "commitment" ) => true ,
67
70
( "blobs" , Some ( _) , "hash" ) => true ,
@@ -93,6 +96,7 @@ impl HandleRequest for RuskNode {
93
96
94
97
( "network" , _, "peers_location" ) => self . peers_location ( ) . await ,
95
98
( "node" , _, "info" ) => self . get_info ( ) . await ,
99
+ ( "account" , Some ( pk) , "status" ) => self . get_account ( pk) . await ,
96
100
( "blocks" , _, "gas-price" ) => {
97
101
let max_transactions = request
98
102
. data
@@ -333,6 +337,51 @@ impl RuskNode {
333
337
} ;
334
338
Ok ( response)
335
339
}
340
+
341
+ async fn get_account ( & self , pk : & str ) -> anyhow:: Result < ResponseData > {
342
+ let pk = bs58:: decode ( pk)
343
+ . into_vec ( )
344
+ . map_err ( |_| anyhow:: anyhow!( "Invalid bs58 account" ) ) ?;
345
+ let pk = BlsPublicKey :: from_slice ( & pk)
346
+ . map_err ( |_| anyhow:: anyhow!( "Invalid bls account" ) ) ?;
347
+
348
+ let db = self . inner ( ) . database ( ) ;
349
+ let vm = self . inner ( ) . vm_handler ( ) ;
350
+
351
+ let account = vm
352
+ . read ( )
353
+ . await
354
+ . account ( & pk)
355
+ . map_err ( |e| anyhow:: anyhow!( "Cannot query the state {e:?}" ) ) ?;
356
+
357
+ // Determine the next available nonce not already used in the mempool.
358
+ // This ensures that any in-flight transactions using sequential nonces
359
+ // are accounted for.
360
+ // If the account has no transactions in the mempool, the mempool_nonce
361
+ // will be `None`, indicating that the next nonce is the same as the
362
+ // account's current nonce.
363
+ let mempool_nonce = db
364
+ . read ( )
365
+ . await
366
+ . view ( |t| {
367
+ let mut next_nonce = account. nonce ;
368
+ loop {
369
+ let id = SpendingId :: AccountNonce ( pk, next_nonce) ;
370
+ if t. mempool_txs_by_spendable_ids ( & [ id] ) . is_empty ( ) {
371
+ break ;
372
+ }
373
+ next_nonce += 1 ;
374
+ }
375
+ anyhow:: Ok ( ( next_nonce > account. nonce ) . then_some ( next_nonce) )
376
+ } )
377
+ . map_err ( |e| anyhow:: anyhow!( "Cannot check the mempool {e}" ) ) ?;
378
+
379
+ Ok ( ResponseData :: new ( json ! ( {
380
+ "balance" : account. balance,
381
+ "nonce" : account. nonce,
382
+ "mempool_nonce" : mempool_nonce,
383
+ } ) ) )
384
+ }
336
385
}
337
386
338
387
async fn load_tip < DB : database:: DB > (
0 commit comments