Module agora.consensus.pool.Enrollment

Contains supporting code for managing enrollments registered by nodes on the network to be a validator, which means the enrollment information needs to be confirmed on the consensus protocol to be a validator. The information is stored in a table of SQLite.

Example

test for function of EnrollmentPool

import agora.consensus.PreImage;
import agora.consensus.data.Params;
import agora.consensus.data.Transaction;
import agora.consensus.EnrollmentManager;
import std.algorithm;

auto params = new immutable(ConsensusParams)();
scope storage = new MemoryUTXOSet;
scope pool = new EnrollmentPool(new ManagedDatabase(":memory:"));
KeyPair key_pair = WK.Keys.A;
Enrollment[] enrollments;
Height avail_height;

bool findEnrollment (in Hash, out EnrollmentState) @trusted nothrow
{
    return false;
}

Amount getPenaltyDeposit (Hash) @trusted nothrow
{
    return 10_000.coins;
}

genesisSpendable().map!(txb => txb.refund(key_pair.address).sign(OutputType.Freeze))
    .each!(tx => storage.put(tx));

// Add enrollments
Hash[] utxo_hashes = storage.keys;
foreach (index; 0 .. 3)
{
    auto utxo_hash = utxo_hashes[index];
    avail_height = Height(params.ValidatorCycle);
    enrollments ~= EnrollmentManager.makeEnrollment(utxo_hash, key_pair, avail_height, params.ValidatorCycle);
    assert(pool.add(enrollments[$ - 1], avail_height,
                            storage.getUTXOFinder(), &findEnrollment, &getPenaltyDeposit));
    assert(pool.count() == index + 1);
    assert(pool.hasEnrollment(utxo_hash, avail_height));
    assert(!pool.add(enrollments[$ - 1], avail_height,
                            storage.getUTXOFinder(), &findEnrollment, &getPenaltyDeposit));
}

// check if enrolled heights are not set
Enrollment[] enrolls = pool.getEnrollments(avail_height);
assert(enrolls.length == 3);
assert(enrolls.isStrictlyMonotonic!("a.utxo_key < b.utxo_key"));

// get a specific enrollment object
Enrollment stored_enroll;
assert((stored_enroll = pool.getEnrollment(utxo_hashes[1],
    Height(avail_height + 1))) == Enrollment.init);
assert((stored_enroll = pool.getEnrollment(utxo_hashes[1],
    Height(avail_height - 1))) == Enrollment.init);
assert((stored_enroll = pool.getEnrollment(utxo_hashes[1],
    avail_height)) == enrollments[1]);
assert((stored_enroll = pool.getEnrollment(utxo_hashes[1])) !=
    Enrollment.init);
assert(stored_enroll == enrollments[1]);

// remove an enrollment
pool.remove(utxo_hashes[1]);
assert(pool.count() == 2);
assert(pool.getEnrollment(utxo_hashes[1]) == Enrollment.init);

// test for enrollment block height update
enrolls = pool.getEnrollments(avail_height);
assert(enrolls.length == 2);

avail_height = Height(params.ValidatorCycle);
assert(pool.hasEnrollment(utxo_hashes[0], avail_height));
avail_height = Height(params.ValidatorCycle * 2);
assert(!pool.hasEnrollment(utxo_hashes[0], avail_height));
pool.remove(utxo_hashes[0]);
assert(!pool.hasEnrollment(utxo_hashes[0], avail_height));
pool.remove(utxo_hashes[1]);
pool.remove(utxo_hashes[2]);
assert(pool.getEnrollments(avail_height).length == 0);

// Reverse ordering
Enrollment[] ordered_enrollments = enrollments.dup;
ordered_enrollments.sort!("a.utxo_key > b.utxo_key");
foreach (ordered_enroll; ordered_enrollments)
    assert(pool.add(ordered_enroll, Height(params.ValidatorCycle),
                    &storage.peekUTXO, &findEnrollment, &getPenaltyDeposit));
enrolls = pool.getEnrollments(Height(params.ValidatorCycle));
assert(enrolls.length == 3);
assert(enrolls.isStrictlyMonotonic!("a.utxo_key < b.utxo_key"));

Classes

NameDescription
EnrollmentPool