test/specs/generic/consensus/base/blockchain/InterlinkChain.spec.js
describe('Interlink Chain', () => {
// For these tests, use a difficulty block window of 6 to make difficulty adjustment quicker.
const orgDifficultyBlockWindow = Policy.DIFFICULTY_BLOCK_WINDOW;
beforeAll(() => {
Policy.DIFFICULTY_BLOCK_WINDOW = 6;
});
afterAll(() => {
Policy.DIFFICULTY_BLOCK_WINDOW = orgDifficultyBlockWindow;
});
it('is constructed correctly (constant level, constant difficulty)', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// Push 5 blocks with superblock level 0.
let prevHash = GenesisConfig.GENESIS_HASH;
for (let i = 0; i < 5; i++) {
const block = await bc.createBlock({
superblockLevel: 0
});
expect(block.interlink.length).toBe(1);
expect(block.interlink.hashes[0].equals(prevHash)).toBeTruthy();
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
prevHash = block.hash();
}
})().then(done, done.fail);
});
it('is constructed correctly (increasing level, constant difficulty)', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// Push 5 blocks with superblock level 1-5.
let prevHash = GenesisConfig.GENESIS_HASH;
for (let i = 0; i < 5; i++) {
const block = await bc.createBlock({
superblockLevel: i + 1
});
expect(block.interlink.length).toBe(i + 1);
for (let j = 0; j < block.interlink.length; j++) {
expect(block.interlink.hashes[j].equals(prevHash)).toBeTruthy();
}
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
prevHash = block.hash();
}
})().then(done, done.fail);
});
it('is constructed correctly (alternating level, constant difficulty)', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// Push 6 blocks with alternating superblock levels.
const levels = [2, 0, 1, 0, 3, 0];
const interlinks = [[0], [1, 1, 1], [2, 1, 1], [3, 3, 1], [4, 3, 1], [5, 5, 5, 5]];
const hashes = [GenesisConfig.GENESIS_HASH];
for (let i = 0; i < levels.length; i++) {
const block = await bc.createBlock({
superblockLevel: levels[i]
});
hashes.push(block.hash());
const interlink = interlinks[i].map(index => hashes[index]);
expect(block.interlink.length).toBe(interlink.length);
expect(block.interlink.hashes.every((hash, i) => hash.equals(interlink[i]))).toBeTruthy();
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
}
})().then(done, done.fail);
});
it('is constructed correctly (constant level-0, increasing difficulty)', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// Push 8 blocks. The target depth increases between block 3,4 and 7,8.
const interlinks = [[0], [1], [2], [], [4], [5], [6], []];
const hashes = [GenesisConfig.GENESIS_HASH];
for (let i = 0; i < interlinks.length; i++) {
const block = await bc.createBlock({
superblockLevel: 0,
timestamp: GenesisConfig.GENESIS_BLOCK.timestamp + i + 1
});
hashes.push(block.hash());
const interlink = interlinks[i].map(index => hashes[index]);
expect(block.interlink.length).toBe(interlink.length);
expect(block.interlink.hashes.every((hash, i) => hash.equals(interlink[i]))).toBeTruthy();
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
}
})().then(done, done.fail);
});
it('is constructed correctly (constant level-1, increasing difficulty)', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// Push 8 blocks. The target depth increases between block 3,4 and 7,8.
const interlinks = [[0], [1, 1], [2, 2], [3], [4, 4], [5, 5], [6, 6], [7]];
const hashes = [GenesisConfig.GENESIS_HASH];
for (let i = 0; i < interlinks.length; i++) {
const block = await bc.createBlock({
superblockLevel: 1,
timestamp: GenesisConfig.GENESIS_BLOCK.timestamp + i + 1
});
hashes.push(block.hash());
const interlink = interlinks[i].map(index => hashes[index]);
expect(block.interlink.length).toBe(interlink.length);
expect(block.interlink.hashes.every((hash, i) => hash.equals(interlink[i]))).toBeTruthy();
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
}
})().then(done, done.fail);
});
it('is constructed correctly (constant depth-1, increasing difficulty)', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// Push 8 blocks. The target depth increases between block 3,4 and 7,8.
const levels = [1, 1, 1, 0, 0, 0, 0, 0];
const interlinks = [[0], [1, 1], [2, 2], [3], [4], [5], [6], []];
const hashes = [GenesisConfig.GENESIS_HASH];
for (let i = 0; i < interlinks.length; i++) {
const block = await bc.createBlock({
superblockLevel: levels[i],
timestamp: GenesisConfig.GENESIS_BLOCK.timestamp + i + 1
});
hashes.push(block.hash());
const interlink = interlinks[i].map(index => hashes[index]);
expect(block.interlink.length).toBe(interlink.length);
expect(block.interlink.hashes.every((hash, i) => hash.equals(interlink[i]))).toBeTruthy();
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
}
})().then(done, done.fail);
});
it('is constructed correctly (constant depth-2, increasing difficulty)', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// Push 8 blocks. The target depth increases between block 3,4 and 7,8.
const levels = [2, 2, 2, 1, 1, 1, 1, 0];
const interlinks = [[0], [1, 1, 1], [2, 2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7]];
const hashes = [GenesisConfig.GENESIS_HASH];
for (let i = 0; i < interlinks.length; i++) {
const block = await bc.createBlock({
superblockLevel: levels[i],
timestamp: GenesisConfig.GENESIS_BLOCK.timestamp + i + 1
});
hashes.push(block.hash());
const interlink = interlinks[i].map(index => hashes[index]);
expect(block.interlink.length).toBe(interlink.length);
expect(block.interlink.hashes.every((hash, i) => hash.equals(interlink[i]))).toBeTruthy();
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
}
})().then(done, done.fail);
});
it('is constructed correctly (alternating depth, increasing difficulty)', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// Push 8 blocks. The target depth increases between block 3,4 and 7,8.
const levels = [2, 0, 1, 0, 2, 0, 1, 0];
const interlinks = [[0], [1, 1, 1], [2, 1, 1], [3, 1], [4, 1], [5, 5, 5], [6, 5, 5], [7, 5]];
const hashes = [GenesisConfig.GENESIS_HASH];
for (let i = 0; i < interlinks.length; i++) {
const block = await bc.createBlock({
superblockLevel: levels[i],
timestamp: GenesisConfig.GENESIS_BLOCK.timestamp + i + 1
});
hashes.push(block.hash());
const interlink = interlinks[i].map(index => hashes[index]);
expect(block.interlink.length).toBe(interlink.length);
expect(block.interlink.hashes.every((hash, i) => hash.equals(interlink[i]))).toBeTruthy();
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
}
})().then(done, done.fail);
});
it('is constructed correctly (alternating depth, increasing difficulty) [2]', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// Push 8 blocks. The target depth increases between block 3,4 and 7,8.
const levels = [2, 1, 0, 0, 2, 1, 0, 0];
const interlinks = [[0], [1, 1, 1], [2, 2, 1], [2, 1], [4, 1], [5, 5, 5], [6, 6, 5], [6, 5]];
const hashes = [GenesisConfig.GENESIS_HASH];
for (let i = 0; i < interlinks.length; i++) {
const block = await bc.createBlock({
superblockLevel: levels[i],
timestamp: GenesisConfig.GENESIS_BLOCK.timestamp + i + 1
});
hashes.push(block.hash());
const interlink = interlinks[i].map(index => hashes[index]);
expect(block.interlink.length).toBe(interlink.length);
expect(block.interlink.hashes.every((hash, i) => hash.equals(interlink[i]))).toBeTruthy();
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
}
})().then(done, done.fail);
});
it('is constructed correctly (constant level-0, alternating difficulty)', (done) => {
(async () => {
const bc = await TestBlockchain.createVolatileTest(0, 5);
// target depths: [0, 0, 0, 1, 0, 1, 0, 1]
const timestamps = [1, 1, 1, 120, 60, 121, 1, 1];
const interlinks = [[0], [1], [2], [], [4, 4], [4], [6, 6], [6]];
let ts = GenesisConfig.GENESIS_BLOCK.timestamp;
const hashes = [GenesisConfig.GENESIS_HASH];
for (let i = 0; i < interlinks.length; i++) {
const block = await bc.createBlock({
superblockLevel: 0,
timestamp: ts + timestamps[i]
});
ts = block.timestamp;
hashes.push(block.hash());
const interlink = interlinks[i].map(index => hashes[index]);
expect(block.interlink.length).toBe(interlink.length);
expect(block.interlink.hashes.every((hash, i) => hash.equals(interlink[i]))).toBeTruthy();
const status = await bc.pushBlock(block);
expect(status).toBe(FullChain.OK_EXTENDED);
}
})().then(done, done.fail);
});
});