Internal Management

TOP

The rai_node software has a built-in private-key manager that is suitable for smaller operations (<1000 accounts). External Key Management allows more powerful and robust systems at the cost of additional complexity. External Key Management is recommended for larger operations.


Creating a Wallet

To create an account, you first must create a wallet to hold the seed that will subsequently create the account.

Request
curl -d '{"action": "wallet_create"}' http://127.0.0.1:7076
Success Response
{ "wallet": "E3E67B1B3FFA46F606240F1D0B964873D42E9C6D0B7A0BF376A2E128541CC446" }

The rai_node responds with the WALLET_ID. If you lose your WALLET_ID, it can only be recovered via a CLI command. To reiterate, the WALLET_ID is not a seed. The seed can be extracted for backup in Backing Up Seed. Many of the RPC commands in this guide require the WALLET_ID.


Recovering WALLET_ID

If you lose your WALLET_ID, you can print out all your WALLET_IDs and public addresses in those wallets with the following CLI command:

sudo docker exec ${NANO_NAME} rai_node --wallet_list
Success Response
Wallet_ID: E3E67B1B3FFA46F606240F1D0B964873D42E9C6D0B7A0BF376A2E128541CC446
xrb_16odwi933gpzmkgdcy9tt5zef5ka3jcfubc97fwypsokg7sji4mb9n6qtbme
Wallet_ID: DB0711484E35A4C75230D898853A86BFAFE9F87FCE99C83A4C2668C39607DD4B

In this example, the rai_node's internal private-key management system contains two wallets, each with a different 256-bit seed. The first wallet has a single account and the second wallet has zero accounts. Account creation will be covered later.


Backing Up Seed

The following command will print the seed for a given wallet to stdout. Replace ${WALLET_ID} with the WALLET_ID that you would like to display the seed of.

Request
sudo docker exec ${NANO_NAME:-nano_node_1} rai_node --wallet_decrypt_unsafe --wallet ${WALLET_ID}
Success Response
Seed: D56143E7561D71C1AF4D563C6AF79EECE93E82479818AD8ED88BED1AAE8BE4E5
Pub: xrb_16odwi933gpzmkgdcy9tt5zef5ka3jcfubc97fwypsokg7sji4mb9n6qtbme
Prv: 1F6FEB5D1E05C10B904E1112F430C3FA93ACC7067206B63AD155199501794E3E

The rai_node responds with three pieces of information:

  1. The seed of the wallet (back this up).

  2. The private key (deterministically derived from seed) of accounts within the wallet.

    • If you change the seed in a wallet, future created accounts will be derived from that seed.
    • Changing seeds on a wallet that already has accounts can cause accidental loss of funds from improper seed or private key backup.
    • It is recommended to always create a new wallet when restoring a seed.
  3. The pairing public address.


Error Response
Wallet doesn't exist

If anyone has access to the seed, they can freely access funds, so keep this very secure. Since the above command prints to stdout, it is recommended to wipe stdout afterwards:

clear && printf '\e[3J'

Restoring/Changing Seed

Only change the seed of a wallet that contains no accounts. Changing the seed of a wallet that already has accounts may lead to a false sense of security; accounts are generated by the seed that is currently in the wallet. Generating accounts, then switching the seed and backing up the new seed does not backup the previously generated accounts.

Request Format
curl -d '{"action": "wallet_change_seed", "wallet": "<WALLET_ID>", "seed": "<SEED>"}' http://127.0.0.1:7076
Request
curl -d '{"action":"wallet_change_seed", "wallet":"DB0711484E35A4C75230D898853A86BFAFE9F87FCE99C83A4C2668C39607DD4B", "seed":"D56143E7561D71C1AF4D563C6AF79EECE93E82479818AD8ED88BED1AAE8BE4E5"}' http://127.0.0.1:7076
Success Response
{ "success": "" }
Error Response
# Response if the wallet_id isn't found in rai_node
{ "error": "Wallet not found" }
# response if the seed field contains non-hexidecimal values or is too long
{ "error": "Bad seed" }

If the hexidecimal seed represents less than 256 bits, the seed will be 0-padded on the left to become 256 bits.


Account Create

After creating a wallet, it's corresponding WALLET_ID, and backing up the seed (not the wallet_id), the wallet can be populated with accounts. To create a new account in a wallet:

Request Format
curl -d '{"action": "account_create", "wallet": "<WALLET_ID>"}' http://127.0.0.1:7076
Success Response
{ "account": "xrb_16odwi933gpzmkgdcy9tt5zef5ka3jcfubc97fwypsokg7sji4mb9n6qtbme" }
Error Response
{ "error": "Wallet not found" }

Bulk Account Create

To generate many accounts in bulk, it is more efficient to create them all at once using the accounts_create command:

Request Format
curl -d '{"action": "accounts_create", "wallet": "<WALLET_ID>", "count": "<NUM_ACCOUNTS>"}' http://127.0.0.1:7076
Request
curl -d '{"action": "accounts_create", "wallet": "DB0711484E35A4C75230D898853A86BFAFE9F87FCE99C83A4C2668C39607DD4B", "count":"5"}' http://127.0.0.1:7076
Success Response
{
  "accounts": [
    "xrb_35kgi43t5hgi64715qnppmz1yb6re1igfcrkfx4ppirkqpfmecnpd1mdmafu",
    "xrb_3t13y6b7h93yn9hehn8p6yqx1yqzrxxs33drhzep8huhymwxamn15pba75oj",
    "xrb_11exxzfoosai96w7gnrjrn7m6i8bodch37ib8jgxsm5k96na6e1wda8np881",
    "xrb_3xbsso8pkemwatwdnkcyn1bfcmrb8dpcg3pit9zqxj9mkxa6ifiankff6m9x",
    "xrb_1q5gpy46moe1csj8md8oq3x57sxqmwskk8mmr7c63q1yebnjcsxg1yib19kn"
  ]
}

Receiving Funds

As long as the rai_node is synced and unlocked (rai_node locking is not covered in this guide), rai_node automatically creates and signs receive transactions for all accounts in the wallet's internal private-key management system.

In the event that a receive is not automatically generated, it can be manually generated using the receive RPC command.

Semi-Manual Receiving Funds

If the rai_node does not automatically sign in a pending transaction, transactions can be manually signed in. The easiest way is to explicitly command the rai_node to check all of the accounts in all of its wallets for pending blocks.

Request
curl -d '{"action": "search_pending_all"}' http://127.0.0.1:7076
Success Response
{ "success": "" }

As the number of accounts in a rai_node grows, this command becomes increasingly computationally expensive.


Sending funds

The send RPC command sends funds from an account in the specified wallet to a destination address.

Request Format
curl -d '{
  "action": "send",
  "wallet": "<WALLET_ID>",
  "source": "<SOURCE_ADDRESS>",
  "destination": "<DESTINATION_ADDRESS>",
  "amount": "1000000",
  "id": "7081e2b8fec9146e"
}' http://127.0.0.1:7076
Field Description
wallet WALLET_ID containing the source address
source Address you control starting with "xrb_"
destination Destination address starting with "xrb_"
amount Amount to send in raw
id Any string

The "id" field is a safety mechanism that prevents issuing a transaction multiple times by repeating the RPC command.

  • If a transaction is successful, any subsequent send commands with the same identifier will be ignored by the rai_node.
  • If the request times out, then the send may or may not have gone through.
  • Most exchange "double withdraw" bugs are caused by naive error-handling routines re-issuing the send request without the "id" parameter.
  • The "id" field is local to your rai_node instance and does not offer protection when sent to different instances of rai_node that manage the same seed.
  • As previously mentioned, having a seed loaded in multiple online rai_node is strongly discouraged.

Below is a sample command to send 1 nanonano from xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000 to xrb_16odwi933gpzmkgdcy9tt5zef5ka3jcfubc97fwypsokg7sji4mb9n6qtbme.

Request
curl -d '{
  "action": "send",
  "wallet": "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F",
  "source": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000",
  "destination": "xrb_16odwi933gpzmkgdcy9tt5zef5ka3jcfubc97fwypsokg7sji4mb9n6qtbme",
  "amount": "1000000000000000000000000000000",
  "id": "7081e2b8fec9146e"
}' http://127.0.0.1:7076
Success Response
{ "block": "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" }

On success, the rai_node returns the hash of the transaction's block.


Republishing Transactions

It may take a few seconds for the transaction to appear on the Nano Network. If the transaction fails to appear, you may call the republish command with the oldest missing transaction's hash. Account-chains must be continuous and unbroken. If for some reason a transaction fails to properly broadcast, subsequent transactions on the account-chain will not be accepted by the network since the "previous" field in the transaction data refers to a "non-existent" block.

Republishing the missing transaction(s) will make all the subsequent blocks valid in the network's ledger. Republishing does not create new transactions.

The following command rebroadcasts all hashes on an acccount-chain starting at block with hash ${BLOCK_HASH}:

Request Format
curl -d '{"action": "republish", "hash": "<BLOCK_HASH>"}' http://127.0.0.1:7076
Request
curl -d '{"action": "republish", "hash": "AF9C1D46AAE66CC8F827904ED02D4B3D95AA98B1FF058352BA6B670BEFD40231"}' http://127.0.0.1:7076
Success Response
{
  "success": "",
  "blocks": [
    "AF9C1D46AAE66CC8F827904ED02D4B3D95AA98B1FF058352BA6B670BEFD40231",
    "C9A111580A21F3E63F2283DAF6450D5178BFAC2A6C38E09B76EEA9CE37EC9CE0"
  ]
}

On success, the rai_node returns the hashes of all republished blocks.