Skip to content

Commit 1534345

Browse files
author
Hyunsik Jeong
committed
Add reseal timer to client
1 parent ce36248 commit 1534345

File tree

7 files changed

+192
-71
lines changed

7 files changed

+192
-71
lines changed

codechain/run_node.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,22 @@ fn discovery_start(service: &NetworkService, cfg: &config::Network) -> Result<()
8686
Ok(())
8787
}
8888

89-
fn client_start(cfg: &config::Operating, scheme: &Scheme, miner: Arc<Miner>) -> Result<ClientService, String> {
89+
fn client_start(
90+
timer_loop: &TimerLoop,
91+
cfg: &config::Operating,
92+
scheme: &Scheme,
93+
miner: Arc<Miner>,
94+
) -> Result<ClientService, String> {
9095
cinfo!(CLIENT, "Starting client");
9196
let db_path = cfg.db_path.as_ref().map(|s| s.as_str()).unwrap();
9297
let client_path = Path::new(db_path);
9398
let client_config = Default::default();
9499
let service = ClientService::start(&client_config, &scheme, &client_path, miner)
95100
.map_err(|e| format!("Client service error: {}", e))?;
96101

102+
let reseal_timer = timer_loop.new_timer("Client reseal timer", service.client());
103+
service.client().register_reseal_timer(reseal_timer);
104+
97105
Ok(service)
98106
}
99107

@@ -229,7 +237,7 @@ pub fn run_node(matches: &ArgMatches) -> Result<(), String> {
229237
unlock_accounts(&*ap, &pf)?;
230238

231239
let miner = new_miner(&config, &scheme, ap.clone())?;
232-
let client = client_start(&config.operating, &scheme, miner.clone())?;
240+
let client = client_start(&timer_loop, &config.operating, &scheme, miner.clone())?;
233241
let sync = BlockSyncExtension::new(client.client());
234242

235243
scheme.engine.register_chain_notify(client.client().as_ref());

core/src/client/client.rs

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use cnetwork::NodeId;
2525
use cstate::{
2626
ActionHandler, AssetScheme, AssetSchemeAddress, OwnedAsset, OwnedAssetAddress, StateDB, TopLevelState, TopStateView,
2727
};
28+
use ctimer::{TimeoutHandler, TimerApi, TimerToken};
2829
use ctypes::invoice::Invoice;
2930
use ctypes::transaction::Transaction;
3031
use ctypes::{BlockNumber, ShardId};
@@ -41,7 +42,8 @@ use super::{
4142
AccountData, AssetClient, Balance, BlockChain as BlockChainTrait, BlockChainClient, BlockChainInfo, BlockInfo,
4243
BlockProducer, ChainInfo, ChainNotify, ClientConfig, DatabaseClient, EngineClient, EngineInfo,
4344
Error as ClientError, ExecuteClient, ImportBlock, ImportResult, ImportSealedBlock, MiningBlockChainClient,
44-
ParcelInfo, PrepareOpenBlock, RegularKey, RegularKeyOwner, ReopenBlock, Seq, Shard, StateOrBlock, TransactionInfo,
45+
ParcelInfo, PrepareOpenBlock, RegularKey, RegularKeyOwner, ReopenBlock, ResealTimer, Seq, Shard, StateOrBlock,
46+
TransactionInfo,
4547
};
4648
use crate::block::{ClosedBlock, IsBlock, OpenBlock, SealedBlock};
4749
use crate::blockchain::{
@@ -79,6 +81,9 @@ pub struct Client {
7981
genesis_accounts: Vec<Address>,
8082

8183
importer: Importer,
84+
85+
/// Timer for reseal_min_period/reseal_max_period on miner client
86+
reseal_timer: RwLock<Option<TimerApi>>,
8287
}
8388

8489
impl Client {
@@ -121,13 +126,18 @@ impl Client {
121126
queue_parcels: AtomicUsize::new(0),
122127
genesis_accounts,
123128
importer,
129+
reseal_timer: RwLock::new(None),
124130
});
125131

126132
// ensure buffered changes are flushed.
127133
client.db.read().flush().map_err(ClientError::Database)?;
128134
Ok(client)
129135
}
130136

137+
pub fn register_reseal_timer(&self, timer: TimerApi) {
138+
self.register_timer(timer);
139+
}
140+
131141
/// Returns engine reference.
132142
pub fn engine(&self) -> &CodeChainEngine {
133143
&*self.engine
@@ -260,6 +270,60 @@ impl Client {
260270
}
261271
}
262272

273+
const RESEAL_MAX_TIMER_TOKEN: TimerToken = 0;
274+
const RESEAL_MIN_TIMER_TOKEN: TimerToken = 1;
275+
276+
impl TimeoutHandler for Client {
277+
fn on_timeout(&self, token: TimerToken) {
278+
match token {
279+
RESEAL_MAX_TIMER_TOKEN => {
280+
// Working in PoW only
281+
if self.engine().seals_internally().is_none() && !self.importer.miner.prepare_work_sealing(self) {
282+
self.update_sealing(true);
283+
}
284+
}
285+
RESEAL_MIN_TIMER_TOKEN => {
286+
if let Some(reseal_timer) = self.reseal_timer.read().as_ref() {
287+
reseal_timer.cancel(RESEAL_MAX_TIMER_TOKEN).expect("Reseal max timer clear succeeds");
288+
};
289+
290+
// Checking self.ready_parcels() for efficiency
291+
if !self.ready_parcels().is_empty() {
292+
self.update_sealing(false);
293+
}
294+
}
295+
_ => unreachable!(),
296+
}
297+
}
298+
}
299+
300+
impl ResealTimer for Client {
301+
fn register_timer(&self, timer: TimerApi) {
302+
timer
303+
.schedule_once(self.importer.miner.get_options().reseal_max_period, RESEAL_MAX_TIMER_TOKEN)
304+
.expect("Reseal max timer set succeeds");
305+
*self.reseal_timer.write() = Some(timer);
306+
}
307+
308+
fn set_max_timer(&self) {
309+
if let Some(reseal_timer) = self.reseal_timer.read().as_ref() {
310+
reseal_timer.cancel(RESEAL_MAX_TIMER_TOKEN).expect("Reseal max timer clear succeeds");
311+
reseal_timer
312+
.schedule_once(self.importer.miner.get_options().reseal_max_period, RESEAL_MAX_TIMER_TOKEN)
313+
.expect("Reseal max timer set succeeds");
314+
};
315+
}
316+
317+
fn set_min_timer(&self) {
318+
if let Some(reseal_timer) = self.reseal_timer.read().as_ref() {
319+
reseal_timer.cancel(RESEAL_MIN_TIMER_TOKEN).expect("Reseal min timer clear succeeds");
320+
reseal_timer
321+
.schedule_once(self.importer.miner.get_options().reseal_min_period, RESEAL_MIN_TIMER_TOKEN)
322+
.expect("Reseal min timer set succeeds");
323+
};
324+
}
325+
}
326+
263327
impl DatabaseClient for Client {
264328
fn database(&self) -> Arc<KeyValueDB> {
265329
Arc::clone(&self.db())
@@ -367,8 +431,8 @@ impl EngineInfo for Client {
367431

368432
impl EngineClient for Client {
369433
/// Make a new block and seal it.
370-
fn update_sealing(&self) {
371-
self.importer.miner.update_sealing(self)
434+
fn update_sealing(&self, allow_empty_block: bool) {
435+
self.importer.miner.update_sealing(self, allow_empty_block)
372436
}
373437

374438
/// Submit a seal for a block in the mining queue.

core/src/client/mod.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use ckey::{Address, PlatformAddress, Public};
3535
use cmerkle::Result as TrieResult;
3636
use cnetwork::NodeId;
3737
use cstate::{ActionHandler, AssetScheme, AssetSchemeAddress, OwnedAsset, TopStateView};
38+
use ctimer::TimerApi;
3839
use ctypes::invoice::Invoice;
3940
use ctypes::transaction::Transaction;
4041
use ctypes::{BlockNumber, ShardId};
@@ -101,7 +102,7 @@ pub trait EngineInfo: Send + Sync {
101102
/// Client facilities used by internally sealing Engines.
102103
pub trait EngineClient: Sync + Send + ChainInfo + ImportBlock + BlockInfo {
103104
/// Make a new block and seal it.
104-
fn update_sealing(&self);
105+
fn update_sealing(&self, allow_empty_block: bool);
105106

106107
/// Submit a seal for a block in the mining queue.
107108
fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>);
@@ -183,6 +184,16 @@ pub trait Shard {
183184
fn shard_root(&self, shard_id: ShardId, state: StateOrBlock) -> Option<H256>;
184185
}
185186

187+
/// Provides a timer API for reseal_min_period/reseal_max_period on miner client
188+
pub trait ResealTimer {
189+
/// Register timer API
190+
fn register_timer(&self, timer: TimerApi);
191+
/// Set reseal min timer as reseal_min_period, for creating blocks with parcels which are pending because of reseal_min_period
192+
fn set_min_timer(&self);
193+
/// Set reseal max timer as reseal_max_period, for creating empty blocks every reseal_max_period
194+
fn set_max_timer(&self);
195+
}
196+
186197
/// Provides methods to access account info
187198
pub trait AccountData: Seq + Balance {}
188199

@@ -200,7 +211,7 @@ pub trait BlockChain: ChainInfo + BlockInfo + ParcelInfo + TransactionInfo {}
200211

201212
/// Blockchain database client. Owns and manages a blockchain and a block queue.
202213
pub trait BlockChainClient:
203-
Sync + Send + AccountData + BlockChain + ImportBlock + RegularKeyOwner + ChainTimeInfo {
214+
Sync + Send + AccountData + BlockChain + ImportBlock + RegularKeyOwner + ChainTimeInfo + ResealTimer {
204215
/// Get block queue information.
205216
fn queue_info(&self) -> BlockQueueInfo;
206217

core/src/client/test_client.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use ckey::{public_to_address, Address, Generator, NetworkId, PlatformAddress, Ra
3939
use cmerkle::skewed_merkle_root;
4040
use cnetwork::NodeId;
4141
use cstate::{ActionHandler, StateDB};
42+
use ctimer::{TimeoutHandler, TimerApi, TimerToken};
4243
use ctypes::invoice::Invoice;
4344
use ctypes::parcel::{Action, Parcel};
4445
use ctypes::transaction::Transaction;
@@ -55,8 +56,8 @@ use crate::blockchain_info::BlockChainInfo;
5556
use crate::client::ImportResult;
5657
use crate::client::{
5758
AccountData, Balance, BlockChain, BlockChainClient, BlockInfo, BlockProducer, BlockStatus, ChainInfo, ImportBlock,
58-
ImportSealedBlock, MiningBlockChainClient, ParcelInfo, PrepareOpenBlock, RegularKeyOwner, ReopenBlock, Seq,
59-
StateOrBlock, TransactionInfo,
59+
ImportSealedBlock, MiningBlockChainClient, ParcelInfo, PrepareOpenBlock, RegularKeyOwner, ReopenBlock, ResealTimer,
60+
Seq, StateOrBlock, TransactionInfo,
6061
};
6162
use crate::db::{COL_STATE, NUM_COLUMNS};
6263
use crate::encoded;
@@ -529,6 +530,18 @@ impl BlockChainClient for TestBlockChainClient {
529530
}
530531
}
531532

533+
impl TimeoutHandler for TestBlockChainClient {
534+
fn on_timeout(&self, _token: TimerToken) {}
535+
}
536+
537+
impl ResealTimer for TestBlockChainClient {
538+
fn register_timer(&self, _timer: TimerApi) {}
539+
540+
fn set_max_timer(&self) {}
541+
542+
fn set_min_timer(&self) {}
543+
}
544+
532545
impl ChainTimeInfo for TestBlockChainClient {
533546
fn best_block_number(&self) -> u64 {
534547
0
@@ -548,8 +561,8 @@ impl ChainTimeInfo for TestBlockChainClient {
548561
}
549562

550563
impl super::EngineClient for TestBlockChainClient {
551-
fn update_sealing(&self) {
552-
self.miner.update_sealing(self)
564+
fn update_sealing(&self, allow_empty_block: bool) {
565+
self.miner.update_sealing(self, allow_empty_block)
553566
}
554567

555568
fn submit_seal(&self, block_hash: H256, seal: Vec<Bytes>) {

core/src/consensus/tendermint/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ impl Tendermint {
256256
fn update_sealing(&self) {
257257
if let Some(ref weak) = *self.client.read() {
258258
if let Some(c) = weak.upgrade() {
259-
c.update_sealing();
259+
c.update_sealing(true);
260260
}
261261
}
262262
}

0 commit comments

Comments
 (0)