From ff55f787846cb1b89fd365307e232c6f4c701ecb Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Tue, 19 Nov 2019 16:35:15 +0900 Subject: [PATCH 1/7] Add register_is_done to ConsensusEngine This is a work-around to the currently order-dependant and non-deterministic initialization of Tendermint ConsensusEngine/Worker. --- codechain/run_node.rs | 1 + core/src/consensus/mod.rs | 2 ++ core/src/consensus/tendermint/engine.rs | 10 ++++++---- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/codechain/run_node.rs b/codechain/run_node.rs index a2fe31670f..b7f3977a3b 100644 --- a/codechain/run_node.rs +++ b/codechain/run_node.rs @@ -376,6 +376,7 @@ pub fn run_node(matches: &ArgMatches) -> Result<(), String> { // drop the scheme to free up genesis state. drop(scheme); + client.client().engine().register_is_done(); cinfo!(TEST_SCRIPT, "Initialization complete"); diff --git a/core/src/consensus/mod.rs b/core/src/consensus/mod.rs index f343634a3e..c00c82b483 100644 --- a/core/src/consensus/mod.rs +++ b/core/src/consensus/mod.rs @@ -265,6 +265,8 @@ pub trait ConsensusEngine: Sync + Send { fn register_snapshot_notify_sender(&self, _sender: SnapshotNotifySender) {} + fn register_is_done(&self) {} + fn send_snapshot_notify(&self, _block_hash: BlockHash) {} fn get_best_block_from_best_proposal_header(&self, header: &HeaderView) -> BlockHash { diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index 3261e087a5..83e5c44c1b 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -281,10 +281,6 @@ impl ConsensusEngine for Tendermint { let extension = service.register_extension(move |api| TendermintExtension::new(inner, timeouts, api)); let client = Weak::clone(self.client.read().as_ref().unwrap()); self.extension_initializer.send((extension, client)).unwrap(); - - let (result, receiver) = crossbeam::bounded(1); - self.inner.send(worker::Event::Restore(result)).unwrap(); - receiver.recv().unwrap(); } fn register_time_gap_config_to_worker(&self, time_gap_params: TimeGapParams) { @@ -303,6 +299,12 @@ impl ConsensusEngine for Tendermint { client.add_notify(Arc::downgrade(&self.chain_notify) as Weak); } + fn register_is_done(&self) { + let (result, receiver) = crossbeam::bounded(1); + self.inner.send(worker::Event::Restore(result)).unwrap(); + receiver.recv().unwrap(); + } + fn get_best_block_from_best_proposal_header(&self, header: &HeaderView) -> BlockHash { header.parent_hash() } From 28ee0ff4cf5fc83c0e8410cb05e349e6c515299e Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Tue, 19 Nov 2019 16:59:53 +0900 Subject: [PATCH 2/7] Fix missing expect.to.be.true on snapshot e2e test --- test/src/e2e/snapshot.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/e2e/snapshot.test.ts b/test/src/e2e/snapshot.test.ts index 0c1c5cf794..fe5ced6ae3 100644 --- a/test/src/e2e/snapshot.test.ts +++ b/test/src/e2e/snapshot.test.ts @@ -57,7 +57,7 @@ describe("Snapshot", async function() { stateRoot.toString() ) ) - ); + ).to.be.true; }); afterEach(function() { From 5f10ef2991b992d91ff061bf46a8dca10663cca1 Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Tue, 19 Nov 2019 13:22:50 +0900 Subject: [PATCH 3/7] Log snapshot task finish --- sync/src/snapshot/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sync/src/snapshot/mod.rs b/sync/src/snapshot/mod.rs index 79b55e70b0..3c27edfb11 100644 --- a/sync/src/snapshot/mod.rs +++ b/sync/src/snapshot/mod.rs @@ -54,6 +54,8 @@ impl Service { state_root, err ); + } else { + cinfo!(SYNC, "Snapshot is ready for block: {}", block_hash) } } cinfo!(SYNC, "Snapshot service is stopped") From 938a6a4da35a94a3ed6f73482102c50858f6e712 Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Tue, 19 Nov 2019 10:23:43 +0900 Subject: [PATCH 4/7] Refactor term_common_params method --- core/src/block.rs | 13 +++---------- core/src/client/mod.rs | 21 ++++++++++++++++++++- core/src/consensus/tendermint/engine.rs | 2 +- core/src/miner/miner.rs | 12 ++---------- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/core/src/block.rs b/core/src/block.rs index 9498ef9337..cfebf1cb7e 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -29,10 +29,12 @@ use primitives::{Bytes, H256}; use rlp::{Decodable, DecoderError, Encodable, RlpStream, UntrustedRlp}; use super::invoice::Invoice; +use crate::client::TermInfoExt; use crate::client::{EngineInfo, TermInfo}; use crate::consensus::CodeChainEngine; use crate::error::{BlockError, Error}; use crate::transaction::{SignedTransaction, UnverifiedTransaction}; +use crate::BlockId; /// A block, encoded as it is on the block chain. #[derive(Debug, Clone, PartialEq)] @@ -504,16 +506,7 @@ pub fn enact( b.push_transactions(transactions, client, parent.number(), parent.timestamp())?; let parent_common_params = client.common_params((*header.parent_hash()).into()).unwrap(); - let term_common_params = { - let block_number = client - .last_term_finished_block_num((*header.parent_hash()).into()) - .expect("The block of the parent hash should exist"); - if block_number == 0 { - None - } else { - Some(client.common_params((block_number).into()).expect("Common params should exist")) - } - }; + let term_common_params = client.term_common_params(BlockId::Hash(*header.parent_hash())); b.close_and_lock(parent, &parent_common_params, term_common_params.as_ref()) } diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 82f39070b7..07e218fae7 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -115,7 +115,7 @@ pub trait EngineClient: Sync + Send + BlockChainTrait + ImportBlock { fn get_kvdb(&self) -> Arc; } -pub trait ConsensusClient: BlockChainClient + EngineClient + EngineInfo + TermInfo + StateInfo {} +pub trait ConsensusClient: BlockChainClient + EngineClient + EngineInfo + TermInfo + StateInfo + TermInfoExt {} pub trait TermInfo { fn last_term_finished_block_num(&self, id: BlockId) -> Option; @@ -351,3 +351,22 @@ pub trait StateInfo { pub trait SnapshotClient { fn notify_snapshot(&self, id: BlockId); } + + +pub trait TermInfoExt { + fn term_common_params(&self, id: BlockId) -> Option; +} + +impl TermInfoExt for C +where + C: TermInfo + EngineInfo, +{ + fn term_common_params(&self, id: BlockId) -> Option { + let block_number = self.last_term_finished_block_num(id).expect("The block of the parent hash should exist"); + if block_number == 0 { + None + } else { + Some(self.common_params(block_number.into()).expect("Common params should exist")) + } + } +} diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index 83e5c44c1b..95efe35ca7 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -345,7 +345,7 @@ impl ConsensusEngine for Tendermint { } } -fn block_number_if_term_changed( +pub(crate) fn block_number_if_term_changed( header: &Header, parent_header: &Header, common_params: &CommonParams, diff --git a/core/src/miner/miner.rs b/core/src/miner/miner.rs index 0278715cff..a645b91f4d 100644 --- a/core/src/miner/miner.rs +++ b/core/src/miner/miner.rs @@ -41,6 +41,7 @@ use crate::account_provider::{AccountProvider, Error as AccountProviderError}; use crate::block::{Block, ClosedBlock, IsBlock}; use crate::client::{ AccountData, BlockChainTrait, BlockProducer, Client, EngineInfo, ImportBlock, MiningBlockChainClient, TermInfo, + TermInfoExt, }; use crate::codechain_machine::CodeChainMachine; use crate::consensus::{CodeChainEngine, EngineType}; @@ -599,16 +600,7 @@ impl Miner { (parent_header.decode(), parent_hash) }; let parent_common_params = chain.common_params(parent_hash.into()).unwrap(); - let term_common_params = { - let block_number = chain - .last_term_finished_block_num(parent_hash.into()) - .expect("The block of the parent hash should exist"); - if block_number == 0 { - None - } else { - Some(chain.common_params((block_number).into()).expect("Common params should exist")) - } - }; + let term_common_params = chain.term_common_params(parent_hash.into()); let block = open_block.close(&parent_header, &parent_common_params, term_common_params.as_ref())?; let fetch_seq = |p: &Public| { From 699c382227af2f4b0c0c7a0d586ea989a9a61d6f Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Mon, 18 Nov 2019 20:13:39 +0900 Subject: [PATCH 5/7] Add SnapshotNotifySender to Tendermint worker --- codechain/run_node.rs | 7 +++--- core/src/consensus/tendermint/engine.rs | 5 ++++ core/src/consensus/tendermint/mod.rs | 13 +++++++++-- core/src/consensus/tendermint/worker.rs | 31 +++++++++++++++++++++++-- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/codechain/run_node.rs b/codechain/run_node.rs index b7f3977a3b..22c2a59e9a 100644 --- a/codechain/run_node.rs +++ b/codechain/run_node.rs @@ -363,10 +363,11 @@ pub fn run_node(matches: &ArgMatches) -> Result<(), String> { } let _snapshot_service = { + let client = client.client(); + let (tx, rx) = snapshot_notify::create(); + client.engine().register_snapshot_notify_sender(tx); + if !config.snapshot.disable.unwrap() { - let client = client.client(); - let (tx, rx) = snapshot_notify::create(); - client.engine().register_snapshot_notify_sender(tx); let service = Arc::new(SnapshotService::new(client, rx, config.snapshot.path.unwrap())); Some(service) } else { diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index 95efe35ca7..3d86f4963d 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -45,6 +45,7 @@ use crate::encoded; use crate::error::Error; use crate::views::HeaderView; use crate::BlockId; +use client::snapshot_notify::NotifySender as SnapshotNotifySender; use rlp::Encodable; impl ConsensusEngine for Tendermint { @@ -299,6 +300,10 @@ impl ConsensusEngine for Tendermint { client.add_notify(Arc::downgrade(&self.chain_notify) as Weak); } + fn register_snapshot_notify_sender(&self, sender: SnapshotNotifySender) { + self.snapshot_notify_sender_initializer.send(sender).unwrap(); + } + fn register_is_done(&self) { let (result, receiver) = crossbeam::bounded(1); self.inner.send(worker::Event::Restore(result)).unwrap(); diff --git a/core/src/consensus/tendermint/mod.rs b/core/src/consensus/tendermint/mod.rs index 4e9ae0cd3a..52973ba1ea 100644 --- a/core/src/consensus/tendermint/mod.rs +++ b/core/src/consensus/tendermint/mod.rs @@ -41,6 +41,7 @@ pub use self::types::{Height, Step, View}; use super::{stake, ValidatorSet}; use crate::client::ConsensusClient; use crate::codechain_machine::CodeChainMachine; +use crate::snapshot_notify::NotifySender as SnapshotNotifySender; use ChainNotify; /// Timer token representing the consensus step timeouts. @@ -58,6 +59,7 @@ pub struct Tendermint { client: RwLock>>, external_params_initializer: crossbeam::Sender, extension_initializer: crossbeam::Sender<(crossbeam::Sender, Weak)>, + snapshot_notify_sender_initializer: crossbeam::Sender, timeouts: TimeoutParams, join: Option>, quit_tendermint: crossbeam::Sender<()>, @@ -93,8 +95,14 @@ impl Tendermint { let timeouts = our_params.timeouts; let machine = Arc::new(machine); - let (join, external_params_initializer, extension_initializer, inner, quit_tendermint) = - worker::spawn(our_params.validators); + let ( + join, + external_params_initializer, + extension_initializer, + snapshot_notify_sender_initializer, + inner, + quit_tendermint, + ) = worker::spawn(our_params.validators); let action_handlers: Vec> = vec![stake.clone()]; let chain_notify = Arc::new(TendermintChainNotify::new(inner.clone())); @@ -102,6 +110,7 @@ impl Tendermint { client: Default::default(), external_params_initializer, extension_initializer, + snapshot_notify_sender_initializer, timeouts, join: Some(join), quit_tendermint, diff --git a/core/src/consensus/tendermint/worker.rs b/core/src/consensus/tendermint/worker.rs index 93386a0df5..11751a5f27 100644 --- a/core/src/consensus/tendermint/worker.rs +++ b/core/src/consensus/tendermint/worker.rs @@ -50,6 +50,7 @@ use crate::consensus::validator_set::{DynamicValidator, ValidatorSet}; use crate::consensus::{EngineError, Seal}; use crate::encoded; use crate::error::{BlockError, Error}; +use crate::snapshot_notify::NotifySender as SnapshotNotifySender; use crate::transaction::{SignedTransaction, UnverifiedTransaction}; use crate::views::BlockView; use crate::BlockId; @@ -59,6 +60,7 @@ type SpawnResult = ( JoinHandle<()>, crossbeam::Sender, crossbeam::Sender<(crossbeam::Sender, Weak)>, + crossbeam::Sender, crossbeam::Sender, crossbeam::Sender<()>, ); @@ -97,6 +99,7 @@ struct Worker { time_gap_params: TimeGapParams, timeout_token_nonce: usize, vote_regression_checker: VoteRegressionChecker, + snapshot_notify_sender: SnapshotNotifySender, } pub enum Event { @@ -180,6 +183,7 @@ impl Worker { extension: EventSender, client: Weak, time_gap_params: TimeGapParams, + snapshot_notify_sender: SnapshotNotifySender, ) -> Self { Worker { client, @@ -198,6 +202,7 @@ impl Worker { time_gap_params, timeout_token_nonce: ENGINE_TIMEOUT_TOKEN_NONCE_BASE, vote_regression_checker: VoteRegressionChecker::new(), + snapshot_notify_sender, } } @@ -206,6 +211,7 @@ impl Worker { let (quit, quit_receiver) = crossbeam::bounded(1); let (external_params_initializer, external_params_receiver) = crossbeam::bounded(1); let (extension_initializer, extension_receiver) = crossbeam::bounded(1); + let (snapshot_notify_sender_initializer, snapshot_notify_sender_receiver) = crossbeam::bounded(1); let join = Builder::new() .name("tendermint".to_string()) .spawn(move || { @@ -249,8 +255,29 @@ impl Worker { return } }; + // TODO: Make initialization steps to order insensitive. + let snapshot_notify_sender = crossbeam::select! { + recv(snapshot_notify_sender_receiver) -> msg => { + match msg { + Ok(sender) => sender, + Err(crossbeam::RecvError) => { + cerror!(ENGINE, "The tendermint extension is not initalized."); + return + } + } + } + recv(quit_receiver) -> msg => { + match msg { + Ok(()) => {}, + Err(crossbeam::RecvError) => { + cerror!(ENGINE, "The quit channel for tendermint thread had been closed."); + } + } + return + } + }; validators.register_client(Weak::clone(&client)); - let mut inner = Self::new(validators, extension, client, time_gap_params); + let mut inner = Self::new(validators, extension, client, time_gap_params, snapshot_notify_sender); loop { crossbeam::select! { recv(receiver) -> msg => { @@ -374,7 +401,7 @@ impl Worker { } }) .unwrap(); - (join, external_params_initializer, extension_initializer, sender, quit) + (join, external_params_initializer, extension_initializer, snapshot_notify_sender_initializer, sender, quit) } /// The client is a thread-safe struct. Using it in multi-threads is safe. From 596471f7b3c807b5a39bf09b2f9602937655beb9 Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Tue, 19 Nov 2019 13:55:01 +0900 Subject: [PATCH 6/7] Implement snapshot on term end --- core/src/consensus/tendermint/worker.rs | 22 ++++++++++++++++++++++ sync/src/snapshot/mod.rs | 1 + 2 files changed, 23 insertions(+) diff --git a/core/src/consensus/tendermint/worker.rs b/core/src/consensus/tendermint/worker.rs index 11751a5f27..da3c9d407c 100644 --- a/core/src/consensus/tendermint/worker.rs +++ b/core/src/consensus/tendermint/worker.rs @@ -1657,6 +1657,28 @@ impl Worker { } } + let mut last_term_end = None; + for block_hash in &enacted { + let header = c.block_header(&BlockId::Hash(*block_hash)).expect("Block is enacted").decode(); + if header.number() == 0 { + continue + } + let parent_header = + c.block_header(&BlockId::Hash(*header.parent_hash())).expect("Parent block should be enacted").decode(); + let term_common_params = if let Some(p) = c.term_common_params(parent_header.hash().into()) { + p + } else { + continue + }; + if super::engine::block_number_if_term_changed(&header, &parent_header, &term_common_params).is_some() { + last_term_end = Some(*block_hash); + } + } + if let Some(last_term_end) = last_term_end { + // TODO: Reduce the snapshot frequency. + self.snapshot_notify_sender.notify(last_term_end); + } + if let Some((last, rest)) = imported.split_last() { let (imported, last_proposal_header) = { let header = diff --git a/sync/src/snapshot/mod.rs b/sync/src/snapshot/mod.rs index 3c27edfb11..80d0835da2 100644 --- a/sync/src/snapshot/mod.rs +++ b/sync/src/snapshot/mod.rs @@ -57,6 +57,7 @@ impl Service { } else { cinfo!(SYNC, "Snapshot is ready for block: {}", block_hash) } + // TODO: Prune old snapshots } cinfo!(SYNC, "Snapshot service is stopped") }); From a71fd81fc2ee2f9c2143dce0449581d9fbba897f Mon Sep 17 00:00:00 2001 From: SeongChan Lee Date: Tue, 19 Nov 2019 17:00:31 +0900 Subject: [PATCH 7/7] Add snapshot sync test with Tendermint dynamic validator --- test/src/e2e.dynval/2/snapshot.test.ts | 111 +++++++++++++++++++++ test/src/e2e.dynval/setup.ts | 38 +++++-- test/tendermint.dynval/snapshot-config.yml | 61 +++++++++++ 3 files changed, 200 insertions(+), 10 deletions(-) create mode 100644 test/src/e2e.dynval/2/snapshot.test.ts create mode 100644 test/tendermint.dynval/snapshot-config.yml diff --git a/test/src/e2e.dynval/2/snapshot.test.ts b/test/src/e2e.dynval/2/snapshot.test.ts new file mode 100644 index 0000000000..cc04a44438 --- /dev/null +++ b/test/src/e2e.dynval/2/snapshot.test.ts @@ -0,0 +1,111 @@ +// Copyright 2019 Kodebox, Inc. +// This file is part of CodeChain. +// +// 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. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +import * as chai from "chai"; +import { expect } from "chai"; +import * as chaiAsPromised from "chai-as-promised"; +import { SDK } from "codechain-sdk"; +import * as stake from "codechain-stakeholder-sdk"; +import * as fs from "fs"; +import "mocha"; +import * as path from "path"; + +import mkdirp = require("mkdirp"); +import { validators } from "../../../tendermint.dynval/constants"; +import { PromiseExpect } from "../../helper/promise"; +import { setTermTestTimeout, withNodes } from "../setup"; + +chai.use(chaiAsPromised); + +const SNAPSHOT_CONFIG = `${__dirname}/../../../tendermint.dynval/snapshot-config.yml`; +const SNAPSHOT_PATH = `${__dirname}/../../../../snapshot/`; + +describe("Snapshot for Tendermint with Dynamic Validator", function() { + const promiseExpect = new PromiseExpect(); + const snapshotValidators = validators.slice(0, 3); + + describe("Snapshot", async function() { + const { nodes } = withNodes(this, { + promiseExpect, + overrideParams: { + maxNumOfValidators: 3 + }, + validators: snapshotValidators.map((signer, index) => ({ + signer, + delegation: 5000, + deposit: 10_000_000 - index // tie-breaker + })), + modify: () => { + mkdirp.sync(SNAPSHOT_PATH); + const snapshotPath = fs.mkdtempSync(SNAPSHOT_PATH); + return { + additionalArgv: [ + "--snapshot-path", + snapshotPath, + "--config", + SNAPSHOT_CONFIG + ], + nodeAdditionalProperties: { + snapshotPath + } + }; + } + }); + + it("should be exist after some time", async function() { + const termWaiter = setTermTestTimeout(this, { + terms: 1 + }); + await termWaiter.waitNodeUntilTerm(nodes[0], { + target: 2, + termPeriods: 1 + }); + const blockNumber = await nodes[0].sdk.rpc.chain.getBestBlockNumber(); + const termMetadata = await stake.getTermMetadata( + nodes[0].sdk, + blockNumber + ); + + expect(termMetadata).not.to.be.null; + const { + currentTermId, + lastTermFinishedBlockNumber + } = termMetadata!; + expect(currentTermId).to.be.equals(2); + expect(lastTermFinishedBlockNumber).to.be.lte(blockNumber); + + const blockHash = (await nodes[0].sdk.rpc.chain.getBlockHash( + lastTermFinishedBlockNumber + ))!; + const stateRoot = (await nodes[0].sdk.rpc.chain.getBlock( + blockHash + ))!.stateRoot; + expect( + fs.existsSync( + path.join( + nodes[0].snapshotPath, + blockHash.toString(), + stateRoot.toString() + ) + ) + ).to.be.true; + }); + }); + + afterEach(async function() { + promiseExpect.checkFulfilled(); + }); +}); diff --git a/test/src/e2e.dynval/setup.ts b/test/src/e2e.dynval/setup.ts index 63760e56cd..fdaf8c5a80 100644 --- a/test/src/e2e.dynval/setup.ts +++ b/test/src/e2e.dynval/setup.ts @@ -28,17 +28,29 @@ interface ValidatorConfig { delegation?: U64Value; } -export function withNodes( +interface NodePropertyModifier { + additionalArgv: string[]; + nodeAdditionalProperties: T; +} + +export function withNodes( suite: Suite, options: { promiseExpect: PromiseExpect; validators: ValidatorConfig[]; overrideParams?: Partial; onBeforeEnable?: (nodes: CodeChain[]) => Promise; + modify?: (signer: Signer, index: number) => NodePropertyModifier; } ) { - const nodes: CodeChain[] = []; - const { overrideParams = {} } = options; + const nodes: (CodeChain & T)[] = []; + const { + overrideParams = {}, + modify = () => ({ + additionalArgv: [], + nodeAdditionalProperties: {} as T + }) + } = options; const initialParams = { ...defaultParams, ...overrideParams @@ -51,7 +63,8 @@ export function withNodes( nodes.length = 0; const newNodes = await createNodes({ ...options, - initialParams + initialParams, + modify }); nodes.push(...newNodes); }); @@ -84,14 +97,15 @@ export function findNode(nodes: CodeChain[], signer: Signer) { ); } -async function createNodes(options: { +async function createNodes(options: { promiseExpect: PromiseExpect; validators: ValidatorConfig[]; initialParams: typeof defaultParams; onBeforeEnable?: (nodes: CodeChain[]) => Promise; -}): Promise { + modify: (signer: Signer, index: number) => NodePropertyModifier; +}): Promise<(CodeChain & T)[]> { const chain = `${__dirname}/../scheme/tendermint-dynval.json`; - const { promiseExpect, validators, initialParams } = options; + const { promiseExpect, validators, initialParams, modify } = options; const initialNodes: CodeChain[] = []; const initialValidators = [ @@ -113,20 +127,24 @@ async function createNodes(options: { }); } - const nodes: CodeChain[] = []; + const nodes: (CodeChain & T)[] = []; for (let i = 0; i < validators.length; i++) { const { signer: validator } = validators[i]; - nodes[i] = new CodeChain({ + const modifier = modify(validator, i); + const node = new CodeChain({ chain, argv: [ "--engine-signer", validator.platformAddress.value, "--password-path", `test/tendermint.dynval/${validator.platformAddress.value}/password.json`, - "--force-sealing" + "--force-sealing", + ...modifier.additionalArgv ], additionalKeysPath: `tendermint.dynval/${validator.platformAddress.value}/keys` }); + + nodes[i] = Object.assign(node, modifier.nodeAdditionalProperties); nodes[i].setSigner(validator); } let bootstrapFailed = false; diff --git a/test/tendermint.dynval/snapshot-config.yml b/test/tendermint.dynval/snapshot-config.yml new file mode 100644 index 0000000000..2b8890b4f7 --- /dev/null +++ b/test/tendermint.dynval/snapshot-config.yml @@ -0,0 +1,61 @@ +[codechain] +quiet = false +base_path = "." +chain = "solo" + +[mining] +mem_pool_mem_limit = 4 # MB +mem_pool_size = 32768 +mem_pool_fee_bump_shift = 3 # 12.5% +allow_create_shard = false +notify_work = [] +force_sealing = false +reseal_on_txs = "all" +reseal_min_period = 0 +reseal_max_period = 120000 +no_reseal_timer = false +work_queue_size = 20 +allowed_past_gap = 30000 +allowed_future_gap = 5000 + +[network] +disable = false +interface = "0.0.0.0" +port = 3485 +max_peers = 30 +min_peers = 10 +bootstrap_addresses = [] +sync = true +transaction_relay = true +discovery = true +discovery_type = "unstructured" +discovery_refresh = 60000 +discovery_bucket_size = 10 +# whitelist_path = "whitelist.txt" +# blacklist_path = "blacklist.txt" + +[rpc] +disable = false +interface = "127.0.0.1" +port = 8080 + +[ipc] +disable = false +path = "/tmp/jsonrpc.ipc" + +[ws] +disable = false +interface = "127.0.0.1" +port = 8081 +max_connections = 100 + +[snapshot] +disable = false +path = "snapshot" + +[stratum] +disable = false +port = 8008 + +[email_alarm] +disable = true