From 230f73e1212e672478b454b5d9e0906615f889df Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 9 May 2019 15:39:30 +0000 Subject: functional_tests: add is_key_image_spent tests --- utils/python-rpc/framework/daemon.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'utils/python-rpc/framework/daemon.py') diff --git a/utils/python-rpc/framework/daemon.py b/utils/python-rpc/framework/daemon.py index 23d5ec0f0..577df0dc0 100644 --- a/utils/python-rpc/framework/daemon.py +++ b/utils/python-rpc/framework/daemon.py @@ -344,3 +344,9 @@ class Daemon(object): 'id': '0' } return self.rpc.send_json_rpc_request(get_fee_estimate) + + def is_key_image_spent(self, key_images = []): + is_key_image_spent = { + 'key_images': key_images, + } + return self.rpc.send_request('/is_key_image_spent', is_key_image_spent) -- cgit v1.2.3 From 51bd45c3528242d16eaa404679dab0d7440dc0e7 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 9 May 2019 15:50:10 +0000 Subject: functional_tests: add save_bc --- tests/functional_tests/blockchain.py | 3 +++ utils/python-rpc/framework/daemon.py | 5 +++++ 2 files changed, 8 insertions(+) (limited to 'utils/python-rpc/framework/daemon.py') diff --git a/tests/functional_tests/blockchain.py b/tests/functional_tests/blockchain.py index 2c3f34c35..92857eae3 100755 --- a/tests/functional_tests/blockchain.py +++ b/tests/functional_tests/blockchain.py @@ -330,6 +330,9 @@ class BlockchainTest(): for txid in [alt_blocks[0], alt_blocks[2], alt_blocks[4]]: assert len([chain for chain in res.chains if chain.block_hash == txid]) == 1 + print('Saving blockchain explicitely') + daemon.save_bc() + if __name__ == '__main__': BlockchainTest().run_test() diff --git a/utils/python-rpc/framework/daemon.py b/utils/python-rpc/framework/daemon.py index 577df0dc0..f9bc51eb2 100644 --- a/utils/python-rpc/framework/daemon.py +++ b/utils/python-rpc/framework/daemon.py @@ -350,3 +350,8 @@ class Daemon(object): 'key_images': key_images, } return self.rpc.send_request('/is_key_image_spent', is_key_image_spent) + + def save_bc(self): + save_bc = { + } + return self.rpc.send_request('/save_bc', save_bc) -- cgit v1.2.3 From d53a55204fd0c10845b8872837ff14aff17ff1c0 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 9 May 2019 18:36:19 +0000 Subject: functional_tests: add get_transaction_pool_stats Also fix part of the RPC results being returned as binary. This makes the RPC backward incompatible. --- src/rpc/core_rpc_server_commands_defs.h | 6 +-- tests/functional_tests/txpool.py | 84 +++++++++++++++++++++++++++++++++ utils/python-rpc/framework/daemon.py | 5 ++ 3 files changed, 92 insertions(+), 3 deletions(-) (limited to 'utils/python-rpc/framework/daemon.py') diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 2f7f22293..39995c206 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -86,8 +86,8 @@ namespace cryptonote // whether they can talk to a given daemon without having to know in // advance which version they will stop working with // Don't go over 32767 for any of these -#define CORE_RPC_VERSION_MAJOR 2 -#define CORE_RPC_VERSION_MINOR 10 +#define CORE_RPC_VERSION_MAJOR 3 +#define CORE_RPC_VERSION_MINOR 0 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -1516,7 +1516,7 @@ namespace cryptonote KV_SERIALIZE(num_10m) KV_SERIALIZE(num_not_relayed) KV_SERIALIZE(histo_98pc) - KV_SERIALIZE_CONTAINER_POD_AS_BLOB(histo) + KV_SERIALIZE(histo) KV_SERIALIZE(num_double_spends) END_KV_SERIALIZE_MAP() }; diff --git a/tests/functional_tests/txpool.py b/tests/functional_tests/txpool.py index b6af4c84f..fd74ae129 100755 --- a/tests/functional_tests/txpool.py +++ b/tests/functional_tests/txpool.py @@ -81,6 +81,26 @@ class TransferTest(): return txes + def check_empty_pool(self): + daemon = Daemon() + + res = daemon.get_transaction_pool_hashes() + assert not 'tx_hashes' in res or len(res.tx_hashes) == 0 + res = daemon.get_transaction_pool_stats() + assert res.pool_stats.bytes_total == 0 + assert res.pool_stats.bytes_min == 0 + assert res.pool_stats.bytes_max == 0 + assert res.pool_stats.bytes_med == 0 + assert res.pool_stats.fee_total == 0 + assert res.pool_stats.oldest == 0 + assert res.pool_stats.txs_total == 0 + assert res.pool_stats.num_failing == 0 + assert res.pool_stats.num_10m == 0 + assert res.pool_stats.num_not_relayed == 0 + assert res.pool_stats.histo_98pc == 0 + assert not 'histo' in res.pool_stats or len(res.pool_stats.histo) == 0 + assert res.pool_stats.num_double_spends == 0 + def check_txpool(self): daemon = Daemon() wallet = Wallet() @@ -89,6 +109,8 @@ class TransferTest(): height = res.height txpool_size = res.tx_pool_size + self.check_empty_pool() + txes = self.create_txes('46r4nYSevkfBUMhuykdK3gQ98XDqDTYW1hNLaXNvjpsJaSbNtdXh1sKMsdVgqkaihChAzEy29zEDPMR3NHQvGoZCLGwTerK', 5) res = daemon.get_info() @@ -97,6 +119,10 @@ class TransferTest(): res = daemon.get_transaction_pool() assert len(res.transactions) == txpool_size + total_bytes = 0 + total_fee = 0 + min_bytes = 99999999999999 + max_bytes = 0 for txid in txes.keys(): x = [x for x in res.transactions if x.id_hash == txid] assert len(x) == 1 @@ -110,9 +136,26 @@ class TransferTest(): assert x.fee == txes[txid].fee assert x.tx_blob == txes[txid].tx_blob + total_bytes += x.blob_size + total_fee += x.fee + min_bytes = min(min_bytes, x.blob_size) + max_bytes = max(max_bytes, x.blob_size) + res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(txes.keys()) + res = daemon.get_transaction_pool_stats() + assert res.pool_stats.bytes_total == total_bytes + assert res.pool_stats.bytes_min == min_bytes + assert res.pool_stats.bytes_max == max_bytes + assert res.pool_stats.bytes_med >= min_bytes and res.pool_stats.bytes_med <= max_bytes + assert res.pool_stats.fee_total == total_fee + assert res.pool_stats.txs_total == len(txes) + assert res.pool_stats.num_failing == 0 + assert res.pool_stats.num_10m == 0 + assert res.pool_stats.num_not_relayed == 0 + assert res.pool_stats.num_double_spends == 0 + print('Flushing 2 transactions') txes_keys = list(txes.keys()) daemon.flush_txpool([txes_keys[1], txes_keys[3]]) @@ -127,6 +170,42 @@ class TransferTest(): res = daemon.get_transaction_pool_hashes() assert sorted(res.tx_hashes) == sorted(new_keys) + res = daemon.get_transaction_pool() + assert len(res.transactions) == len(new_keys) + total_bytes = 0 + total_fee = 0 + min_bytes = 99999999999999 + max_bytes = 0 + for txid in new_keys: + x = [x for x in res.transactions if x.id_hash == txid] + assert len(x) == 1 + x = x[0] + assert x.kept_by_block == False + assert x.last_failed_id_hash == '0'*64 + assert x.double_spend_seen == False + assert x.weight >= x.blob_size + + assert x.blob_size * 2 == len(txes[txid].tx_blob) + assert x.fee == txes[txid].fee + assert x.tx_blob == txes[txid].tx_blob + + total_bytes += x.blob_size + total_fee += x.fee + min_bytes = min(min_bytes, x.blob_size) + max_bytes = max(max_bytes, x.blob_size) + + res = daemon.get_transaction_pool_stats() + assert res.pool_stats.bytes_total == total_bytes + assert res.pool_stats.bytes_min == min_bytes + assert res.pool_stats.bytes_max == max_bytes + assert res.pool_stats.bytes_med >= min_bytes and res.pool_stats.bytes_med <= max_bytes + assert res.pool_stats.fee_total == total_fee + assert res.pool_stats.txs_total == len(new_keys) + assert res.pool_stats.num_failing == 0 + assert res.pool_stats.num_10m == 0 + assert res.pool_stats.num_not_relayed == 0 + assert res.pool_stats.num_double_spends == 0 + print('Flushing unknown transactions') unknown_txids = ['1'*64, '2'*64, '3'*64] daemon.flush_txpool(unknown_txids) @@ -140,6 +219,8 @@ class TransferTest(): res = daemon.get_transaction_pool_hashes() assert not 'tx_hashes' in res or len(res.tx_hashes) == 0 + self.check_empty_pool() + print('Popping block') daemon.pop_blocks(1) res = daemon.get_transaction_pool_hashes() @@ -159,6 +240,9 @@ class TransferTest(): assert x.fee == txes[txid].fee assert x.tx_blob == txes[txid].tx_blob + daemon.flush_txpool() + self.check_empty_pool() + if __name__ == '__main__': TransferTest().run_test() diff --git a/utils/python-rpc/framework/daemon.py b/utils/python-rpc/framework/daemon.py index f9bc51eb2..89b13b951 100644 --- a/utils/python-rpc/framework/daemon.py +++ b/utils/python-rpc/framework/daemon.py @@ -208,6 +208,11 @@ class Daemon(object): } return self.rpc.send_request('/get_transaction_pool_hashes', get_transaction_pool_hashes) + def get_transaction_pool_stats(self): + get_transaction_pool_stats = { + } + return self.rpc.send_request('/get_transaction_pool_stats', get_transaction_pool_stats) + def flush_txpool(self, txids = []): flush_txpool = { 'method': 'flush_txpool', -- cgit v1.2.3 From e037ecb014858054670ef2b0992ba7a934c84e15 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Fri, 24 May 2019 21:56:04 +0000 Subject: functional_tests: check for RPC methods which aren't exposed --- tests/functional_tests/CMakeLists.txt | 4 + .../functional_tests/check_missing_rpc_methods.py | 50 ++++++++ utils/python-rpc/framework/daemon.py | 138 +++++++++++++++++++++ utils/python-rpc/framework/wallet.py | 4 + 4 files changed, 196 insertions(+) create mode 100644 tests/functional_tests/check_missing_rpc_methods.py (limited to 'utils/python-rpc/framework/daemon.py') diff --git a/tests/functional_tests/CMakeLists.txt b/tests/functional_tests/CMakeLists.txt index fd49ba623..bc55da9e3 100644 --- a/tests/functional_tests/CMakeLists.txt +++ b/tests/functional_tests/CMakeLists.txt @@ -59,3 +59,7 @@ else() message(WARNING "functional_tests_rpc skipped, needs the 'requests' python module") set(CTEST_CUSTOM_TESTS_IGNORE ${CTEST_CUSTOM_TESTS_IGNORE} functional_tests_rpc) endif() + +add_test( + NAME check_missing_rpc_methods + COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/check_missing_rpc_methods.py" "${CMAKE_SOURCE_DIR}") diff --git a/tests/functional_tests/check_missing_rpc_methods.py b/tests/functional_tests/check_missing_rpc_methods.py new file mode 100644 index 000000000..6fadebf9b --- /dev/null +++ b/tests/functional_tests/check_missing_rpc_methods.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +from __future__ import print_function +import sys +import re + +USAGE = 'usage: check_untested_methods.py ' +try: + rootdir = sys.argv[1] +except: + print(USAGE) + sys.exit(1) + +sys.path.insert(0, rootdir + '/utils/python-rpc') + +from framework import daemon +from framework import wallet + +modules = [ + { + 'name': 'daemon', + 'object': daemon.Daemon(), + 'path': rootdir + '/src/rpc/core_rpc_server.h', + 'ignore': [] + }, + { + 'name': 'wallet', + 'object': wallet.Wallet(), + 'path': rootdir + '/src/wallet/wallet_rpc_server.h', + 'ignore': [] + } +] + +error = False +for module in modules: + for line in open(module['path']).readlines(): + if 'MAP_URI_AUTO_JON2' in line or 'MAP_JON_RPC' in line: + match = re.search('.*\"(.*)\".*', line) + name = match.group(1) + if name in module['ignore'] or name.endswith('.bin'): + continue + if 'MAP_URI_AUTO_JON2' in line: + if not name.startswith('/'): + print('Error: %s does not start with /' % name) + error = True + name = name[1:] + if not hasattr(module['object'], name): + print('Error: %s API method %s does not have a matching function' % (module['name'], name)) + +sys.exit(1 if error else 0) diff --git a/utils/python-rpc/framework/daemon.py b/utils/python-rpc/framework/daemon.py index 89b13b951..1d6c57c56 100644 --- a/utils/python-rpc/framework/daemon.py +++ b/utils/python-rpc/framework/daemon.py @@ -49,6 +49,7 @@ class Daemon(object): 'id': '0' } return self.rpc.send_json_rpc_request(getblocktemplate) + get_block_template = getblocktemplate def send_raw_transaction(self, tx_as_hex, do_not_relay = False, do_sanity_checks = True): send_raw_transaction = { @@ -57,6 +58,7 @@ class Daemon(object): 'do_sanity_checks': do_sanity_checks, } return self.rpc.send_request("/send_raw_transaction", send_raw_transaction) + sendrawtransaction = send_raw_transaction def submitblock(self, block): submitblock = { @@ -66,6 +68,7 @@ class Daemon(object): 'id': '0' } return self.rpc.send_json_rpc_request(submitblock) + submit_block = submitblock def getblock(self, hash = '', height = 0, fill_pow_hash = False): getblock = { @@ -79,6 +82,7 @@ class Daemon(object): 'id': '0' } return self.rpc.send_json_rpc_request(getblock) + get_block = getblock def getlastblockheader(self): getlastblockheader = { @@ -89,6 +93,7 @@ class Daemon(object): 'id': '0' } return self.rpc.send_json_rpc_request(getlastblockheader) + get_last_block_header = getlastblockheader def getblockheaderbyhash(self, hash = "", hashes = []): getblockheaderbyhash = { @@ -101,6 +106,7 @@ class Daemon(object): 'id': '0' } return self.rpc.send_json_rpc_request(getblockheaderbyhash) + get_block_header_by_hash = getblockheaderbyhash def getblockheaderbyheight(self, height): getblockheaderbyheight = { @@ -112,6 +118,7 @@ class Daemon(object): 'id': '0' } return self.rpc.send_json_rpc_request(getblockheaderbyheight) + get_block_header_by_height = getblockheaderbyheight def getblockheadersrange(self, start_height, end_height, fill_pow_hash = False): getblockheadersrange = { @@ -125,6 +132,7 @@ class Daemon(object): 'id': '0' } return self.rpc.send_json_rpc_request(getblockheadersrange) + get_block_headers_range = getblockheadersrange def get_connections(self): get_connections = { @@ -141,6 +149,7 @@ class Daemon(object): 'id': '0' } return self.rpc.send_json_rpc_request(get_info) + getinfo = get_info def hard_fork_info(self): hard_fork_info = { @@ -172,6 +181,7 @@ class Daemon(object): 'id': '0' } return self.rpc.send_request("/get_height", get_height) + getheight = get_height def pop_blocks(self, nblocks = 1): pop_blocks = { @@ -261,6 +271,7 @@ class Daemon(object): 'split': split, } return self.rpc.send_request('/get_transactions', get_transactions) + gettransactions = get_transactions def get_outs(self, outputs = [], get_txid = False): get_outs = { @@ -360,3 +371,130 @@ class Daemon(object): save_bc = { } return self.rpc.send_request('/save_bc', save_bc) + + def get_peer_list(self): + get_peer_list = { + } + return self.rpc.send_request('/get_peer_list', get_peer_list) + + def set_log_hash_rate(self, visible): + set_log_hash_rate = { + 'visible': visible, + } + return self.rpc.send_request('/set_log_hash_rate', set_log_hash_rate) + + def stop_daemon(self): + stop_daemon = { + } + return self.rpc.send_request('/stop_daemon', stop_daemon) + + def get_net_stats(self): + get_net_stats = { + } + return self.rpc.send_request('/get_net_stats', get_net_stats) + + def get_limit(self): + get_limit = { + } + return self.rpc.send_request('/get_limit', get_limit) + + def set_limit(self, limit_down, limit_up): + set_limit = { + 'limit_down': limit_down, + 'limit_up': limit_up, + } + return self.rpc.send_request('/set_limit', set_limit) + + def out_peers(self, out_peers): + out_peers = { + 'out_peers': out_peers, + } + return self.rpc.send_request('/out_peers', out_peers) + + def in_peers(self, in_peers): + in_peers = { + 'in_peers': in_peers, + } + return self.rpc.send_request('/in_peers', in_peers) + + def update(self, command, path = None): + update = { + 'command': command, + 'path': path, + } + return self.rpc.send_request('/update', update) + + def get_block_count(self): + get_block_count = { + 'method': 'get_block_count', + 'params': { + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_json_rpc_request(get_block_count) + getblockcount = get_block_count + + def get_block_hash(self, height): + get_block_hash = { + 'method': 'get_block_hash', + 'params': [height], + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_json_rpc_request(get_block_hash) + on_get_block_hash = get_block_hash + on_getblockhash = get_block_hash + + def relay_tx(self, txids = []): + relay_tx = { + 'method': 'relay_tx', + 'params': { + 'txids': txids, + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_json_rpc_request(relay_tx) + + def sync_info(self): + sync_info = { + 'method': 'sync_info', + 'params': { + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_json_rpc_request(sync_info) + + def get_txpool_backlog(self): + get_txpool_backlog = { + 'method': 'get_txpool_backlog', + 'params': { + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_json_rpc_request(get_txpool_backlog) + + def prune_blockchain(self, check = False): + prune_blockchain = { + 'method': 'prune_blockchain', + 'params': { + 'check': check, + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_json_rpc_request(prune_blockchain) + + def get_block_rate(self, seconds = [3600]): + get_block_rate = { + 'method': 'get_block_rate', + 'params': { + 'seconds': seconds, + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_json_rpc_request(get_block_rate) diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py index afc335f9b..6a3fabdc9 100644 --- a/utils/python-rpc/framework/wallet.py +++ b/utils/python-rpc/framework/wallet.py @@ -152,6 +152,7 @@ class Wallet(object): 'id': '0' } return self.rpc.send_json_rpc_request(get_balance) + getbalance = get_balance def sweep_dust(self, get_tx_keys = True, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False): sweep_dust = { @@ -166,6 +167,7 @@ class Wallet(object): 'id': '0' } return self.rpc.send_json_rpc_request(sweep_dust) + sweep_unmixable = sweep_dust def sweep_all(self, address = '', account_index = 0, subaddr_indices = [], priority = 0, ring_size = 0, outputs = 1, unlock_time = 0, payment_id = '', get_tx_keys = False, below_amount = 0, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False): sweep_all = { @@ -222,6 +224,7 @@ class Wallet(object): 'id': '0' } return self.rpc.send_json_rpc_request(get_address) + getaddress = get_address def create_account(self, label = ""): create_account = { @@ -733,6 +736,7 @@ class Wallet(object): 'id': '0' } return self.rpc.send_json_rpc_request(get_height) + getheight = get_height def relay_tx(self, hex_): relay_tx = { -- cgit v1.2.3