Source code for nano.rpc

import six
import json
import requests


[docs]def doc_metadata(categories): """ Decorator to add doc metadata for docs generation """ def wrapper(f): f.__doc_meta__ = { 'categories': categories } return f return wrapper
[docs]class RPCException(Exception): """ Base class for RPC errors """
[docs]class Client(object): """ Nano (RaiBlocks) node RPC client :param host: RPC server host, defaults to `'http://localhost:7076'` :param session: optional :py:class:`requests.Session` session to use for this client >>> from nano.rpc import Client >>> rpc = Client('http://localhost:7076') >>> rpc.version() { 'rpc_version': 1, 'store_version': 10, 'node_vendor': 'RaiBlocks 9.0' } """ def __init__(self, host='http://localhost:7076', session=None): """ Initialize the Nano (RaiBlocks) RPC client :param host: location of the RPC server eg. http://localhost:7076 :type host: str :param session: optional `requests` session to use for this client :type host: :py:class:`requests.Session` """ if not session: session = requests.Session() self.session = session self.host = host
[docs] def call(self, action, params=None): """ Makes an RPC call to the server and returns the json response :param action: RPC method to call :type action: str :param params: Dict of arguments to send with RPC call :type params: dict :raises: :py:exc:`nano.rpc.RPCException` :raises: :py:exc:`requests.exceptions.RequestException` >>> rpc.call( ... action='account_balance', ... params={ ... 'account': xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3' ... }) {'balance': '325586539664609129644855132177', 'pending': '2309370940000000000000000000000000'} """ params = params or {} params['action'] = action resp = self.session.post(self.host, json=params) result = resp.json() if 'error' in result: raise RPCException(result['error']) return result
def _process_value(self, value, type): """ Process a value that will be sent to backend :param value: the value to return :param type: hint for what sort of value this is :type type: str """ if not isinstance(value, six.string_types + (list,)): value = json.dumps(value) return value
[docs] @doc_metadata(categories=['account']) def account_balance(self, account): """ Returns how many RAW is owned and how many have not yet been received by **account** :param account: Account id to return balance of :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_balance( ... account="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" ... ) { "balance": 10000, "pending": 10000 } """ account = self._process_value(account, 'account') payload = { "account": account, } resp = self.call('account_balance', payload) for k, v in resp.items(): resp[k] = int(v) return resp
[docs] @doc_metadata(categories=['account']) def accounts_balances(self, accounts): """ Returns how many RAW is owned and how many have not yet been received by **accounts** list :param accounts: list of accounts to return balances for :type accounts: list of str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.accounts_balances( ... accounts=[ ... "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", ... "xrb_3i1aq1cchnmbn9x5rsbap8b15akfh7wj7pwskuzi7ahz8oq6cobd99d4r3b7" ... ] ... ) { "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000": { "balance": 10000, "pending": 10000 }, "xrb_3i1aq1cchnmbn9x5rsbap8b15akfh7wj7pwskuzi7ahz8oq6cobd99d4r3b7": { "balance": 10000000, "pending": 0 } } """ accounts = self._process_value(accounts, 'list') payload = { "accounts": accounts, } resp = self.call('accounts_balances', payload) accounts_balances = resp.get('balances') or {} for account, balances in accounts_balances.items(): for k in balances: balances[k] = int(balances[k]) return accounts_balances
[docs] @doc_metadata(categories=['account']) def account_block_count(self, account): """ Get number of blocks for a specific **account** :param account: Account to get number of blocks for :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_block_count(account="xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3") 19 """ account = self._process_value(account, 'account') payload = { "account": account, } resp = self.call('account_block_count', payload) return int(resp['block_count'])
[docs] @doc_metadata(categories=['wallet', 'account']) def accounts_create(self, wallet, count, work=True): """ Creates new accounts, insert next deterministic keys in **wallet** up to **count** .. enable_control required .. version 8.0 required :param wallet: Wallet to create new accounts in :type wallet: str :param count: Number of accounts to create :type count: int :param work: If false, disables work generation after creating account :type work: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.accounts_create( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... count=2 ... ) [ "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "xrb_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3s00000000" ] """ wallet = self._process_value(wallet, 'wallet') count = self._process_value(count, 'int') payload = { "wallet": wallet, "count": count, } if not work: payload['work'] = self._process_value(work, 'strbool') resp = self.call('accounts_create', payload) return resp.get('accounts') or []
[docs] @doc_metadata(categories=['account']) def accounts_frontiers(self, accounts): """ Returns a list of pairs of account and block hash representing the head block for **accounts** list :param accounts: Accounts to return frontier blocks for :type accounts: list of str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.accounts_frontiers( ... accounts=[ ... "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3", ... "xrb_3i1aq1cchnmbn9x5rsbap8b15akfh7wj7pwskuzi7ahz8oq6cobd99d4r3b7" ... ] ... ) { "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3": "791AF413173EEE674A6FCF633B5DFC0F3C33F397F0DA08E987D9E0741D40D81A", "xrb_3i1aq1cchnmbn9x5rsbap8b15akfh7wj7pwskuzi7ahz8oq6cobd99d4r3b7": "6A32397F4E95AF025DE29D9BF1ACE864D5404362258E06489FABDBA9DCCC046F" } """ accounts = self._process_value(accounts, 'list') payload = { "accounts": accounts, } resp = self.call('accounts_frontiers', payload) return resp.get('frontiers') or {}
[docs] @doc_metadata(categories=['account']) def account_info(self, account, representative=False, weight=False, pending=False): """ Returns frontier, open block, change representative block, balance, last modified timestamp from local database & block count for **account** :param account: Account to return info for :type account: str :param representative: if True, also returns the representative block :type representative: bool :param weight: if True, also returns the voting weight :type weight: bool :param pending: if True, also returns the pending balance :type pending: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_info( ... account="xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3" ... ) { "frontier": "FF84533A571D953A596EA401FD41743AC85D04F406E76FDE4408EAED50B473C5", "open_block": "991CF190094C00F0B68E2E5F75F6BEE95A2E0BD93CEAA4A6734DB9F19B728948", "representative_block": "991CF190094C00F0B68E2E5F75F6BEE95A2E0BD93CEAA4A6734DB9F19B728948", "balance": "235580100176034320859259343606608761791", "modified_timestamp": "1501793775", "block_count": "33" } """ account = self._process_value(account, 'account') payload = { "account": account, } if representative: payload['representative'] = self._process_value(representative, 'strbool') if weight: payload['weight'] = self._process_value(weight, 'strbool') if pending: payload['pending'] = self._process_value(pending, 'strbool') resp = self.call('account_info', payload) for key in ('modified_timestamp', 'block_count', 'balance', 'pending', 'weight'): if key in resp: resp[key] = int(resp[key]) return resp
[docs] @doc_metadata(categories=['wallet', 'account']) def account_create(self, wallet, work=True): """ Creates a new account, insert next deterministic key in **wallet** .. enable_control required :param wallet: Wallet to insert new account into :type wallet: str :param work: If false, disables work generation after creating account :type work: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_create( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } if not work: payload['work'] = self._process_value(work, 'strbool') resp = self.call('account_create', payload) return resp['account']
[docs] @doc_metadata(categories=['account']) def account_get(self, key): """ Get account number for the **public key** :param key: Public key to get account for :type key: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_get( ... key="3068BB1CA04525BB0E416C485FE6A67FD52540227D267CC8B6E8DA958A7FA039" ... ) "xrb_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx" """ key = self._process_value(key, 'publickey') payload = { "key": key, } resp = self.call('account_get', payload) return resp['account']
[docs] @doc_metadata(categories=['account']) def account_history(self, account, count): """ Reports send/receive information for a **account** :param account: Account to get send/receive information for :type account: str :param count: number of blocks to return :type count: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_history( ... account="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", ... count=1 ... ) [ { "hash": "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", "type": "receive", "account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "amount": 100000000000000000000000000000000 } ] """ account = self._process_value(account, 'account') count = self._process_value(count, 'int') payload = { "account": account, "count": count, } resp = self.call('account_history', payload) history = resp.get('history') or [] for entry in history: entry['amount'] = int(entry['amount']) return history
[docs] @doc_metadata(categories=['wallet', 'account']) def account_list(self, wallet): """ Lists all the accounts inside **wallet** :param wallet: Wallet to get account list for :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_list( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) [ "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" ] """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('account_list', payload) return resp.get('accounts') or []
[docs] @doc_metadata(categories=['wallet', 'account']) def account_move(self, source, wallet, accounts): """ Moves **accounts** from **source** to **wallet** .. enable_control required :param source: wallet to move accounts from :type source: str :param wallet: wallet to move accounts to :type wallet: str :param accounts: accounts to move :type accounts: list of str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_move( ... source="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... accounts=[ ... "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" ... ] ... ) True """ wallet = self._process_value(wallet, 'wallet') source = self._process_value(source, 'wallet') accounts = self._process_value(accounts, 'list') payload = { "wallet": wallet, "source": source, "accounts": accounts, } resp = self.call('account_move', payload) return resp['moved'] == '1'
[docs] @doc_metadata(categories=['account']) def accounts_pending(self, accounts, count=None, threshold=None, source=False): """ Returns a list of block hashes which have not yet been received by these **accounts** :param accounts: Accounts to return list of block hashes for :type accounts: list of str :param count: Max number of blocks to returns :type count: int :param threshold: Minimum amount in raw per block :type threshold: int :param source: if True returns the source as well :type source: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.accounts_pending( ... accounts=[ ... "xrb_1111111111111111111111111111111111111111111111111117353trpda", ... "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3" ... ], ... count=1 ... ) { "xrb_1111111111111111111111111111111111111111111111111117353trpda": [ "142A538F36833D1CC78B94E11C766F75818F8B940771335C6C1B8AB880C5BB1D" ], "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3": [ "4C1FEEF0BEA7F50BE35489A1233FE002B212DEA554B55B1B470D78BD8F210C74" ] } """ payload = { "accounts": accounts, } accounts = self._process_value(accounts, 'list') if count is not None: payload['count'] = self._process_value(count, 'int') if threshold is not None: payload['threshold'] = self._process_value(threshold, 'int') if source: payload['source'] = self._process_value(source, 'strbool') resp = self.call('accounts_pending', payload) blocks = resp.get('blocks') or {} for account, data in blocks.items(): if isinstance(data, list): # list of block hashes, no change needed continue if not data: blocks[account] = [] # convert a "" response to [] continue for key, value in data.items(): if isinstance(value, six.string_types): # amount data[key] = int(value) elif isinstance(value, dict): # dict with "amount" and "source" for key in ('amount',): if key in value: value[key] = int(value[key]) return blocks
[docs] @doc_metadata(categories=['account']) def account_key(self, account): """ Get the public key for **account** :param account: Account to get public key for :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_key( ... account="xrb_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx" ... ) "3068BB1CA04525BB0E416C485FE6A67FD52540227D267CC8B6E8DA958A7FA039" """ account = self._process_value(account, 'account') payload = { "account": account, } resp = self.call('account_key', payload) return resp['key']
[docs] @doc_metadata(categories=['account', 'wallet']) def account_remove(self, wallet, account): """ Remove **account** from **wallet** .. enable_control required :param wallet: Wallet to remove account from :type wallet: str :param account: Account to remove :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_remove( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... account="xrb_39a73oy5ungrhxy5z5oao1xso4zo7dmgpjd4u74xcrx3r1w6rtazuouw6qfi" ... ) True """ wallet = self._process_value(wallet, 'wallet') account = self._process_value(account, 'account') payload = { "wallet": wallet, "account": account, } resp = self.call('account_remove', payload) return resp['removed'] == '1'
[docs] @doc_metadata(categories=['account']) def account_representative(self, account): """ Returns the representative for **account** :param account: Account to get representative for :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_representative( ... account="xrb_39a73oy5ungrhxy5z5oao1xso4zo7dmgpjd4u74xcrx3r1w6rtazuouw6qfi" ) "xrb_16u1uufyoig8777y6r8iqjtrw8sg8maqrm36zzcm95jmbd9i9aj5i8abr8u5" """ account = self._process_value(account, 'account') payload = { "account": account, } resp = self.call('account_representative', payload) return resp['representative']
[docs] @doc_metadata(categories=['wallet', 'account']) def account_representative_set(self, wallet, account, representative, work=None): """ Sets the representative for **account** in **wallet** .. enable_control required :param wallet: Wallet to use for account :type wallet: str :param account: Account to set representative for :type account: str :param representative: Representative to set to :type representative: str :param work: If set, is used as the work for the block :type work: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_representative_set( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... account="xrb_39a73oy5ungrhxy5z5oao1xso4zo7dmgpjd4u74xcrx3r1w6rtazuouw6qfi", ... representative="xrb_16u1uufyoig8777y6r8iqjtrw8sg8maqrm36zzcm95jmbd9i9aj5i8abr8u5" ... ) "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" """ wallet = self._process_value(wallet, 'wallet') account = self._process_value(account, 'account') representative = self._process_value(representative, 'account') payload = { "wallet": wallet, "account": account, "representative": representative, } if work is not None: payload['work'] = self._process_value(work, 'work') resp = self.call('account_representative_set', payload) return resp['block']
[docs] @doc_metadata(categories=['account']) def account_weight(self, account): """ Returns the voting weight for **account** :param account: Account to get voting weight for :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.account_weight( ... account="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" ... ) 10000 """ account = self._process_value(account, 'account') payload = { "account": account, } resp = self.call('account_weight', payload) return int(resp['weight'])
[docs] @doc_metadata(categories=['global']) def available_supply(self): """ Returns how many rai are in the public supply :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.available_supply() 10000 """ resp = self.call('available_supply') return int(resp['available'])
[docs] @doc_metadata(categories=['block']) def block(self, hash): """ Retrieves a json representation of **block** :param hash: Hash of block to return representation for :type hash: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.block( ... hash="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) { "account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "work": "0000000000000000", "source": "FA5B51D063BADDF345EFD7EF0D3C5FB115C85B1EF4CDE89D8B7DF3EAF60A04A4", "representative": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "type": "open" } """ hash = self._process_value(hash, 'block') payload = { "hash": hash, } resp = self.call('block', payload) return json.loads(resp['contents'])
[docs] @doc_metadata(categories=['block']) def blocks(self, hashes): """ Retrieves a json representations of **blocks** :param hashes: List of block hashes to return :type hashes: list of str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.blocks( ... hashes=["000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F"] ... ) { "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F": { "account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "work": "0000000000000000", "source": "FA5B51D063BADDF345EFD7EF0D3C5FB115C85B1EF4CDE89D8B7DF3EAF60A04A4", "representative": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "type": "open" } } """ hashes = self._process_value(hashes, 'list') payload = { "hashes": hashes, } resp = self.call('blocks', payload) blocks = resp.get('blocks') or {} for k, v in blocks.items(): blocks[k] = json.loads(v) return blocks
[docs] @doc_metadata(categories=['block']) def blocks_info(self, hashes, pending=False, source=False): """ Retrieves a json representations of **blocks** with transaction **amount** & block **account** :param hashes: List of block hashes to return info for :type hashes: list of str :param pending: If true, returns pending amount as well :type pending: bool :param source: If true, returns source account as well :type source: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.blocks_info(hashes=["000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F"]) { "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F": { "block_account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "amount": "1000000000000000000000000000000", "contents": { "account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "work": "0000000000000000", "source": "FA5B51D063BADDF345EFD7EF0D3C5FB115C85B1EF4CDE89D8B7DF3EAF60A04A4", "representative": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "type": "open" } } } """ hashes = self._process_value(hashes, 'list') payload = { "hashes": hashes, } if pending: payload['pending'] = self._process_value(pending, 'strbool') if source: payload['source'] = self._process_value(source, 'strbool') resp = self.call('blocks_info', payload) blocks = resp.get('blocks') or {} for block, data in blocks.items(): data['contents'] = json.loads(data['contents']) for key in ('amount', 'pending'): if key in data: data[key] = int(data[key]) return blocks
[docs] @doc_metadata(categories=['account', 'block']) def block_account(self, hash): """ Returns the account containing block :param hash: Hash of the block to return account for :type hash: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.block_account( ... hash="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" """ hash = self._process_value(hash, 'block') payload = { "hash": hash, } resp = self.call('block_account', payload) return resp['account']
[docs] @doc_metadata(categories=['global', 'block']) def block_count(self): """ Reports the number of blocks in the ledger and unchecked synchronizing blocks :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.block_count() { "count": 1000, "unchecked": 10 } """ resp = self.call('block_count') for k, v in resp.items(): resp[k] = int(v) return resp
[docs] @doc_metadata(categories=['global', 'block']) def block_count_type(self): """ Reports the number of blocks in the ledger by type (send, receive, open, change) :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.block_count_type() { "send": 1000, "receive": 900, "open": 100, "change": 50 } """ resp = self.call('block_count_type') for k, v in resp.items(): resp[k] = int(v) return resp
[docs] @doc_metadata(categories=['block']) def block_create(self, type, account, wallet=None, representative=None, key=None, destination=None, amount=None, balance=None, previous=None, source=None, work=None): """ Creates a json representations of new block based on input data & signed with private key or account in **wallet** for offline signing .. enable_control required .. version 8.1 required :param type: Type of block to create one of **open**, **receive**, **change**, **send** :type type: str :param account: Account for the signed block :type account: str :param wallet: Wallet to use :type wallet: str :param representative: Representative account for **open** and **change** blocks :type representative: str :param key: Private key to use to open account for **open** blocks :type key: str :param destination: Destination account for **send** blocks :type destination: str :param amount: Amount in raw for **send** blocks :type amount: int :param balance: Balance in raw of account for **send** blocks :type balance: int :param previous: Previous block hash for **receive**, **send** and **change** blocks :type previous: str :param source: Source block for **open** and **receive** blocks :type source: str :param work: Work value to use for block from external source :type work: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.block_create( ... type="open", ... account="xrb_3kdbxitaj7f6mrir6miiwtw4muhcc58e6tn5st6rfaxsdnb7gr4roudwn951", ... source="19D3D919475DEED4696B5D13018151D1AF88B2BD3BCFF048B45031C1F36D1858", ... representative="xrb_1hza3f7wiiqa7ig3jczyxj5yo86yegcmqk3criaz838j91sxcckpfhbhhra1", ... key="0000000000000000000000000000000000000000000000000000000000000001" ... ) { "block": { "account": "xrb_3kdbxitaj7f6mrir6miiwtw4muhcc58e6tn5st6rfaxsdnb7gr4roudwn951", "representative": "xrb_1hza3f7wiiqa7ig3jczyxj5yo86yegcmqk3criaz838j91sxcckpfhbhhra1", "signature": "5974324F8CC42DA56F62FC212A17886BDCB18DE363D04DA84EEDC99CB4A33919D14A2CF9DE9D534FAA6D0B91D01F0622205D898293525E692586C84F2DCF9208", "source": "19D3D919475DEED4696B5D13018151D1AF88B2BD3BCFF048B45031C1F36D1858", "type": "open", "work": "4ec76c9bda2325ed" }, "hash": "F47B23107E5F34B2CE06F562B5C435DF72A533251CB414C51B2B62A8F63A00E4" } >>> rpc.block_create( ... type="receive", ... account="xrb_3kdbxitaj7f6mrir6miiwtw4muhcc58e6tn5st6rfaxsdnb7gr4roudwn951", ... previous="F47B23107E5F34B2CE06F562B5C435DF72A533251CB414C51B2B62A8F63A00E4", ... source="19D3D919475DEED4696B5D13018151D1AF88B2BD3BCFF048B45031C1F36D1858", ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... ) { "block": { "previous": "F47B23107E5F34B2CE06F562B5C435DF72A533251CB414C51B2B62A8F63A00E4", "signature": "A13FD22527771667D5DFF33D69787D734836A3561D8A490C1F4917A05D77EA09860461D5FBFC99246A4EAB5627F119AD477598E22EE021C4711FACF4F3C80D0E", "source": "19D3D919475DEED4696B5D13018151D1AF88B2BD3BCFF048B45031C1F36D1858", "type": "receive", "work": "6acb5dd43a38d76a" }, "hash": "314BA8D9057678C1F53371C2DB3026C1FAC01EC8E7802FD9A2E8130FC523429E" } >>> rpc.block_create( ... type="send", ... account="xrb_3kdbxitaj7f6mrir6miiwtw4muhcc58e6tn5st6rfaxsdnb7gr4roudwn951", ... amount=10000000000000000000000000000000, ... balance=20000000000000000000000000000000, ... destination="xrb_18gmu6engqhgtjnppqam181o5nfhj4sdtgyhy36dan3jr9spt84rzwmktafc", ... previous="314BA8D9057678C1F53371C2DB3026C1FAC01EC8E7802FD9A2E8130FC523429E", ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... work="478563b2d9facfd4", ... ) { "block": { "balance": "0000007E37BE2022C0914B2680000000", "destination": "xrb_18gmu6engqhgtjnppqam181o5nfhj4sdtgyhy36dan3jr9spt84rzwmktafc", "previous": "314BA8D9057678C1F53371C2DB3026C1FAC01EC8E7802FD9A2E8130FC523429E", "signature": "F19CA177EFA8692C8CBF7478CE3213F56E4A85DF760DA7A9E69141849831F8FD79BA9ED89CEC807B690FB4AA42D5008F9DBA7115E63C935401F1F0EFA547BC00", "type": "send", "work": "478563b2d9facfd4" }, "hash": "F958305C0FF0551421D4ABEDCCF302079D020A0A3833E33F185E2B0415D4567A" } >>> rpc.block_create( ... type="change", ... account="xrb_3kdbxitaj7f6mrir6miiwtw4muhcc58e6tn5st6rfaxsdnb7gr4roudwn951", ... representative="xrb_18gmu6engqhgtjnppqam181o5nfhj4sdtgyhy36dan3jr9spt84rzwmktafc", ... previous="F958305C0FF0551421D4ABEDCCF302079D020A0A3833E33F185E2B0415D4567A", ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... ) { "block": { "previous": "F958305C0FF0551421D4ABEDCCF302079D020A0A3833E33F185E2B0415D4567A", "representative": "xrb_18gmu6engqhgtjnppqam181o5nfhj4sdtgyhy36dan3jr9spt84rzwmktafc", "signature": "98B4D56881D9A88B170A6B2976AE21900C26A27F0E2C338D93FDED56183B73D19AA5BEB48E43FCBB8FF8293FDD368CEF50600FECEFD490A0855ED702ED209E04", "type": "change", "work": "55e5b7a83edc3f4f" }, "hash": "654FA425CEBFC9E7726089E4EDE7A105462D93DBC915FFB70B50909920A7D286" } """ payload = { "type": self._process_value(type, 'blocktype'), "account": self._process_value(account, 'account'), } if representative is not None: payload['representative'] = self._process_value(representative, 'account') if key is not None: payload['key'] = self._process_value(key, 'privatekey') if source is not None: payload['source'] = self._process_value(source, 'block') if destination is not None: payload['destination'] = self._process_value(destination, 'account') if amount is not None: payload['amount'] = self._process_value(amount, 'int') if balance is not None: payload['balance'] = self._process_value(balance, 'int') if previous is not None: payload['previous'] = self._process_value(previous, 'block') if wallet is not None: payload['wallet'] = self._process_value(wallet, 'wallet') if work is not None: payload['work'] = self._process_value(work, 'work') resp = self.call('block_create', payload) resp['block'] = json.loads(resp['block']) return resp
[docs] @doc_metadata(categories=['node']) def bootstrap(self, address, port): """ Initialize bootstrap to specific **IP address** and **port** :param address: Ip address to bootstrap :type address: str :param port: Port to bootstrap :type port: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.bootstrap(address="::ffff:138.201.94.249", port="7075") True """ address = self._process_value(address, 'ipaddr') port = self._process_value(port, 'int') payload = { "address": address, "port": port, } resp = self.call('bootstrap', payload) return 'success' in resp
[docs] @doc_metadata(categories=['node']) def bootstrap_any(self): """ Initialize multi-connection bootstrap to random peers :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.bootstrap_any() True """ resp = self.call('bootstrap_any') return 'success' in resp
[docs] @doc_metadata(categories=['block']) def chain(self, block, count): """ Returns a list of block hashes in the account chain starting at **block** up to **count** :param block: Block hash to start at :type block: str :param count: Number of blocks to return up to :type count: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.chain( ... block="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... count=1 ... ) [ "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ] """ block = self._process_value(block, 'block') count = self._process_value(count, 'int') payload = { "block": block, "count": count, } resp = self.call('chain', payload) return resp.get('blocks') or []
[docs] @doc_metadata(categories=['account']) def delegators(self, account): """ Returns a list of pairs of delegator names given **account** a representative and its balance .. version 8.0 required :param account: Account to return delegators for :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.delegators( ... account="xrb_1111111111111111111111111111111111111111111111111117353trpda" ... ) { "xrb_13bqhi1cdqq8yb9szneoc38qk899d58i5rcrgdk5mkdm86hekpoez3zxw5sd": "500000000000000000000000000000000000", "xrb_17k6ug685154an8gri9whhe5kb5z1mf5w6y39gokc1657sh95fegm8ht1zpn": "961647970820730000000000000000000000" } """ account = self._process_value(account, 'account') payload = { "account": account, } resp = self.call('delegators', payload) delegators = resp.get('delegators') or {} for k, v in delegators.items(): delegators[k] = int(v) return delegators
[docs] @doc_metadata(categories=['account']) def delegators_count(self, account): """ Get number of delegators for a specific representative **account** .. version 8.0 required :param account: Account to get number of delegators for :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.delegators_count( ... account="xrb_1111111111111111111111111111111111111111111111111117353trpda" ... ) 2 """ account = self._process_value(account, 'account') payload = { "account": account, } resp = self.call('delegators_count', payload) return int(resp['count'])
[docs] @doc_metadata(categories=['utility']) def deterministic_key(self, seed, index): """ Derive deterministic keypair from **seed** based on **index** :param seed: Seed used to get keypair :type seed: str :param index: Index of the generated keypair :type index: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.deterministic_key( ... seed="0000000000000000000000000000000000000000000000000000000000000000", ... index=0 ... ) { "private": "9F0E444C69F77A49BD0BE89DB92C38FE713E0963165CCA12FAF5712D7657120F", "public": "C008B814A7D269A1FA3C6528B19201A24D797912DB9996FF02A1FF356E45552B", "account": "xrb_3i1aq1cchnmbn9x5rsbap8b15akfh7wj7pwskuzi7ahz8oq6cobd99d4r3b7" } """ seed = self._process_value(seed, 'seed') index = self._process_value(index, 'int') payload = { "seed": seed, "index": index, } resp = self.call('deterministic_key', payload) return resp
[docs] @doc_metadata(categories=['account']) def frontiers(self, account, count): """ Returns a list of pairs of account and block hash representing the head block starting at **account** up to **count** :param account: Account to get frontier blocks for :type account: str :param count: Max amount to return :type count: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.frontiers( ... account="xrb_1111111111111111111111111111111111111111111111111111hifc8npp", ... count=1 ... ) { "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000": "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" } """ account = self._process_value(account, 'account') count = self._process_value(count, 'int') payload = { "account": account, "count": count, } resp = self.call('frontiers', payload) return resp.get('frontiers') or {}
[docs] @doc_metadata(categories=['global']) def frontier_count(self): """ Reports the number of accounts in the ledger :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.frontier_count() 1000 """ resp = self.call('frontier_count') return int(resp['count'])
[docs] @doc_metadata(categories=['block']) def history(self, hash, count): """ Reports send/receive information for a chain of blocks :param hash: Hash of block to receive history for :type hash: str :param count: Max number of blocks to return :type count: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.history( ... hash="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... count=1 ... ) [ { "hash": "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", "type": "receive", "account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "amount": "100000000000000000000000000000000" } ] """ hash = self._process_value(hash, 'block') count = self._process_value(count, 'int') payload = { "hash": hash, "count": count, } resp = self.call('history', payload) history = resp.get('history') or [] for entry in history: entry['amount'] = int(entry['amount']) return history
[docs] @doc_metadata(categories=['utility']) def mrai_from_raw(self, amount): """ Divide a raw amount down by the Mrai ratio. :param amount: Amount in raw to convert to Mrai :type amount: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.mrai_from_raw(amount=1000000000000000000000000000000) 1 """ amount = self._process_value(amount, 'int') payload = { "amount": amount, } resp = self.call('mrai_from_raw', payload) return int(resp['amount'])
[docs] @doc_metadata(categories=['utility']) def mrai_to_raw(self, amount): """ Multiply an Mrai amount by the Mrai ratio. :param amount: Amount in Mrai to convert to raw :type amount: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.mrai_to_raw(amount=1) 1000000000000000000000000000000 """ amount = self._process_value(amount, 'int') payload = { "amount": amount, } resp = self.call('mrai_to_raw', payload) return int(resp['amount'])
[docs] @doc_metadata(categories=['utility']) def krai_from_raw(self, amount): """ Divide a raw amount down by the krai ratio. :param amount: Amount in raw to convert to krai :type amount: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.krai_from_raw(amount=1000000000000000000000000000) 1 """ amount = self._process_value(amount, 'int') payload = { "amount": amount, } resp = self.call('krai_from_raw', payload) return int(resp['amount'])
[docs] @doc_metadata(categories=['utility']) def krai_to_raw(self, amount): """ Multiply an krai amount by the krai ratio. :param amount: Amount in krai to convert to raw :type amount: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.krai_to_raw(amount=1) 1000000000000000000000000000 """ amount = self._process_value(amount, 'int') payload = { "amount": amount, } resp = self.call('krai_to_raw', payload) return int(resp['amount'])
[docs] @doc_metadata(categories=['utility']) def rai_from_raw(self, amount): """ Divide a raw amount down by the rai ratio. :param amount: Amount in raw to convert to rai :type amount: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.rai_from_raw(amount=1000000000000000000000000) 1 """ amount = self._process_value(amount, 'int') payload = { "amount": amount, } resp = self.call('rai_from_raw', payload) return int(resp['amount'])
[docs] @doc_metadata(categories=['utility']) def rai_to_raw(self, amount): """ Multiply an rai amount by the rai ratio. :param amount: Amount in rai to convert to raw :type amount: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.rai_to_raw(amount=1) 1000000000000000000000000 """ amount = self._process_value(amount, 'int') payload = { "amount": amount, } resp = self.call('rai_to_raw', payload) return int(resp['amount'])
[docs] @doc_metadata(categories=['utility']) def key_create(self): """ Generates an **adhoc random keypair** :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.key_create() { "private": "781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3", "public": "3068BB1CA04525BB0E416C485FE6A67FD52540227D267CC8B6E8DA958A7FA039", "account": "xrb_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx" } """ resp = self.call('key_create') return resp
[docs] @doc_metadata(categories=['utility']) def key_expand(self, key): """ Derive public key and account number from **private key** :param key: Private key to generate account and public key of :type key: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.key_expand( key="781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3" ) { "private": "781186FB9EF17DB6E3D1056550D9FAE5D5BBADA6A6BC370E4CBB938B1DC71DA3", "public": "3068BB1CA04525BB0E416C485FE6A67FD52540227D267CC8B6E8DA958A7FA039", "account": "xrb_1e5aqegc1jb7qe964u4adzmcezyo6o146zb8hm6dft8tkp79za3sxwjym5rx" } """ key = self._process_value(key, 'privatekey') payload = { "key": key, } resp = self.call('key_expand', payload) return resp
[docs] @doc_metadata(categories=['node']) def keepalive(self, address, port): """ Tells the node to send a keepalive packet to **address**:**port** .. enable_control required :param address: IP address of node to send keepalive packet to :type address: str :param port: Port of node to send keepalive packet to :type port: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.keepalive(address="::ffff:192.168.1.1", port=1024) True """ address = self._process_value(address, 'ipaddr') port = self._process_value(port, 'int') payload = { "address": address, "port": port, } resp = self.call('keepalive', payload) return resp == {}
[docs] @doc_metadata(categories=['account']) def ledger(self, account, count=None, representative=False, weight=False, pending=False, sorting=False): """ Returns frontier, open block, change representative block, balance, last modified timestamp from local database & block count starting at **account** up to **count** .. enable_control required .. version 8.0 required :param account: Account to return blocks for :type account: str :param count: Max number of blocks to return :type count: int :param representative: If true, returns the representative as well :type representative: bool :param weight: If true, returns the voting weight as well :type weight: bool :param pending: If true, returns the pending amount as well :type pending: bool :param sorting: If true, sorts the response by balance :type sorting: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.ledger( ... account="xrb_1111111111111111111111111111111111111111111111111111hifc8npp", ... count=1 ... ) { "xrb_11119gbh8hb4hj1duf7fdtfyf5s75okzxdgupgpgm1bj78ex3kgy7frt3s9n": { "frontier": "E71AF3E9DD86BBD8B4620EFA63E065B34D358CFC091ACB4E103B965F95783321", "open_block": "643B77F1ECEFBDBE1CC909872964C1DBBE23A6149BD3CEF2B50B76044659B60F", "representative_block": "643B77F1ECEFBDBE1CC909872964C1DBBE23A6149BD3CEF2B50B76044659B60F", "balance": 0, "modified_timestamp": 1511476234, "block_count": 2 } } """ account = self._process_value(account, 'account') payload = { "account": account, } if count is not None: payload['count'] = self._process_value(count, 'int') if sorting: payload['sorting'] = self._process_value(sorting, 'strbool') if representative: payload['representative'] = self._process_value(representative, 'strbool') if weight: payload['weight'] = self._process_value(weight, 'strbool') if pending: payload['pending'] = self._process_value(pending, 'strbool') resp = self.call('ledger', payload) accounts = resp.get('accounts') or {} int_keys = ( 'balance', 'modified_timestamp', 'block_count', 'weight', 'pending' ) for account, frontier in accounts.items(): for key in int_keys: if key in frontier: frontier[key] = int(frontier[key]) return accounts
[docs] @doc_metadata(categories=['wallet']) def payment_begin(self, wallet): """ Begin a new payment session. Searches wallet for an account that's marked as available and has a 0 balance. If one is found, the account number is returned and is marked as unavailable. If no account is found, a new account is created, placed in the wallet, and returned. :param wallet: Wallet to begin payment in :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.payment_begin( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('payment_begin', payload) return resp['account']
# NOTE(dan): Server RPC is broken here - it *should* return an # 'error' for 'No wallet found', but it returns 'status' instead # https://github.com/clemahieu/nano/blob/e9592e5/rai/node/rpc.cpp#L2238
[docs] @doc_metadata(categories=['wallet']) def payment_init(self, wallet): """ Marks all accounts in wallet as available for being used as a payment session. :param wallet: Wallet to init payment in :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.payment_init( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) True """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('payment_init', payload) return resp['status'] == 'Ready'
[docs] @doc_metadata(categories=['wallet']) def payment_end(self, account, wallet): """ End a payment session. Marks the account as available for use in a payment session. :param account: Account to mark available :type account: str :param wallet: Wallet to end payment session for :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.payment_end( ... account="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", ... wallet="FFFD1BAEC8EC20814BBB9059B393051AAA8380F9B5A2E6B2489A277D81789EEE" ... ) True """ account = self._process_value(account, 'account') wallet = self._process_value(wallet, 'wallet') payload = { "account": account, "wallet": wallet, } resp = self.call('payment_end', payload) return resp == {}
[docs] @doc_metadata(categories=['account']) def payment_wait(self, account, amount, timeout): """ Wait for payment of **amount** to arrive in **account** or until **timeout** milliseconds have elapsed. :param account: Account to wait for payment :type account: str :param amount: Amount in raw of funds to wait for payment to arrive :type amount: int :param timeout: Timeout in milliseconds to wait for :type timeout: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.payment_wait( ... account="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", ... amount=1, ... timeout=1000 ... ) True """ account = self._process_value(account, 'account') amount = self._process_value(amount, 'int') timeout = self._process_value(timeout, 'int') payload = { "account": account, "amount": amount, "timeout": timeout, } resp = self.call('payment_wait', payload) return resp['status'] == 'success'
[docs] @doc_metadata(categories=['block']) def process(self, block): """ Publish **block** to the network :param block: Block to publish :type block: dict or json :raises: :py:exc:`nano.rpc.RPCException` >>> block = { "account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "work": "0000000000000000", "source": "FA5B51D063BADDF345EFD7EF0D3C5FB115C85B1EF4CDE89D8B7DF3EAF60A04A4", "representative": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "type": "open" } >>> rpc.process(block=block) "42A723D2B60462BF7C9A003FE9A70057D3A6355CA5F1D0A57581000000000000" >>> rpc.process(json.dumps(block)) "42A723D2B60462BF7C9A003FE9A70057D3A6355CA5F1D0A57581000000000000" """ if isinstance(block, dict): block = json.dumps(block, sort_keys=True) payload = { "block": block, } resp = self.call('process', payload) return resp['hash']
[docs] @doc_metadata(categories=['wallet', 'account', 'block']) def receive(self, wallet, account, block, work=None): """ Receive pending **block** for **account** in **wallet** .. enable_control required :param wallet: Wallet of account to receive block for :type wallet: str :param account: Account to receive block for :type account: str :param block: Block hash to receive :type block: str :param work: If set, uses this work for the receive block :type work: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.receive( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... account="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", ... block="53EAA25CE28FA0E6D55EA9704B32604A736966255948594D55CBB05267CECD48", ... work="12041e830ad10de1" ... ) "EE5286AB32F580AB65FD84A69E107C69FBEB571DEC4D99297E19E3FA5529547B" """ wallet = self._process_value(wallet, 'wallet') account = self._process_value(account, 'account') block = self._process_value(block, 'block') payload = { "wallet": wallet, "account": account, "block": block, } if work: payload['work'] = self._process_value(work, 'work') resp = self.call('receive', payload) return resp['block']
[docs] @doc_metadata(categories=['node']) def receive_minimum(self): """ Returns receive minimum for node .. enable_control required .. version 8.0 required :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.receive_minimum() 1000000000000000000000000 """ resp = self.call('receive_minimum') return int(resp['amount'])
[docs] @doc_metadata(categories=['node']) def receive_minimum_set(self, amount): """ Set **amount** as new receive minimum for node until restart .. enable_control required .. version 8.0 required :param amount: Amount in raw to set as minimum to receive :type amount: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.receive_minimum_set(amount=1000000000000000000000000000000) True """ amount = self._process_value(amount, 'int') payload = { "amount": amount, } resp = self.call('receive_minimum_set', payload) return 'success' in resp
[docs] @doc_metadata(categories=['global']) def representatives(self, count=None, sorting=False): """ Returns a list of pairs of representative and its voting weight :param count: Max amount of representatives to return :type count: int :param sorting: If true, sorts by weight :type sorting: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.representatives() { "xrb_1111111111111111111111111111111111111111111111111117353trpda": 3822372327060170000000000000000000000, "xrb_1111111111111111111111111111111111111111111111111awsq94gtecn": 30999999999999999999999999000000, "xrb_114nk4rwjctu6n6tr6g6ps61g1w3hdpjxfas4xj1tq6i8jyomc5d858xr1xi": 0 } """ payload = {} if count is not None: payload['count'] = self._process_value(count, 'int') if sorting: payload['sorting'] = self._process_value(sorting, 'strbool') resp = self.call('representatives', payload) representatives = resp.get('representatives') or {} for k, v in representatives.items(): representatives[k] = int(v) return representatives
[docs] @doc_metadata(categories=['node', 'block']) def unchecked(self, count=None): """ Returns a list of pairs of unchecked synchronizing block hash and its json representation up to **count** .. version 8.0 required :param count: Max amount of unchecked blocks to return :type count: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.unchecked(count=1) { "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F": { "account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "work": "0000000000000000", "source": "FA5B51D063BADDF345EFD7EF0D3C5FB115C85B1EF4CDE89D8B7DF3EAF60A04A4", "representative": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "type": "open" } } """ payload = {} if count is not None: payload["count"] = self._process_value(count, 'int') resp = self.call('unchecked', payload) blocks = resp.get('blocks') or {} for block, block_json in blocks.items(): blocks[block] = json.loads(block_json) return blocks
[docs] @doc_metadata(categories=['node', 'block']) def unchecked_clear(self): """ Clear unchecked synchronizing blocks .. enable_control required .. version 8.0 required :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.unchecked_clear() True """ resp = self.call('unchecked_clear') return 'success' in resp
[docs] @doc_metadata(categories=['node', 'block']) def unchecked_get(self, hash): """ Retrieves a json representation of unchecked synchronizing block by **hash** .. version 8.0 required :param hash: Hash of unchecked block to get :type hash: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.unchecked_get( ... hash="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) { "account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "work": "0000000000000000", "source": "FA5B51D063BADDF345EFD7EF0D3C5FB115C85B1EF4CDE89D8B7DF3EAF60A04A4", "representative": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "type": "open" } """ hash = self._process_value(hash, 'block') payload = { "hash": hash, } resp = self.call('unchecked_get', payload) return json.loads(resp['contents'])
[docs] @doc_metadata(categories=['node', 'block']) def unchecked_keys(self, key=None, count=None): """ Retrieves unchecked database keys, blocks hashes & a json representations of unchecked pending blocks starting from **key** up to **count** .. version 8.0 required :param key: Starting key to return unchecked keys for :type key: str :param count: Max number of keys/blocks to return :type count: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.unchecked_keys( ... key="FA5B51D063BADDF345EFD7EF0D3C5FB115C85B1EF4CDE89D8B7DF3EAF60A04A4", ... count=1 ... ) [ { "key": "FA5B51D063BADDF345EFD7EF0D3C5FB115C85B1EF4CDE89D8B7DF3EAF60A04A4", "hash": "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", "contents": { "account": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "work": "0000000000000000", "source": "FA5B51D063BADDF345EFD7EF0D3C5FB115C85B1EF4CDE89D8B7DF3EAF60A04A4", "representative": "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", "signature": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "type": "open" } } ] """ payload = {} if key: payload['key'] = self._process_value(key, 'publickey') if count is not None: payload['count'] = self._process_value(count, 'int') resp = self.call('unchecked_keys', payload) unchecked = resp.get('unchecked') or [] for entry in unchecked: entry['contents'] = json.loads(entry['contents']) return unchecked
[docs] @doc_metadata(categories=['account']) def validate_account_number(self, account): """ Check whether **account** is a valid account number :param account: Account number to check :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.validate_account_number( ... account="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" ... ) True """ account = self._process_value(account, 'account') payload = { "account": account, } resp = self.call('validate_account_number', payload) return resp['valid'] == '1'
[docs] @doc_metadata(categories=['wallet']) def wallet_representative(self, wallet): """ Returns the default representative for **wallet** :param wallet: Wallet to get default representative account for :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_representative( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_representative', payload) return resp['representative']
[docs] @doc_metadata(categories=['wallet']) def wallet_representative_set(self, wallet, representative): """ Sets the default **representative** for **wallet** .. enable_control required :param wallet: Wallet to set default representative account for :type wallet: str :param representative: Representative account to set for **wallet** :type representative: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_representative_set( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... representative="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" ... ) True """ wallet = self._process_value(wallet, 'wallet') representative = self._process_value(representative, 'account') payload = { "wallet": wallet, "representative": representative, } resp = self.call('wallet_representative_set', payload) return resp['set'] == '1'
[docs] @doc_metadata(categories=['wallet']) def wallet_add(self, wallet, key, work=True): """ Add an adhoc private key **key** to **wallet** .. enable_control required :param wallet: Wallet to add private key to :type wallet: str :param key: Private key to add :type key: str :param work: If false, disables work generation :type work: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_add( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... key="34F0A37AAD20F4A260F0A5B3CB3D7FB50673212263E58A380BC10474BB039CE4" ... ) "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" """ wallet = self._process_value(wallet, 'wallet') key = self._process_value(key, 'privatekey') payload = { "wallet": wallet, "key": key, } if not work: payload['work'] = self._process_value(work, 'strbool') resp = self.call('wallet_add', payload) return resp['account']
[docs] @doc_metadata(categories=['wallet']) def wallet_balance_total(self, wallet): """ Returns the sum of all accounts balances in **wallet** :param wallet: Wallet to return sum of balances for :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_balance_total( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) { "balance": 10000, "pending": 10000 } """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_balance_total', payload) for k, v in resp.items(): resp[k] = int(v) return resp
[docs] @doc_metadata(categories=['wallet']) def wallet_balances(self, wallet): """ Returns how many rai is owned and how many have not yet been received by all accounts in **wallet** :param wallet: Wallet to return balances for :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_balances( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) { "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000": { "balance": 10000, "pending": 10000 } } """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_balances', payload) balances = resp.get('balances') or {} for account, balance in balances.items(): for k, v in balances[account].items(): balances[account][k] = int(v) return balances
[docs] @doc_metadata(categories=['wallet']) def wallet_change_seed(self, wallet, seed): """ Changes seed for **wallet** to **seed** .. enable_control required :param wallet: Wallet to change seed for :type wallet: str :param seed: Seed to change wallet to :type seed: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_change_seed( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... seed="74F2B37AAD20F4A260F0A5B3CB3D7FB51673212263E58A380BC10474BB039CEE" ... ) True """ wallet = self._process_value(wallet, 'wallet') seed = self._process_value(seed, 'seed') payload = { "wallet": wallet, "seed": seed, } resp = self.call('wallet_change_seed', payload) return 'success' in resp
[docs] @doc_metadata(categories=['wallet']) def wallet_contains(self, wallet, account): """ Check whether **wallet** contains **account** :param wallet: Wallet to check contains **account** :type wallet: str :param account: Account to check exists in **wallet** :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_contains( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... account="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000" ... ) True """ wallet = self._process_value(wallet, 'wallet') account = self._process_value(account, 'account') payload = { "wallet": wallet, "account": account, } resp = self.call('wallet_contains', payload) return resp['exists'] == '1'
[docs] @doc_metadata(categories=['wallet']) def wallet_create(self): """ Creates a new random wallet id .. enable_control required :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_create() "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" """ resp = self.call('wallet_create') return resp['wallet']
[docs] @doc_metadata(categories=['wallet']) def wallet_destroy(self, wallet): """ Destroys **wallet** and all contained accounts .. enable_control required :param wallet: Wallet to destroy :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_destroy( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) True """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_destroy', payload) return resp == {}
[docs] @doc_metadata(categories=['wallet']) def wallet_export(self, wallet): """ Return a json representation of **wallet** :param wallet: Wallet to export :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_export(wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F") { "0000000000000000000000000000000000000000000000000000000000000000": "0000000000000000000000000000000000000000000000000000000000000001" } """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_export', payload) return json.loads(resp['json'])
[docs] @doc_metadata(categories=['wallet']) def wallet_frontiers(self, wallet): """ Returns a list of pairs of account and block hash representing the head block starting for accounts from **wallet** :param wallet: Wallet to return frontiers for :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_frontiers( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) { "xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000": "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" } """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_frontiers', payload) return resp.get('frontiers') or {}
[docs] @doc_metadata(categories=['wallet']) def wallet_key_valid(self, wallet): """ Returns if a **wallet** key is valid :param wallet: Wallet to check key is valid :type wallet: str >>> rpc.wallet_key_valid( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) True """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_key_valid', payload) return resp['valid'] == '1'
[docs] @doc_metadata(categories=['wallet']) def wallet_lock(self, wallet): """ Locks a **wallet** :param wallet: Wallet to lock :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_lock( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) True """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_lock', payload) return resp['locked'] == '1'
[docs] @doc_metadata(categories=['wallet']) def wallet_locked(self, wallet): """ Checks whether **wallet** is locked :param wallet: Wallet to check if locked :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_locked( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) False """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_locked', payload) return resp['locked'] == '1'
[docs] @doc_metadata(categories=['wallet']) def wallet_unlock(self, wallet, password): """ Unlocks **wallet** using **password** :param wallet: Wallet to unlock :type wallet: str :param password: Password to enter :type password: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_unlock( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... password="test" ... ) True """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, "password": password, } resp = self.call('wallet_unlock', payload) return resp['valid'] == '1'
[docs] @doc_metadata(categories=['wallet']) def wallet_pending(self, wallet, count=None, threshold=None, source=False): """ Returns a list of block hashes which have not yet been received by accounts in this **wallet** .. enable_control required .. version 8.0 required :param wallet: Wallet to get list of pending block hashes for :type wallet: str :param count: Max amount of blocks to return :type count: int :param threshold: Minimum amount in raw per block :type threshold: int :param source: If true, returns source account as well :type source: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_pending( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... count=1 ... ) { "xrb_1111111111111111111111111111111111111111111111111117353trpda": [ "142A538F36833D1CC78B94E11C766F75818F8B940771335C6C1B8AB880C5BB1D" ], "xrb_3t6k35gi95xu6tergt6p69ck76ogmitsa8mnijtpxm9fkcm736xtoncuohr3": [ "4C1FEEF0BEA7F50BE35489A1233FE002B212DEA554B55B1B470D78BD8F210C74" ] } """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } if count is not None: payload['count'] = self._process_value(count, 'int') if threshold is not None: payload['threshold'] = self._process_value(threshold, 'int') if source: payload['source'] = self._process_value(source, 'strbool') resp = self.call('wallet_pending', payload) blocks = resp.get('blocks') or {} for account, data in blocks.items(): if isinstance(data, list): # list of block hashes, no change needed continue if not data: blocks[account] = [] # convert a "" response to [] continue for key, value in data.items(): if isinstance(value, six.string_types): # amount data[key] = int(value) elif isinstance(value, dict): # dict with "amount" and "source" for key in ('amount',): if key in value: value[key] = int(value[key]) return blocks or {}
[docs] @doc_metadata(categories=['wallet']) def wallet_republish(self, wallet, count): """ Rebroadcast blocks for accounts from **wallet** starting at frontier down to **count** to the network .. enable_control required .. version 8.0 required :param wallet: Wallet to rebroadcast blocks for :type wallet: str :param count: Max amount of blocks to rebroadcast since frontier block :type count: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_republish( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... count=2 ... ) [ "991CF190094C00F0B68E2E5F75F6BEE95A2E0BD93CEAA4A6734DB9F19B728948", "A170D51B94E00371ACE76E35AC81DC9405D5D04D4CEBC399AEACE07AE05DD293", "90D0C16AC92DD35814E84BFBCC739A039615D0A42A76EF44ADAEF1D99E9F8A35" ] """ wallet = self._process_value(wallet, 'wallet') count = self._process_value(count, 'int') payload = { "wallet": wallet, "count": count, } resp = self.call('wallet_republish', payload) return resp.get('blocks') or []
[docs] @doc_metadata(categories=['work']) def wallet_work_get(self, wallet): """ Returns a list of pairs of account and work from **wallet** .. enable_control required .. version 8.0 required :param wallet: Wallet to return work for :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.wallet_work_get( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) { "xrb_1111111111111111111111111111111111111111111111111111hifc8npp": "432e5cf728c90f4f" } """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('wallet_work_get', payload) return resp.get('works') or {}
[docs] @doc_metadata(categories=['wallet']) def password_change(self, wallet, password): """ Changes the password for **wallet** to **password** .. enable_control required :param wallet: Wallet to change password for :type wallet: str :param password: Password to set :type password: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.password_change( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... password="test" ... ) True """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, "password": password, } resp = self.call('password_change', payload) return resp['changed'] == '1'
[docs] @doc_metadata(categories=['wallet']) def password_enter(self, wallet, password): """ Enters the **password** in to **wallet** :param wallet: Wallet to enter password for :type wallet: str :param password: Password to enter :type password: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.password_enter( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... password="test" ... ) True """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, "password": password, } resp = self.call('password_enter', payload) return resp['valid'] == '1'
[docs] @doc_metadata(categories=['wallet']) def password_valid(self, wallet): """ Checks whether the password entered for **wallet** is valid :param wallet: Wallet to check password for :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.password_valid( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) True """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('password_valid', payload) return resp['valid'] == '1'
[docs] @doc_metadata(categories=['node']) def peers(self): """ Returns a list of pairs of peer IPv6:port and its node network version :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.peers() { "[::ffff:172.17.0.1]:32841": 3 } """ resp = self.call('peers') result = {} peers = resp.get('peers') or {} for host, version in peers.items(): result[host] = int(version) return result
[docs] @doc_metadata(categories=['account']) def pending(self, account, count=None, threshold=None, source=False): """ Returns a list of pending block hashes with amount more or equal to **threshold** .. version 8.0 required :param account: Account to get list of pending block hashes for :type account: str :param count: Max blocks to return :type count: int :param threshold: Minimum amount in raw for blocks :type threshold: int :param source: If true, returns source address as well :type source: bool :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.pending( ... account="xrb_1111111111111111111111111111111111111111111111111117353trpda" ... ) [ "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ] >>> rpc.pending( ... account="xrb_1111111111111111111111111111111111111111111111111117353trpda", ... count=1, ... threshold=1000000000000000000000000 ... ) { "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F": "6000000000000000000000000000000" } """ account = self._process_value(account, 'account') payload = { "account": account, } if count is not None: payload['count'] = self._process_value(count, 'int') if threshold is not None: payload['threshold'] = self._process_value(threshold, 'int') if source: payload['source'] = self._process_value(source, 'strbool') resp = self.call('pending', payload) blocks = resp.get('blocks') or {} if isinstance(blocks, list): return blocks for block, value in blocks.items(): if isinstance(value, six.string_types): # amount blocks[block] = int(value) elif isinstance(value, dict): # dict with "amount" and "source" for key in ('amount',): if key in value: value[key] = int(value[key]) return blocks
[docs] @doc_metadata(categories=['block']) def pending_exists(self, hash): """ Check whether block is pending by **hash** .. version 8.0 required :param hash: Hash of block to check if pending :type hash: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.pending_exists( hash="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ) True """ hash = self._process_value(hash, 'block') payload = { "hash": hash, } resp = self.call('pending_exists', payload) return resp['exists'] == '1'
[docs] @doc_metadata(categories=['work']) def work_cancel(self, hash): """ Stop generating **work** for block .. enable_control required :param hash: Hash to stop generating work for :type hash: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.work_cancel( ... hash="718CC2121C3E641059BC1C2CFC45666C99E8AE922F7A807B7D07B62C995D79E2" ... ) True """ hash = self._process_value(hash, 'block') payload = { "hash": hash, } resp = self.call('work_cancel', payload) return resp == {}
[docs] @doc_metadata(categories=['work']) def work_generate(self, hash): """ Generates **work** for block .. enable_control required :param hash: Hash to start generating **work** for :type hash: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.work_generate( ... hash="718CC2121C3E641059BC1C2CFC45666C99E8AE922F7A807B7D07B62C995D79E2" ... ) "2bf29ef00786a6bc" """ hash = self._process_value(hash, 'block') payload = { "hash": hash, } resp = self.call('work_generate', payload) return resp['work']
[docs] @doc_metadata(categories=['work']) def work_get(self, wallet, account): """ Retrieves work for **account** in **wallet** .. enable_control required .. version 8.0 required :param wallet: Wallet to get account work for :type wallet: str :param account: Account to get work for :type account: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.work_get( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... account="xrb_1111111111111111111111111111111111111111111111111111hifc8npp" ... ) "432e5cf728c90f4f" """ wallet = self._process_value(wallet, 'wallet') account = self._process_value(account, 'account') payload = { "wallet": wallet, "account": account, } resp = self.call('work_get', payload) return resp['work']
[docs] @doc_metadata(categories=['work']) def work_set(self, wallet, account, work): """ Set **work** for **account** in **wallet** .. enable_control required .. version 8.0 required :param wallet: Wallet to set work for account for :type wallet: str :param account: Account to set work for :type account: str :param work: Work to set for account in wallet :type work: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.work_set( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... account="xrb_1111111111111111111111111111111111111111111111111111hifc8npp", ... work="0000000000000000" ... ) True """ wallet = self._process_value(wallet, 'wallet') account = self._process_value(account, 'account') work = self._process_value(work, 'work') payload = { "wallet": wallet, "account": account, "work": work, } resp = self.call('work_set', payload) return 'success' in resp
[docs] @doc_metadata(categories=['work']) def work_peer_add(self, address, port): """ Add specific **IP address** and **port** as work peer for node until restart .. enable_control required .. version 8.0 required :param address: IP address of work peer to add :type address: str :param port: Port work peer to add :type port: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.work_peer_add(address="::ffff:172.17.0.1", port="7076") True """ address = self._process_value(address, 'ipaddr') port = self._process_value(port, 'int') payload = { "address": address, "port": port, } resp = self.call('work_peer_add', payload) return 'success' in resp
[docs] @doc_metadata(categories=['work']) def work_peers(self): """ Retrieve work peers .. enable_control required .. version 8.0 required :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.work_peers() [ "::ffff:172.17.0.1:7076" ] """ resp = self.call('work_peers') return resp.get('work_peers') or []
[docs] @doc_metadata(categories=['work']) def work_peers_clear(self): """ Clear work peers node list until restart .. enable_control required .. version 8.0 required :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.work_peers_clear() True """ resp = self.call('work_peers_clear') return 'success' in resp
[docs] @doc_metadata(categories=['work', 'block']) def work_validate(self, work, hash): """ Check whether **work** is valid for block :param work: Work to validate :type work: str :param hash: Hash of block to validate work for :type hash: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.work_validate( ... work="2bf29ef00786a6bc", ... hash="718CC2121C3E641059BC1C2CFC45666C99E8AE922F7A807B7D07B62C995D79E2" ... ) True """ work = self._process_value(work, 'work') hash = self._process_value(hash, 'block') payload = { "work": work, "hash": hash, } resp = self.call('work_validate', payload) return resp['valid'] == '1'
[docs] @doc_metadata(categories=['block']) def republish(self, hash, count=None, sources=None, destinations=None): """ Rebroadcast blocks starting at **hash** to the network :param hash: Hash of block to start rebroadcasting from :type hash: str :param count: Max number of blocks to rebroadcast :type count: int :param sources: If set, additionally rebroadcasts source chain blocks for receive/open up to **sources** depth :type sources: int :param destinations: If set, additionally rebroadcasts destination chain blocks for receive/open up to **destinations** depth :type destinations: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.republish( ... hash="991CF190094C00F0B68E2E5F75F6BEE95A2E0BD93CEAA4A6734DB9F19B728948" ... ) [ "991CF190094C00F0B68E2E5F75F6BEE95A2E0BD93CEAA4A6734DB9F19B728948", "A170D51B94E00371ACE76E35AC81DC9405D5D04D4CEBC399AEACE07AE05DD293" ] """ hash = self._process_value(hash, 'block') payload = { "hash": hash, } if count is not None: payload['count'] = self._process_value(count, 'int') if sources is not None: payload['sources'] = self._process_value(sources, 'int') if destinations is not None: payload['destinations'] = self._process_value(destinations, 'int') resp = self.call('republish', payload) return resp.get('blocks') or []
[docs] @doc_metadata(categories=['wallet']) def search_pending(self, wallet): """ Tells the node to look for pending blocks for any account in **wallet** .. enable_control required :param wallet: Wallet to search for pending blocks :type wallet: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.search_pending( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" ... ) True """ wallet = self._process_value(wallet, 'wallet') payload = { "wallet": wallet, } resp = self.call('search_pending', payload) return resp['started'] == '1'
[docs] @doc_metadata(categories=['node']) def search_pending_all(self): """ Tells the node to look for pending blocks for any account in all available wallets .. enable_control required .. version 8.0 required :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.search_pending_all() True """ resp = self.call('search_pending_all') return 'success' in resp
[docs] @doc_metadata(categories=['wallet', 'account']) def send(self, wallet, source, destination, amount, work=None): """ Send **amount** from **source** in **wallet** to **destination** .. enable_control required :param wallet: Wallet of account used to send funds :type wallet: str :param source: Account to send funds from :type source: str :param destination: Account to send funds to :type destination: str :param amount: Amount in raw to send :type amount: int :param work: If set, uses this work for the block :type work: str :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.send( ... wallet="000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F", ... source="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", ... destination="xrb_3e3j5tkog48pnny9dmfzj1r16pg8t1e76dz5tmac6iq689wyjfpi00000000", ... amount=1000000, ... work="2bf29ef00786a6bc" ... ) "000D1BAEC8EC208142C99059B393051BAC8380F9B5A2E6B2489A277D81789F3F" """ wallet = self._process_value(wallet, 'wallet') source = self._process_value(source, 'account') destination = self._process_value(destination, 'account') amount = self._process_value(amount, 'int') payload = { "wallet": wallet, "source": source, "destination": destination, "amount": amount, } if work is not None: payload['work'] = self._process_value(work, 'work') resp = self.call('send', payload) return resp['block']
[docs] @doc_metadata(categories=['block']) def successors(self, block, count): """ Returns a list of block hashes in the account chain ending at **block** up to **count** :param block: Hash of block to start returning successors for :type block: str :param count: Max number of successor blocks to return :type count: int :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.successors( ... block="991CF190094C00F0B68E2E5F75F6BEE95A2E0BD93CEAA4A6734DB9F19B728948", ... count=1 ... ) [ "A170D51B94E00371ACE76E35AC81DC9405D5D04D4CEBC399AEACE07AE05DD293" ] """ block = self._process_value(block, 'block') count = self._process_value(count, 'int') payload = { "block": block, "count": count, } resp = self.call('successors', payload) return resp.get('blocks') or []
[docs] @doc_metadata(categories=['node']) def stop(self): """ Stop the node .. enable_control required :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.stop() True """ resp = self.call('stop') return 'success' in resp
[docs] @doc_metadata(categories=['node']) def version(self): """ Returns the node's RPC version :raises: :py:exc:`nano.rpc.RPCException` >>> rpc.version() { "rpc_version": 1, "store_version": 10, "node_vendor": "RaiBlocks 9.0" } """ resp = self.call('version') for key in ('rpc_version', 'store_version'): resp[key] = int(resp[key]) return resp
RPCClient = Client