Skip to content

Commit

Permalink
Forge block timestamps in manual seal mode (paritytech#76)
Browse files Browse the repository at this point in the history
* sketch the idea

* re-enable some tests

* re-enable genesis-block test

* re-work timestamp test

* prettier

* fix test
  • Loading branch information
JoshOrndorff authored Oct 29, 2020
1 parent 4aec8f6 commit c77c00e
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 5 deletions.
1 change: 1 addition & 0 deletions node/standalone/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod service;
mod cli;
mod command;
mod rpc;
mod mock_timestamp;

fn main() -> sc_cli::Result<()> {
command::run()
Expand Down
62 changes: 62 additions & 0 deletions node/standalone/src/mock_timestamp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/// Provide a mock duration starting at 0 in millisecond for timestamp inherent.
/// Each call will increment timestamp by slot_duration making Aura think time has passed.
// Copyright 2019-2020 PureStake Inc.
// This file is part of Moonbeam.

// Moonbeam is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Moonbeam 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 General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Moonbeam. If not, see <http://www.gnu.org/licenses/>.

// This module introduces a FAKE timestamp inherent data provider which will
// always include timestamps that are one aura-slot-duration apart from one another.
// This allows us to use manual seal to author blocks quickly without violating
// timestamp assumptions made by either the Aura pallet or the Timestamp pallet.
//
// This code was taken from https://github.com/paritytech/frontier/pull/170
// When moonbeam updates to a Frontier version that includes that PR, we should re-evaluate
// whether it makes sense to keep this here.

use sp_inherents::{InherentData, InherentIdentifier, ProvideInherentData};
use sp_timestamp::InherentError;
use std::cell::RefCell;

use moonbeam_runtime::MINIMUM_PERIOD;

const SLOT_DURATION : u64 = MINIMUM_PERIOD * 2;

/// Provide a mock duration starting at 0 in millisecond for timestamp inherent.
/// Each call will increment timestamp by slot_duration making Aura think time has passed.
pub struct MockTimestampInherentDataProvider;

pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"timstap0";

thread_local!(static TIMESTAMP: RefCell<u64> = RefCell::new(0));

impl ProvideInherentData for MockTimestampInherentDataProvider {
fn inherent_identifier(&self) -> &'static InherentIdentifier {
&INHERENT_IDENTIFIER
}

fn provide_inherent_data(
&self,
inherent_data: &mut InherentData,
) -> Result<(), sp_inherents::Error> {
TIMESTAMP.with(|x| {
*x.borrow_mut() += SLOT_DURATION;
inherent_data.put_data(INHERENT_IDENTIFIER, &*x.borrow())
})
}

fn error_to_string(&self, error: &[u8]) -> Option<String> {
InherentError::try_from(&INHERENT_IDENTIFIER, error).map(|e| format!("{:?}", e))
}
}
3 changes: 2 additions & 1 deletion node/standalone/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair};
use sc_finality_grandpa::{
GrandpaBlockImport, FinalityProofProvider as GrandpaFinalityProofProvider, SharedVoterState,
};
use crate::mock_timestamp::MockTimestampInherentDataProvider;

// Our native executor instance.
native_executor_instance!(
Expand Down Expand Up @@ -84,7 +85,7 @@ pub fn new_partial(config: &Configuration, manual_seal: bool) -> Result<

if manual_seal {
inherent_data_providers
.register_provider(sp_timestamp::InherentDataProvider)
.register_provider(MockTimestampInherentDataProvider)
.map_err(Into::into)
.map_err(sp_consensus::error::Error::InherentData)?;

Expand Down
5 changes: 4 additions & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ pub type Hash = sp_core::H256;
/// Digest item type.
pub type DigestItem = generic::DigestItem<Hash>;

/// Minimum time between blocks.
pub const MINIMUM_PERIOD: u64 = 3000;

/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
Expand Down Expand Up @@ -193,7 +196,7 @@ parameter_types! {
// When running in standalone mode, this controls the block time.
// Block time is double the minimum period.
// https://github.com/paritytech/substrate/blob/e4803bd/frame/aura/src/lib.rs#L197-L199
pub const MinimumPeriod: u64 = 3_000;
pub const MinimumPeriod: u64 = MINIMUM_PERIOD;
}

impl pallet_timestamp::Trait for Runtime {
Expand Down
7 changes: 4 additions & 3 deletions tests/tests/test-block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ describeWithMoonbeam("Moonbeam RPC (Block)", `simple-specs.json`, (context) => {
});

it("should have valid timestamp after block production", async function () {
// Originally ,this test required the timestamp be in the last finve minutes.
// This requirement doesn't make sense when we forge timestamps in manual seal.
const block = await context.web3.eth.getBlock("latest");
const last5Minutes = Date.now() / 1000 - 300;
const next5Minutes = Date.now() / 1000 + 300;
expect(block.timestamp).to.be.least(last5Minutes);
expect(block.timestamp).to.be.least(0);
expect(block.timestamp).to.be.below(next5Minutes);
});

Expand All @@ -81,7 +82,7 @@ describeWithMoonbeam("Moonbeam RPC (Block)", `simple-specs.json`, (context) => {
//parentHash: "0x04540257811b46d103d9896e7807040e7de5080e285841c5430d1a81588a0ce4",
receiptsRoot: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
sha3Uncles: "0x0000000000000000000000000000000000000000000000000000000000000000",
size: 539,
size: 535,
stateRoot: "0x0000000000000000000000000000000000000000000000000000000000000000",
//timestamp: 1595012243836,
totalDifficulty: null,
Expand Down

0 comments on commit c77c00e

Please sign in to comment.