Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions contrib/epee/include/storages/portable_storage_from_bin.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ namespace epee
case SERIALIZE_TYPE_OBJECT: return read_ae<section>();
case SERIALIZE_TYPE_ARRAY: return read_ae<array_entry>();
default:
CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << type);
CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << static_cast<int>(type));
}
return read_ae<int8_t>(); // unreachable, dummy return to avoid compiler warning
}
Expand Down Expand Up @@ -321,7 +321,7 @@ namespace epee
case SERIALIZE_TYPE_OBJECT: return read_se<section>();
case SERIALIZE_TYPE_ARRAY: return read_se<array_entry>();
default:
CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << ent_type);
CHECK_AND_ASSERT_THROW_MES(false, "unknown entry_type code = " << static_cast<int>(ent_type));
}
return read_se<int8_t>(); // unreachable, dummy return to avoid compiler warning
}
Expand Down
77 changes: 77 additions & 0 deletions tests/functional_tests/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@
"""

from framework.daemon import Daemon
from framework.wallet import Wallet

class BlockchainTest():
def run_test(self):
self.reset()
self._test_generateblocks(5)
self._test_alt_chains()
self.test_get_blocks_fast()

def reset(self):
print('Resetting blockchain')
Expand Down Expand Up @@ -340,6 +342,81 @@ def _test_alt_chains(self):
print('Saving blockchain explicitely')
daemon.save_bc()

def test_get_blocks_fast(self):
print('Testing the /get_blocks.bin RPC endpoint')

daemon = Daemon()

n_blocks = daemon.get_height()['height']
assert(n_blocks >= 3)

genesis_block_id = daemon.getblockheaderbyheight(0)['block_header']['hash']

target_block_index = n_blocks-1
target_block_id = daemon.getblockheaderbyheight(target_block_index)['block_header']['hash']

print('First, mining to wallet and creating 2 transactions in the top block')

wallet = Wallet()
seed = 'velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted'
main_address = '42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm'

try: wallet.close_wallet()
except: pass
wallet.auto_refresh(enable = False)
wallet.restore_deterministic_wallet(seed)
assert wallet.get_transfers() == {}
assert wallet.get_address().address == main_address

wallet.refresh()
res = wallet.get_transfers()
assert len(res['in']) > 0
first_recv_height = res['in'][0]['height']

N_TO_MINE = 8 + max(0, first_recv_height + 60 - n_blocks)
daemon.generateblocks(main_address, N_TO_MINE)
wallet.refresh()

dst = {'address': '8BQKgTSSqJjP14AKnZUBwnXWj46MuNmLvHfPTpmry52DbfNjjHVvHUk4mczU8nj8yZ57zBhksTJ8kM5xKeJXw55kCMVqyG7', 'amount': 1000000000000}

res = wallet.get_transfers()
assert len(res['in']) >= N_TO_MINE
last_recv_height = max(x['height'] for x in res['in'])
assert last_recv_height == n_blocks + N_TO_MINE - 1, last_recv_height
assert wallet.get_balance().unlocked_balance > dst['amount'] * 2

res = wallet.transfer([dst])
balance_1 = wallet.get_balance().unlocked_balance
res = wallet.transfer([dst])

assert len(daemon.get_transaction_pool_hashes()['tx_hashes']) == 2

daemon.generateblocks(main_address, 1)

print('Calling /get_blocks.bin and testing response...')

res = daemon.get_blocks_fast(0, [target_block_id, genesis_block_id])
assert len(res.blocks) == N_TO_MINE + 1 + 1
assert len(res.blocks) == len(res.output_indices)

for i in range(len(res.blocks)):
is_last = i == len(res.blocks) - 1
block = res.blocks[i]
assert block.pruned
block_indices = res.output_indices[i]['indices']
n_txs = len(block['txs']) if 'txs' in block else 0
if is_last:
assert n_txs == 2
assert len(block_indices) == 3
else:
assert n_txs == 0
assert len(block_indices) == 1
for tx_idx in range(n_txs):
tx = block.txs[tx_idx]
tx_indices = block_indices[1 + tx_idx]['indices']
assert tx.prunable_hash != (b'\0' * 32) # non-null
assert len(tx_indices) == 2


if __name__ == '__main__':
BlockchainTest().run_test()
25 changes: 25 additions & 0 deletions utils/python-rpc/framework/daemon.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,17 @@

"""Daemon class to make rpc calls and store state."""

from . import epee_binary
from .rpc import JSONRPC

class DaemonBinary:
def hash_list_to_blob(hash_list):
blob = bytes()
for h in hash_list:
assert len(h) == 64
blob += bytes.fromhex(h)
return blob

class Daemon(object):

def __init__(self, protocol='http', host='127.0.0.1', port=0, idx=0, restricted_rpc = False, username=None, password=None):
Expand Down Expand Up @@ -179,6 +188,22 @@ def getblockheadersrange(self, start_height, end_height, fill_pow_hash = False,
return self.rpc.send_json_rpc_request(getblockheadersrange)
get_block_headers_range = getblockheadersrange

def get_blocks_fast(self, start_height, block_ids, requested_info = 0,
pool_info_since = 0, prune = True, no_miner_tx = False, max_block_count = 0):
get_blocks_fast = {
'requested_info': requested_info,
'block_ids': DaemonBinary.hash_list_to_blob(block_ids),
'start_height': start_height,
'prune': prune,
'no_miner_tx': no_miner_tx,
'pool_info_since': pool_info_since,
'max_block_count': max_block_count
}
res = self.rpc.send_binary_request("/getblocks.bin", get_blocks_fast)
if 'top_block_hash' in res:
res['top_block_hash'] = res['top_block_hash'].hex()
return res

def get_connections(self, client = ""):
get_connections = {
'client': client,
Expand Down
Loading
Loading