def check_transaction_outcome_proof(nodes, should_succeed, nonce): status = nodes[1].get_status() latest_block_hash = status['sync_info']['latest_block_hash'] function_caller_key = nodes[0].signer_key gas = 300000000000000 if should_succeed else 1000 function_call_1_tx = transaction.sign_function_call_tx( function_caller_key, nodes[0].signer_key.account_id, 'write_key_value', struct.pack('<QQ', 42, 10), gas, 100000000000, nonce, base58.b58decode(latest_block_hash.encode('utf8'))) function_call_result = nodes[1].send_tx_and_wait(function_call_1_tx, 15) assert 'error' not in function_call_result status = nodes[0].get_status() latest_block_height = status['sync_info']['latest_block_height'] # wait for finalization light_client_request_block_hash = None while True: status = nodes[0].get_status() cur_height = status['sync_info']['latest_block_height'] if cur_height > latest_block_height + 2 and light_client_request_block_hash is None: light_client_request_block_hash = status['sync_info'][ 'latest_block_hash'] if cur_height > latest_block_height + 7: break time.sleep(1) light_client_block = nodes[0].json_rpc( 'next_light_client_block', [light_client_request_block_hash])['result'] light_client_block_hash = compute_block_hash( light_client_block['inner_lite'], light_client_block['inner_rest_hash'], light_client_block['prev_block_hash']).decode('utf-8') queries = [{ "type": "transaction", "transaction_hash": function_call_result['result']['transaction_outcome']['id'], "sender_id": "test0", "light_client_head": light_client_block_hash }] outcomes = [ (function_call_result['result']['transaction_outcome']['outcome'], function_call_result['result']['transaction_outcome']['id']) ] for receipt_outcome in function_call_result['result']['receipts_outcome']: outcomes.append((receipt_outcome['outcome'], receipt_outcome['id'])) queries.append({ "type": "receipt", "receipt_id": receipt_outcome['id'], "receiver_id": "test0", "light_client_head": light_client_block_hash }) for query, (outcome, id) in zip(queries, outcomes): res = nodes[0].json_rpc('light_client_proof', query, timeout=10) assert 'error' not in res, res light_client_proof = res['result'] # check that execution outcome root proof is valid execution_outcome_hash = hashlib.sha256( serialize_execution_outcome_with_id(outcome, id)).digest() outcome_root = compute_merkle_root_from_path( light_client_proof['outcome_proof']['proof'], execution_outcome_hash) block_outcome_root = compute_merkle_root_from_path( light_client_proof['outcome_root_proof'], hashlib.sha256(outcome_root).digest()) block = nodes[0].json_rpc( 'block', {"block_id": light_client_proof['outcome_proof']['block_hash']}) expected_root = block['result']['header']['outcome_root'] assert base58.b58decode( expected_root ) == block_outcome_root, f'expected outcome root {expected_root} actual {base58.b58encode(block_outcome_root)}' # check that the light block header is valid block_header_lite = light_client_proof['block_header_lite'] computed_block_hash = compute_block_hash( block_header_lite['inner_lite'], block_header_lite['inner_rest_hash'], block_header_lite['prev_block_hash']) assert light_client_proof['outcome_proof'][ 'block_hash'] == computed_block_hash.decode( 'utf-8' ), f'expected block hash {light_client_proof["outcome_proof"]["block_hash"]} actual {computed_block_hash}' # check that block proof is valid block_merkle_root = compute_merkle_root_from_path( light_client_proof['block_proof'], light_client_proof['outcome_proof']['block_hash']) assert base58.b58decode( light_client_block['inner_lite']['block_merkle_root'] ) == block_merkle_root, f'expected block merkle root {light_client_block["inner_lite"]["block_merkle_root"]} actual {base58.b58encode(block_merkle_root)}'
while True: assert time.time() - started < TIMEOUT res = get_light_client_block(last_known_block_hash, last_known_block) if last_known_block_hash == height_to_hash[20 + first_epoch_switch_height]: assert res['result'] is None break assert res['result']['inner_lite']['epoch_id'] == epochs[iter_] print(iter_, heights[iter_]) assert res['result']['inner_lite']['height'] == heights[iter_], ( res['result']['inner_lite'], first_epoch_switch_height) last_known_block_hash = compute_block_hash( res['result']['inner_lite'], res['result']['inner_rest_hash'], res['result']['prev_block_hash']).decode('ascii') assert last_known_block_hash == height_to_hash[ res['result']['inner_lite']['height']], "%s != %s" % ( last_known_block_hash, height_to_hash[res['result']['inner_lite']['height']]) if last_known_block is None: block_producers_map[res['result']['inner_lite'] ['next_epoch_id']] = res['result']['next_bps'] last_known_block = res['result'] iter_ += 1 res = get_light_client_block(height_to_hash[19 + first_epoch_switch_height], last_known_block)