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)}'
Пример #2
0
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)