def test_transfer_funds(self): """Tests the transfer funds to another wallet""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) with ExonumCryptoAdvancedClient(client) as crypto_client: alice_keys = KeyPair.generate() bob_keys = KeyPair.generate() with client.create_subscriber("transactions") as subscriber: crypto_client.create_wallet(alice_keys, "Alice" + str(validator_id)) subscriber.wait_for_new_event() crypto_client.create_wallet(bob_keys, "Bob" + str(validator_id)) subscriber.wait_for_new_event() crypto_client.transfer(20, alice_keys, bob_keys.public_key.value) subscriber.wait_for_new_event() alice_wallet = crypto_client.get_wallet_info( alice_keys).json() alice_balance = alice_wallet["wallet_proof"]["to_wallet"][ "entries"][0]["value"]["balance"] bob_wallet = crypto_client.get_wallet_info(bob_keys).json() bob_balance = bob_wallet["wallet_proof"]["to_wallet"][ "entries"][0]["value"]["balance"] self.assertEqual(alice_balance, 80) self.assertEqual(bob_balance, 120)
def test_transfer_funds(self): """Tests the transfer funds to another wallet""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) with ExonumCryptoAdvancedClient(client) as crypto_client: alice_keys = KeyPair.generate() crypto_client.create_wallet(alice_keys, "Alice" + str(validator_id)) bob_keys = KeyPair.generate() crypto_client.create_wallet(bob_keys, "Bob" + str(validator_id)) with client.create_subscriber("blocks") as subscriber: subscriber.wait_for_new_event() # TODO: Sometimes it fails without time.sleep() [ECR-3876] time.sleep(2) crypto_client.transfer(20, alice_keys, bob_keys.public_key.value) subscriber.wait_for_new_event() # TODO: Sometimes it fails without time.sleep() [ECR-3876] time.sleep(2) alice_balance = (crypto_client.get_wallet_info( alice_keys).json()['wallet_proof']['to_wallet'] ['entries'][0]['value']['balance']) bob_balance = (crypto_client.get_wallet_info( bob_keys).json()['wallet_proof']['to_wallet'] ['entries'][0]['value']['balance']) self.assertEqual(alice_balance, 80) self.assertEqual(bob_balance, 120)
def test_transfer_funds_insufficient(self): """Tests the transfer insufficient amount of funds is failed""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) with ExonumCryptoAdvancedClient(client) as crypto_client: alice_keys = KeyPair.generate() crypto_client.create_wallet(alice_keys, "Alice" + str(validator_id)) bob_keys = KeyPair.generate() crypto_client.create_wallet(bob_keys, "Bob" + str(validator_id)) with client.create_subscriber("blocks") as subscriber: subscriber.wait_for_new_event() tx_response = crypto_client.transfer( 110, alice_keys, bob_keys.public_key.value) subscriber.wait_for_new_event() tx_status = client.get_tx_info( tx_response.json()['tx_hash']).json()['status']['type'] self.assertEqual(tx_status, 'service_error') alice_balance = (crypto_client.get_wallet_info( alice_keys).json()['wallet_proof']['to_wallet'] ['entries'][0]['value']['balance']) bob_balance = (crypto_client.get_wallet_info( bob_keys).json()['wallet_proof']['to_wallet'] ['entries'][0]['value']['balance']) self.assertEqual(alice_balance, 100) self.assertEqual(bob_balance, 100)
def test_transfer_funds_insufficient(self): """Tests the transfer insufficient amount of funds is failed""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) with ExonumCryptoAdvancedClient(client) as crypto_client: alice_keys = KeyPair.generate() crypto_client.create_wallet(alice_keys, "Alice" + str(validator_id)) bob_keys = KeyPair.generate() crypto_client.create_wallet(bob_keys, "Bob" + str(validator_id)) with client.create_subscriber("blocks") as subscriber: subscriber.wait_for_new_event() tx_response = crypto_client.transfer( 110, alice_keys, bob_keys.public_key) subscriber.wait_for_new_event() tx_info = client.public_api.get_tx_info( tx_response.json()["tx_hash"]).json() tx_status = tx_info["status"]["type"] self.assertEqual(tx_status, "service_error") alice_balance = crypto_client.get_balance(alice_keys) bob_balance = crypto_client.get_balance(bob_keys) self.assertEqual(alice_balance, 100) self.assertEqual(bob_balance, 100)
def transfer( client: ExonumClient, message_generator: MessageGenerator, from_keypair: KeyPair, to_key: PublicKey, amount: int ) -> Tuple[int, int]: """This example transfers tokens from one wallet to the other one and returns the balances of these wallets.""" cryptocurrency_module = ModuleManager.import_service_module(CRYPTOCURRENCY_ARTIFACT_NAME, "service") # Note that since we are using the Cryptocurrency module, # we need to load helpers from this module and not from the main module: helpers_module = ModuleManager.import_service_module(CRYPTOCURRENCY_ARTIFACT_NAME, "helpers") transfer_message = cryptocurrency_module.Transfer() transfer_message.to.CopyFrom(helpers_module.PublicKey(data=to_key.value)) transfer_message.amount = amount transfer_message.seed = Seed.get_seed() transfer_tx = message_generator.create_message(transfer_message) transfer_tx.sign(from_keypair) response = client.send_transaction(transfer_tx) ensure_status_code(response) tx_hash = response.json()["tx_hash"] # Wait for new blocks: with client.create_subscriber() as subscriber: subscriber.wait_for_new_block() subscriber.wait_for_new_block() ensure_transaction_success(client, tx_hash) from_balance = get_balance(client, from_keypair.public_key) to_balance = get_balance(client, to_key) return from_balance, to_balance
def run() -> None: """Example of downloading the Protobuf sources and using the compiled module.""" client = ExonumClient(hostname="127.0.0.1", public_api_port=8080, private_api_port=8081) # Create ProtobufLoader via context manager (so that we will not have to # initialize/deinitialize it manually): with client.protobuf_loader() as loader: # Load core proto files: loader.load_main_proto_files() # Load proto files for the Exonum supervisor service: loader.load_service_proto_files(RUST_RUNTIME_ID, "exonum-supervisor:0.12.0") # Load the main module (runtime.proto): main_module = ModuleManager.import_main_module("runtime") # Create a Protobuf message object: artifact_id = main_module.ArtifactId() artifact_id.runtime_id = RUST_RUNTIME_ID artifact_id.name = "some_service:0.1.0" # Working with Protobuf objects, you have to follow Protobuf Python API # conventions. See Protobuf Python API docs for details: instance_spec = main_module.InstanceSpec() instance_spec.artifact.CopyFrom(artifact_id) # Load the service module (service.proto from the supervisor service): service_module = ModuleManager.import_service_module("exonum-supervisor:0.12.0", "service") # Workflow is the same as for the main modules: _deploy_request = service_module.DeployRequest()
def create_wallet(client: ExonumClient, message_generator: MessageGenerator, name: str) -> KeyPair: """Creates a wallet with the given name and returns a KeyPair for it.""" key_pair = KeyPair.generate() # Load the "service.proto" from the Cryptocurrency service: cryptocurrency_module = ModuleManager.import_service_module( CRYPTOCURRENCY_ARTIFACT_NAME, "service") # Create a Protobuf message: create_wallet_message = cryptocurrency_module.TxCreateWallet() create_wallet_message.name = name # Convert the Protobuf message to an Exonum message and sign it: create_wallet_tx = message_generator.create_message(create_wallet_message) create_wallet_tx.sign(key_pair) # Send the transaction to Exonum: response = client.send_transaction(create_wallet_tx) ensure_status_code(response) tx_hash = response.json()["tx_hash"] # Wait for new blocks: with client.create_subscriber() as subscriber: subscriber.wait_for_new_block() subscriber.wait_for_new_block() ensure_transaction_success(client, tx_hash) print(f"Successfully created wallet with name '{name}'") return key_pair
def test_user_agent(self): """Tests the `user_agent` endpoint.""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) user_agent_response = client.user_agent() self.assertEqual(user_agent_response.status_code, 200)
def test_get_blocks_with_time(self): """Tests the `blocks` endpoint. Check response for blocks with time""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) blocks_response = client.get_blocks(count=1, add_blocks_time=True) self.assertEqual(blocks_response.status_code, 200) self.assertIsNotNone(blocks_response.json()['blocks'][0]['time'])
def test_nonexistent_block(self): """Tests the `block` endpoint. Check response for nonexistent block""" nonexistent_height = 999 for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) block_response = client.get_block(nonexistent_height) self.assertEqual(block_response.status_code, 404)
def test_zero_block(self): """Tests the `block` endpoint. Check response for 0 block""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) block_response = client.get_block(0) self.assertEqual(block_response.status_code, 200) self.assertEqual(block_response.json()['height'], 0)
def test_get_only_non_empty_blocks(self): """Tests the `blocks` endpoint. Check response for only non empty blocks""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) blocks_response = client.get_blocks(count=5, skip_empty_blocks=True) self.assertEqual(blocks_response.status_code, 200) self.assertEqual(len(blocks_response.json()['blocks']), 0)
def test_deploy_regular_with_consensus_config(self): """Tests the deploy mechanism in regular mode with consensus config.""" pub_configs = self.network._public_configs().split() validator_keys = [] for pub_config in pub_configs: keys = [] with open(pub_config, "r") as file: data = file.read() keys.append(re.search('consensus_key = "(.+?)"', data).group(1)) keys.append(re.search('service_key = "(.+?)"', data).group(1)) validator_keys.append(keys) consensus = { "validator_keys": validator_keys, "first_round_timeout": 3000, "status_timeout": 5000, "peers_timeout": 10000, "txs_block_limit": 5000, "max_message_len": 1048576, "min_propose_timeout": 10, "max_propose_timeout": 200, "propose_timeout_threshold": 500, } instances = {"crypto": {"artifact": "cryptocurrency"}} cryptocurrency_advanced_config_dict = generate_config( self.network, consensus=consensus, instances=instances ) cryptocurrency_advanced_config = Configuration( cryptocurrency_advanced_config_dict ) with Launcher(cryptocurrency_advanced_config) as launcher: explorer = launcher.explorer() launcher.deploy_all() launcher.wait_for_deploy() launcher.start_all() launcher.wait_for_start() for artifact in launcher.launch_state.completed_deployments(): deployed = explorer.check_deployed(artifact) self.assertEqual(deployed, True) self.assertEqual(len(launcher.launch_state.completed_configs()), 1) for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address(validator_id) client = ExonumClient(host, public_port, private_port) supervisor_api = client.service_apis("supervisor") consensus_config = supervisor_api[0].get_service("consensus-config").json() # check that initial config has been applied self.assertEqual(consensus_config["txs_block_limit"], 5000)
def test_zero_initial_stats(self): """Tests the `stats` endpoint. Check initial stats values""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) stats = client.stats() self.assertEqual(stats.status_code, 200) self.assertEqual(stats.json()['tx_count'], 0) self.assertEqual(stats.json()['tx_pool_size'], 0) self.assertEqual(stats.json()['tx_cache_size'], 0)
def test_get_unknown_transaction(self): """Tests the `transactions` endpoint. Check response for unknown transaction""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) tx_response = client.get_tx_info( "b2d09e1bddca851bee8faf8ffdcfc18cb87fbde167a29bd049fa2eee4a82c1ca" ) self.assertEqual(tx_response.status_code, 404) self.assertEqual(tx_response.json()['type'], "unknown")
def test_get_n_latest_blocks_negative(self): """Tests the `blocks` endpoint. Check response for N latest blocks if latest exceeds current height""" latest = 999 number_of_blocks = 6 for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) blocks_response = client.get_blocks(count=number_of_blocks, latest=latest) self.assertEqual(blocks_response.status_code, 404)
def test_get_blocks_with_precommits(self): """Tests the `blocks` endpoint. Check response for blocks with precommits""" time.sleep(2) for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) blocks_response = client.get_blocks(count=1, add_precommits=True) self.assertEqual(blocks_response.status_code, 200) self.assertEqual( len(blocks_response.json()['blocks'][0]['precommits']), 3)
def test_get_last_n_blocks(self): """Tests the `blocks` endpoint. Check response for last N blocks""" number_of_blocks = 5 time.sleep(5) for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) blocks_response = client.get_blocks(count=number_of_blocks) self.assertEqual(blocks_response.status_code, 200) self.assertEqual(len(blocks_response.json()['blocks']), number_of_blocks)
def test_health_check(self): """Tests the `healthcheck` endpoint.""" time.sleep(10) for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) health_info_response = client.health_info() self.assertEqual(health_info_response.status_code, 200) self.assertEqual(health_info_response.json()['connected_peers'], self.network.validators_count() - 1) self.assertEqual(health_info_response.json()['consensus_status'], 'Active')
def test_freeze_service(self): host, public_port, private_port = self.network.api_address(0) client = ExonumClient(host, public_port, private_port) # Create wallet alice_keys = KeyPair.generate() with ExonumCryptoAdvancedClient(client) as crypto_client: crypto_client.create_wallet(alice_keys, "Alice") with client.create_subscriber("transactions") as subscriber: subscriber.wait_for_new_event() alice_balance = crypto_client.get_balance(alice_keys) self.assertEqual(alice_balance, 100) # Freeze the service instances = { "crypto": { "artifact": "cryptocurrency", "action": "freeze" } } cryptocurrency_advanced_config_dict = generate_config( self.network, instances=instances, artifact_action="none") cryptocurrency_advanced_config = Configuration( cryptocurrency_advanced_config_dict) with Launcher(cryptocurrency_advanced_config) as launcher: launcher.deploy_all() launcher.wait_for_deploy() launcher.start_all() launcher.wait_for_start() # Check that the service status has been changed to `frozen`. for service in client.public_api.available_services().json( )["services"]: if service["spec"]["name"] == "crypto": self.assertEqual(service["status"]["type"], "frozen") # Try to create a new wallet. The operation should fail. with ExonumCryptoAdvancedClient(client) as crypto_client: bob_keys = KeyPair.generate() response = crypto_client.create_wallet(bob_keys, "Bob") self.assertEqual(response.status_code, 400) # Because the service is frozen, transaction should be inadmissible. self.assertEqual(response.json()["title"], "Failed to add transaction to memory pool") # Check that we can use service endpoints for data retrieving. Check wallet once again. with ExonumCryptoAdvancedClient(client) as crypto_client: alice_balance = crypto_client.get_balance(alice_keys) self.assertEqual(alice_balance, 100)
def run() -> None: """This example creates two wallets (for Alice and Bob) and performs several transactions between these wallets.""" client = ExonumClient(hostname="127.0.0.1", public_api_port=8080, private_api_port=8081) with client.protobuf_loader() as loader: # Load and compile proto files: loader.load_main_proto_files() loader.load_service_proto_files(RUST_RUNTIME_ID, CRYPTOCURRENCY_ARTIFACT_NAME, CRYPTOCURRENCY_ARTIFACT_VERSION) instance_id = get_cryptocurrency_instance_id(client) cryptocurrency_message_generator = MessageGenerator( instance_id, CRYPTOCURRENCY_ARTIFACT_NAME, CRYPTOCURRENCY_ARTIFACT_VERSION) alice_keypair = create_wallet(client, cryptocurrency_message_generator, "Alice") bob_keypair = create_wallet(client, cryptocurrency_message_generator, "Bob") alice_balance = get_balance(client, alice_keypair.public_key) bob_balance = get_balance(client, bob_keypair.public_key) print("Created the wallets for Alice and Bob. Balance:") print(f" Alice => {alice_balance}") print(f" Bob => {bob_balance}") amount = 10 alice_balance, bob_balance = transfer( client, cryptocurrency_message_generator, alice_keypair, bob_keypair.public_key, amount) print(f"Transferred {amount} tokens from Alice's wallet to Bob's one") print(f" Alice => {alice_balance}") print(f" Bob => {bob_balance}") amount = 25 bob_balance, alice_balance = transfer( client, cryptocurrency_message_generator, bob_keypair, alice_keypair.public_key, amount) print(f"Transferred {amount} tokens from Bob's wallet to Alice's one") print(f" Alice => {alice_balance}") print(f" Bob => {bob_balance}")
def start_service(client: ExonumClient, service_name: str, instance_name: str) -> int: """This function starts the previously deployed service instance.""" # Create a start request: service_module = ModuleManager.import_service_module( "exonum-supervisor:0.12.0", "service") start_request = service_module.StartService() start_request.artifact.runtime_id = 0 # Rust runtime ID. start_request.artifact.name = service_name start_request.name = instance_name start_request.deadline_height = 1000000 # Some big number. # Convert the request from a Protobuf message to bytes: request_bytes = start_request.SerializeToString() # Send the request and wait for Exonum to process it: send_request(client, "start-service", request_bytes) # Ensure that the service is added to the running instances list: available_services = client.available_services().json() if instance_name not in map(lambda x: x["name"], available_services["services"]): raise RuntimeError( f"{instance_name} is not listed in running instances after starting" ) # Service has started. # Return the running instance ID: for instance in available_services["services"]: if instance["name"] == instance_name: return instance["id"] raise RuntimeError("Instance ID was not found")
def test_add_funds_to_nonexistent_wallet(self): """Tests the funds issue is failed if wallet doesn't exist""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) with ExonumCryptoAdvancedClient(client) as crypto_client: alice_keys = KeyPair.generate() tx_response = crypto_client.issue(alice_keys, 100) with client.create_subscriber("transactions") as subscriber: subscriber.wait_for_new_event() tx_info = client.public_api.get_tx_info( tx_response.json()["tx_hash"]).json() tx_status = tx_info["status"]["type"] self.assertEqual(tx_status, "service_error")
def deploy_service(client: ExonumClient, service_name: str) -> None: """This function sends a deploy request for the desired service and waits until it is deployed.""" # Create a deploy request message: service_module = ModuleManager.import_service_module( "exonum-supervisor:0.12.0", "service") deploy_request = service_module.DeployRequest() deploy_request.artifact.runtime_id = 0 # Rust runtime ID. deploy_request.artifact.name = service_name deploy_request.deadline_height = 1000000 # Some big number (we won't have to wait that long, it's just a deadline). # Convert the request from a Protobuf message to bytes: request_bytes = deploy_request.SerializeToString() # Send the request and wait for Exonum to process it: send_request(client, "deploy-artifact", request_bytes) # Ensure that the service is added to the available modules: available_services = client.available_services().json() if service_name not in map(lambda x: x["name"], available_services["artifacts"]): raise RuntimeError( f"{service_name} is not listed in available services after deployment" )
def __init__(self, client: ExonumClient, instance_name: str = "crypto", version: str = "0.2.0"): self.client = client service_name = "exonum-cryptocurrency" self.service_version = version self.instance_name = instance_name self.loader = client.protobuf_loader() self.loader.initialize() self.loader.load_main_proto_files() self.loader.load_service_proto_files(runtime_id=0, artifact_name="exonum-supervisor", artifact_version="1.0.0") self.loader.load_service_proto_files( runtime_id=0, artifact_name=service_name, artifact_version=self.service_version) self.cryptocurrency_module = ModuleManager.import_service_module( service_name, self.service_version, "service") self.types_module = ModuleManager.import_service_module( service_name, self.service_version, "exonum.crypto.types") instance_id = client.public_api.get_instance_id_by_name( self.instance_name) self.msg_generator = MessageGenerator( instance_id=instance_id, artifact_name=service_name, artifact_version=self.service_version)
def __init__(self, client: ExonumClient): self.client = client cryptocurrency_service_name = "exonum-cryptocurrency-advanced" cryptocurrency_service_version = "0.13.0-rc.2" self.loader = client.protobuf_loader() self.loader.initialize() self.loader.load_main_proto_files() self.loader.load_service_proto_files( runtime_id=0, artifact_name="exonum-supervisor", artifact_version="0.13.0-rc.2", ) self.loader.load_service_proto_files( runtime_id=0, artifact_name=cryptocurrency_service_name, artifact_version=cryptocurrency_service_version, ) self.cryptocurrency_module = ModuleManager.import_service_module( cryptocurrency_service_name, cryptocurrency_service_version, "service") self.types_module = ModuleManager.import_service_module( cryptocurrency_service_name, cryptocurrency_service_version, "types") instance_id = client.public_api.get_instance_id_by_name("crypto") self.msg_generator = MessageGenerator( instance_id=instance_id, artifact_name=cryptocurrency_service_name, artifact_version=cryptocurrency_service_version)
def test_token_issue(self): """Tests the token issue""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) with ExonumCryptoAdvancedClient(client) as crypto_client: alice_keys = KeyPair.generate() crypto_client.create_wallet(alice_keys, "Alice" + str(validator_id)) with client.create_subscriber("transactions") as subscriber: subscriber.wait_for_new_event() crypto_client.issue(alice_keys, 100) subscriber.wait_for_new_event() alice_balance = crypto_client.get_balance(alice_keys) self.assertEqual(alice_balance, 200)
def ensure_transaction_success(client: ExonumClient, tx_hash: str) -> None: """Checks that the transaction is committed and the status is success.""" tx_info_response = client.get_tx_info(tx_hash) ensure_status_code(tx_info_response) tx_info = tx_info_response.json() if not (tx_info["type"] == "committed" and tx_info["status"]["type"] == "success"): raise RuntimeError(f"Error occured during transaction execution: {tx_info}")
def test_add_funds_to_nonexistent_wallet(self): """Tests the funds issue is failed if wallet doesn't exist""" for validator_id in range(self.network.validators_count()): host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) with ExonumCryptoAdvancedClient(client) as crypto_client: alice_keys = KeyPair.generate() tx_response = crypto_client.issue(alice_keys, 100) with client.create_subscriber("blocks") as subscriber: subscriber.wait_for_new_event() # TODO: Sometimes it fails without time.sleep() [ECR-3876] time.sleep(2) tx_status = client.get_tx_info( tx_response.json()['tx_hash']).json()['status']['type'] self.assertEqual(tx_status, 'service_error')
def test_get_n_latest_blocks(self): """Tests the `blocks` endpoint. Check response for N latest blocks""" latest = 5 number_of_blocks = 15 time.sleep(5) for validator_id in range(self.network.validators_count()): height_counter = latest host, public_port, private_port = self.network.api_address( validator_id) client = ExonumClient(host, public_port, private_port) blocks_response = client.get_blocks(count=number_of_blocks, latest=latest) self.assertEqual(len(blocks_response.json()['blocks']), latest + 1) for block in blocks_response.json()['blocks']: self.assertEqual(int(block['height']), height_counter) height_counter -= 1