Пример #1
0
def test_calc_batches_takes_prepared_only(builder):
    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=0,
                    digest=cp_digest(0, 0))
    vc = ViewChange(viewNo=0,
                    stableCheckpoint=0,
                    prepared=[],
                    preprepared=[(0, 1, "digest1"), (0, 2, "digest2"),
                                 (0, 3, "digest3"), (0, 4, "digest4")],
                    checkpoints=[cp])

    vcs = [vc, vc, vc, vc]
    assert builder.calc_batches(cp, vcs) == []

    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=0,
                    digest=cp_digest(0, 0))
    vc = ViewChange(viewNo=0,
                    stableCheckpoint=0,
                    prepared=[(0, 1, "digest1"), (0, 2, "digest2")],
                    preprepared=[(0, 1, "digest1"), (0, 2, "digest2"),
                                 (0, 3, "digest3"), (0, 4, "digest4")],
                    checkpoints=[cp])

    vcs = [vc, vc, vc, vc]
    assert builder.calc_batches(
        cp, vcs) == [BatchID(0, 1, "digest1"),
                     BatchID(0, 2, "digest2")]
Пример #2
0
def test_calc_batches_respects_checkpoint(builder):
    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=10,
                    digest=cp_digest(0, 0))
    vc = ViewChange(viewNo=0,
                    stableCheckpoint=0,
                    prepared=[(0, 1, "digest1"), (0, 2, "digest2")],
                    preprepared=[(0, 1, "digest1"), (0, 2, "digest2")],
                    checkpoints=[cp])

    vcs = [vc, vc, vc, vc]
    assert builder.calc_batches(cp, vcs) == []

    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=10,
                    digest=cp_digest(0, 0))
    vc = ViewChange(viewNo=0,
                    stableCheckpoint=0,
                    prepared=[(0, 10, "digest10"), (0, 11, "digest11"),
                              (1, 12, "digest12")],
                    preprepared=[(0, 10, "digest10"), (0, 11, "digest11"),
                                 (1, 12, "digest12")],
                    checkpoints=[cp])

    vcs = [vc, vc, vc, vc]
    assert builder.calc_batches(
        cp, vcs) == [BatchID(0, 11, "digest11"),
                     BatchID(1, 12, "digest12")]
Пример #3
0
def test_calc_batches_must_be_in_pre_prepare(builder):
    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=0,
                    digest=cp_digest(0, 0))
    vc = ViewChange(viewNo=0,
                    stableCheckpoint=0,
                    prepared=[(0, 1, "digest1"), (0, 2, "digest2")],
                    preprepared=[(0, 1, "digest1")],
                    checkpoints=[cp])

    vcs = [vc, vc, vc, vc]
    # all nodes are malicious here since all added (0, 2) into prepared without adding to pre-prepared
    # so, None here means we can not calculate NewView reliably
    assert builder.calc_batches(cp, vcs) is None

    vc1 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1"), (0, 2, "digest2")],
                     preprepared=[(0, 1, "digest1")],
                     checkpoints=[cp])
    vc2 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1")],
                     preprepared=[(0, 1, "digest1")],
                     checkpoints=[cp])

    vcs = [vc1, vc2, vc2, vc2]
    assert builder.calc_batches(cp, vcs) == [BatchID(0, 1, "digest1")]
Пример #4
0
def test_calc_batches_takes_prepared_with_same_batchid_only(builder):
    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=0,
                    digest=cp_digest(0, 0))
    vc1 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(1, 1, "digest1")],
                     preprepared=[(1, 1, "digest1")],
                     checkpoints=[cp])
    vc2 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(1, 1, "digest1")],
                     preprepared=[(1, 1, "digest1")],
                     checkpoints=[cp])
    vc3 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(1, 1, "digest2")],
                     preprepared=[(1, 1, "digest2")],
                     checkpoints=[cp])
    vc4 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[],
                     preprepared=[(1, 1, "digest1")],
                     checkpoints=[cp])

    vcs = [vc1, vc2, vc3, vc4]
    assert builder.calc_batches(cp, vcs) == [BatchID(1, 1, "digest1")]
Пример #5
0
def test_calc_batches_takes_next_view_one_prepared_if_weak_quorum_of_preprepared(
        builder):
    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=0,
                    digest=cp_digest(0, 0))
    vc1 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1"), (1, 2, "digest2")],
                     preprepared=[(0, 1, "digest1"), (1, 2, "digest2")],
                     checkpoints=[cp])
    vc2 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1")],
                     preprepared=[(0, 1, "digest1"), (1, 2, "digest2")],
                     checkpoints=[cp])
    vc3 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1")],
                     preprepared=[(0, 1, "digest1")],
                     checkpoints=[cp])
    vc4 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1")],
                     preprepared=[(0, 1, "digest1")],
                     checkpoints=[cp])

    vcs = [vc1, vc2, vc3, vc4]
    assert builder.calc_batches(
        cp, vcs) == [BatchID(0, 1, "digest1"), (1, 2, "digest2")]
def test_calc_batches_same_data(builder):
    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=0,
                    digest='empty')
    vc = ViewChange(viewNo=0,
                    stableCheckpoint=0,
                    prepared=[(0, 1, "digest1"), (0, 2, "digest2")],
                    preprepared=[(0, 1, "digest1"), (0, 2, "digest2")],
                    checkpoints=[cp])

    vcs = [vc, vc, vc, vc]
    assert builder.calc_batches(
        cp, vcs) == [BatchID(0, 1, "digest1"),
                     BatchID(0, 2, "digest2")]
def test_calc_batches_takes_prepared_if_preprepared_in_next_view(builder):
    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=0,
                    digest='empty')
    vc1 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(1, 1, "digest2")],
                     preprepared=[(0, 1, "digest1"), (2, 1, "digest2")],
                     checkpoints=[cp])
    vc2 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1")],
                     preprepared=[(0, 1, "digest1"), (2, 1, "digest2")],
                     checkpoints=[cp])
    vc3 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1")],
                     preprepared=[(0, 1, "digest1")],
                     checkpoints=[cp])
    vc4 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1")],
                     preprepared=[(0, 1, "digest1")],
                     checkpoints=[cp])

    vcs = [vc1, vc2, vc3, vc4]
    assert builder.calc_batches(cp, vcs) == [BatchID(1, 1, "digest2")]
Пример #8
0
def test_calc_batches_takes_quorum_of_prepared(builder):
    cp = Checkpoint(instId=0,
                    viewNo=0,
                    seqNoStart=0,
                    seqNoEnd=0,
                    digest=cp_digest(0, 0))
    vc1 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest2")],
                     preprepared=[(0, 1, "digest2")],
                     checkpoints=[cp])
    vc2 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[(0, 1, "digest1")],
                     preprepared=[(0, 1, "digest1")],
                     checkpoints=[cp])
    vc3 = ViewChange(viewNo=0,
                     stableCheckpoint=0,
                     prepared=[],
                     preprepared=[(0, 1, "digest1")],
                     checkpoints=[cp])

    vcs = [vc1, vc2, vc2, vc2]
    assert builder.calc_batches(cp, vcs) == [BatchID(0, 1, "digest1")]

    vcs = [vc3, vc2, vc2, vc2]
    assert builder.calc_batches(cp, vcs) == [BatchID(0, 1, "digest1")]

    vcs = [vc3, vc3, vc3, vc3]
    assert builder.calc_batches(cp, vcs) == []

    vcs = [vc1, vc1, vc2, vc2]
    assert builder.calc_batches(cp, vcs) is None

    # since we have enough pre-prepares
    vcs = [vc2, vc3, vc3, vc3]
    assert builder.calc_batches(cp, vcs) == [BatchID(0, 1, "digest1")]
    vcs = [vc2, vc2, vc3, vc3]
    assert builder.calc_batches(cp, vcs) == [BatchID(0, 1, "digest1")]
Пример #9
0
def some_pool(random: SimRandom) -> (SimPool, List):
    pool_size = random.integer(4, 8)
    pool = SimPool(pool_size, random)

    # Create simulated history
    # TODO: Move into helper?
    faulty = (pool_size - 1) // 3
    seq_no_per_cp = 10
    max_batches = 50
    batches = [BatchID(0, n, random.string(40)) for n in range(1, max_batches)]
    checkpoints = [
        some_checkpoint(random, 0, n)
        for n in range(0, max_batches, seq_no_per_cp)
    ]

    # Preprepares
    pp_count = [random.integer(0, len(batches)) for _ in range(pool_size)]
    max_pp = sorted(pp_count)[faulty]
    # Prepares
    p_count = [random.integer(0, min(max_pp, pp)) for pp in pp_count]
    max_p = sorted(p_count)[faulty]
    # Checkpoints
    cp_count = [
        1 + random.integer(0, min(max_p, p)) // seq_no_per_cp for p in pp_count
    ]
    max_stable_cp_indx = sorted(cp_count)[faulty] - 1
    stable_cp = [
        checkpoints[random.integer(0, min(max_stable_cp_indx, cp))].seqNoEnd
        for cp in cp_count
    ]

    # Initialize consensus data
    for i, node in enumerate(pool.nodes):
        node._data.preprepared = batches[:pp_count[i]]
        node._data.prepared = batches[:p_count[i]]
        node._data.checkpoints = checkpoints[:cp_count[i]]
        node._data.stable_checkpoint = stable_cp[i]

    committed = []
    for i in range(1, max_batches):
        prepare_count = sum(1 for node in pool.nodes
                            if i <= len(node._data.prepared))
        has_prepared_cert = prepare_count >= pool_size - faulty
        if has_prepared_cert:
            committed.append(batches[i - 1])

    return pool, committed
Пример #10
0
def calc_committed(view_changes):
    committed = []
    for pp_seq_no in range(1, 50):
        batch_id = None
        for vc in view_changes:
            # pp_seq_no must be present in all PrePrepares
            for pp in vc.preprepared:
                if pp[1] == pp_seq_no:
                    if batch_id is None:
                        batch_id = pp
                    assert batch_id == pp
                    break

            # pp_seq_no must be present in all Prepares
            if batch_id not in vc.prepared:
                return committed
        committed.append(BatchID(*batch_id))
    return committed
Пример #11
0
def calc_committed(view_changes, max_pp_seq_no, n, f) -> List[BatchID]:
    def check_in_batch(batch_id, some_batch_id, check_view_no=False):
        if check_view_no and (batch_id[0] != some_batch_id[0]):
            return False
        return batch_id[1] == some_batch_id[1] and batch_id[
            2] == some_batch_id[2]

    def check_prepared_in_vc(vc, batch_id):
        # check that (pp_seq_no, digest) is present in VC's prepared and preprepared
        for p_batch_id in vc.prepared:
            if not check_in_batch(batch_id, p_batch_id, check_view_no=True):
                continue
            for pp_batch_id in vc.preprepared:
                if check_in_batch(batch_id, pp_batch_id, check_view_no=True):
                    return True

        return False

    def find_batch_id(pp_seq_no):
        for vc in view_changes:
            for batch_id in vc.prepared:
                if batch_id[1] != pp_seq_no:
                    continue
                prepared_count = sum(1 for vc in view_changes
                                     if check_prepared_in_vc(vc, batch_id))
                if prepared_count < n - f:
                    continue
                return batch_id
        return None

    committed = []
    for pp_seq_no in range(1, max_pp_seq_no):
        batch_id = find_batch_id(pp_seq_no)
        if batch_id is not None:
            committed.append(BatchID(*batch_id))

    return committed