Commit 907a2106 authored by Cédric Moreau's avatar Cédric Moreau
Browse files

[fix] #1396: ensure that we do have a bug with triming + reverting for CINDEX entries

parent cde657e8
......@@ -146,13 +146,13 @@ export class LevelDBCindex extends LevelDBTable<LevelDBCindexEntry> implements C
}
}
// Remove the "received" arrays
await Promise.all(toRemove.map(async e => {
for (const e of toRemove) {
const entry = await this.get(e.receiver)
// Remove the certification
entry.received = entry.received.filter(issuer => issuer !== e.issuer)
// Persist
await this.put(e.receiver, entry)
}))
}
// Remove the expires_on index entries
const expires = Underscore.uniq(toRemove.filter(e => e.expires_on).map(e => e.expires_on))
await Promise.all(expires.map(async e => this.indexForExpiresOn.del(LevelDBCindex.trimExpiredOnKey(e))))
......
......@@ -460,7 +460,7 @@ export class BlockGenerator {
exclusions:any,
wereExcluded:any,
transactions:any,
manualValues:any) {
manualValues:ForcedBlockValues) {
if (manualValues && manualValues.excluded) {
exclusions = manualValues.excluded;
......@@ -630,6 +630,16 @@ export class BlockGenerator {
}
}
// Forced joiners (by tests)
if (manualValues && manualValues.joiners) {
block.joiners = block.joiners.concat(manualValues.joiners.map(j => j.inline()))
}
// Forced certifications (by tests)
if (manualValues && manualValues.certifications) {
block.certifications = block.certifications.concat(manualValues.certifications.map(c => c.inline()))
}
// Final number of members
block.membersCount = previousCount + block.joiners.length - block.excluded.length;
......@@ -679,7 +689,7 @@ export class BlockGenerator {
block.issuersFrameVar = vHEAD.issuersFrameVar;
// Manual values before hashing
if (manualValues) {
Underscore.extend(block, Underscore.omit(manualValues, 'time'));
Underscore.extend(block, Underscore.omit(manualValues, 'time', 'certifications', 'joiners'));
}
// InnerHash
block.time = block.medianTime;
......@@ -847,3 +857,13 @@ class ManualRootGenerator implements BlockGeneratorInterface {
}
}
}
export interface ForcedBlockValues {
time?: number
version?: number
medianTime?: number
excluded?: string[]
revoked?: string[]
certifications?: CertificationDTO[]
joiners?: MembershipDTO[]
}
\ No newline at end of file
// Source file from duniter: Crypto-currency software to manage libre currency such as Ğ1
// Copyright (C) 2018 Cedric Moreau <cem.moreau@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
import {assertEqual, writeBasicTestWithConfAnd2Users} from "../tools/test-framework"
import {assertThrows} from "../../unit-tools"
import {CommonConstants} from "../../../app/lib/common-libs/constants"
const currentVersion = CommonConstants.BLOCK_GENERATED_VERSION
describe('Block revert with a comebacker in it', () => writeBasicTestWithConfAnd2Users({
sigQty: 2,
sigReplay: 0,
sigPeriod: 0,
sigValidity: 10,
dtDiffEval: 1,
forksize: 0,
}, (test) => {
const now = 1500000000
test('(t = 0) should init with a 4 members WoT with bidirectionnal certs', async (s1, cat, tac, toc) => {
CommonConstants.BLOCK_GENERATED_VERSION = 11
await cat.createIdentity()
await tac.createIdentity()
await toc.createIdentity()
await cat.cert(tac)
await cat.cert(toc)
await tac.cert(cat)
await tac.cert(toc)
await toc.cert(cat)
await toc.cert(tac)
await cat.join()
await tac.join()
await toc.join()
const b0 = await s1.commit({ time: now })
assertEqual(b0.certifications.length, 6)
const b1 = await s1.commit({ time: now })
assertEqual(b1.membersCount, 3)
})
test('(t = 5) cat & tac certify each other', async (s1, cat, tac, toc) => {
await s1.commit({ time: now + 5 })
await s1.commit({ time: now + 5 })
await new Promise(resolve => setTimeout(resolve, 500))
// cat and tac certify each other to stay in the WoT
await tac.cert(cat)
await toc.cert(cat) // <-- toc adds the 2nd certification
const b1 = await s1.commit({ time: now + 6 })
assertEqual(b1.certifications.length, 2)
await cat.cert(tac)
await toc.cert(tac) // <-- toc adds the 2nd certification
const b2 = await s1.commit({ time: now + 6 })
assertEqual(b2.certifications.length, 2)
// // /!\/!\/!\
// // toc gets certified by cat, to a have a remaining valid certification in the blockchain: THIS WONT BE ENOUGH!
await cat.cert(toc)
// // /!\/!\/!\
const b4 = await s1.commit({ time: now + 6 })
assertEqual(b4.certifications.length, 1)
})
test('(t = 12) toc is excluded for lack of certifications', async (s1, cat, tac, toc) => {
await s1.commit({ time: now + 12 })
await s1.commit({ time: now + 12 })
const b = await s1.commit({ time: now + 12 })
assertEqual(b.excluded.length, 1)
assertEqual(b.excluded[0], toc.pub)
})
test('(t = 12) we want some blocs to trim CINDEX', async (s1) => {
for (let i = 0; i < 10; i++) {
await s1.commit({ time: now + 12 })
}
})
test('(t = 13 #1) toc is coming back with 2 certs, whose 1 is a renewal', async (s1, cat, tac, toc) => {
await s1.commit({ time: now + 13 })
await s1.commit({ time: now + 13 })
const c1 = await cat.makeCert(toc) // <-- a renewal ==> this is what we want to observe
const join = await toc.makeMembership('IN')
const b = await s1.commit({
time: now + 13,
joiners: [join],
certifications: [c1]
})
assertEqual(b.membersCount, 3)
assertEqual(b.number, 22)
})
test('(t = 12 #2) revert successfuly', async (s1) => {
await s1.revert()
const b = await s1.dal.getBlockCurrent()
assertEqual(b.membersCount, 2)
assertEqual(b.number, 21)
})
test('(t = 12 #3) resolution should work', async (s1) => {
await assertThrows(s1.resolve(), 'BLOCK_WASNT_COMMITTED')
const b = await s1.dal.getBlockCurrent()
assertEqual(b.membersCount, 2)
assertEqual(b.number, 21)
})
after(() => {
CommonConstants.BLOCK_GENERATED_VERSION = currentVersion
})
}))
......@@ -60,6 +60,7 @@ import {WebSocketServer} from "../../../app/lib/common-libs/websocket"
import {CommonConstants} from "../../../app/lib/common-libs/constants"
import {WS2PRequester} from "../../../app/modules/ws2p/lib/WS2PRequester"
import {WS2PDependency} from "../../../app/modules/ws2p/index"
import {ForcedBlockValues} from "../../../app/modules/prover/lib/blockGenerator"
const assert = require('assert');
const rp = require('request-promise');
......@@ -239,7 +240,7 @@ export const NewTestingServer = (conf:any) => {
remoteipv4: host,
currency: conf.currency || CURRENCY_NAME,
httpLogs: true,
forksize: conf.forksize || 3,
forksize: conf.forksize !== undefined ? conf.forksize : 3,
nonWoTPeersLimit: CommonConstants.DEFAULT_NON_WOT_PEERS_LIMIT,
};
if (conf.sigQty === undefined) {
......@@ -508,7 +509,7 @@ export class TestingServer {
return proven
}
async commit(options:any = null) {
async commit(options:ForcedBlockValues|null = null) {
const proven = await this.generateNext(options)
await this.server.writeBlock(proven, true, true) // The resolution is done manually
const blocksResolved = await this.server.BlockchainService.blockResolution()
......
......@@ -12,6 +12,7 @@
// GNU Affero General Public License for more details.
import * as assert from 'assert'
const should = require('should')
export async function shouldThrow(promise:Promise<any>) {
......@@ -58,7 +59,7 @@ export const assertThrows = async (promise:Promise<any>, message:string|null = n
if (e === "Should have thrown") {
throw e
}
assert.equal(e, message)
assert.equal(e.message || e, message)
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment