Fetch next nonce
Recall that Fast doesn't enforce a total global order on transaction processing. However, it does require a per-account sequencing to protect against double-spending. To ensure the sequencing is respected, transactions initiated from the same account are to carry an increasing nonce. For example, transaction t1 carries nonce 1, transaction t2 nonce 2, etc.
Through nonces, the validators can enforce a processing order on transactions originating from the same account. If the nonce is not the expected one, then the validators reject the transaction. Therefore, you must submit the transaction to Fast with the correct nonce to be accepted.
In simple applications, one can just keep track of this locally and increment it before building each transaction, but what if you lose track of this number? Or what if you have multiple users submitting transactions from the same account, e.g., using a multisig account or just a shared key?
In this case, you would simply query a proxy or one or more validators to find out what the next expected nonce is for your account. This tutorial describes how to fetch the next nonce for a transaction.
Fetch from proxy
When querying the proxy to get the next expected nonce of a given account, you need to use the proxy_getAccountInfo endpoint.
Parameters token_balances_filter and certificate_by_nonce can be ignored, since the next nonce is always returned regardless of options.
use crate::base_types::*;
use crate::messages::*;
use crate::proxy::client::ProxyRpcClient;
let account: FastSetAddress = ...
let client = HttpClient::builder().build(&proxy_rpc_url).unwrap();
let nonce = client
.get_account_info(account, None, None)
.await.unwrap().next_nonce;
println!("Next nonce for account {:?} is {:?}", account, nonce);Fetch from validator
This is very similar to using the proxy. However, you need to use the validator-specific endpoint, getAccountInfo.
Validator desynchronization and incorrect next nonce
Due to the any processing order of transactions and the strong eventual consensus Fast enforces, validators' view of what the next_nonce is may temporarily differ.
When querying for the next nonce, either from a validator or the proxy, you will get the view of a single validator. In the case of the validator, its own view. In the case of the proxy, the process is a bit more involved, but with a similar outcome. Specifically, the proxy will request the account info from all validators until it has a quorum of them, but then will only return the first response.
Since the response may be incorrect, a transaction submitted with that nonce will fail, even if otherwise valid. Due to the risk of account locking when submitting incorrect transactions, you should not blindly submit transactions with the nonce obtained from just one validator. Some of the validators may be dishonest (our security model assumes up to 1/3 are dishonest validators) and may maliciously return any number.
How account locking can occur
Let's assume you submit two different transactions t1 and t2 with same nonce N to a committee of four validators v0, v1, v2, and v3.
To validators v0 and v1, you send t1, and to validators v2 and v3, you send t2. Both transactions are valid in the current account state, both have the correct nonce, and both are signed correctly, so two validators will sign t1 and the other two will sign t2.
However, validators v0 and v1 will never sign another transaction with nonce N, nor will validators v2 and v3. This means that a certificate will never be able to be produced for neither of the transactions because obtaining a certificate from a pool of four validators means getting the signatures of three of them on the same transaction.
To prevent this, you should make sure that you never send different valid transactions with the same nonce.
Last updated
Was this helpful?