Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic PoT verification #1918

Merged
merged 7 commits into from
Sep 4, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 7 additions & 14 deletions crates/pallet-subspace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ use sp_runtime::DispatchError;
use sp_std::collections::btree_map::BTreeMap;
use sp_std::prelude::*;
use subspace_core_primitives::crypto::Scalar;
#[cfg(feature = "pot")]
use subspace_core_primitives::PotProof;
use subspace_core_primitives::{
ArchivedHistorySegment, HistorySize, PublicKey, Randomness, RewardSignature, SectorId,
SectorIndex, SegmentHeader, SegmentIndex, SolutionRange,
};
#[cfg(feature = "pot")]
use subspace_core_primitives::{PotProof, PotSeed};
use subspace_solving::REWARD_SIGNING_CONTEXT;
#[cfg(not(feature = "pot"))]
use subspace_verification::derive_randomness;
Expand Down Expand Up @@ -789,20 +789,13 @@ impl<T: Config> Pallet<T> {

fn do_initialize(block_number: T::BlockNumber) {
#[cfg(feature = "pot")]
frame_system::Pallet::<T>::deposit_log(DigestItem::future_pot_seed(
if block_number.is_one() {
PotSeed::from_genesis_block_hash(
frame_system::Pallet::<T>::block_hash(T::BlockNumber::zero())
.as_ref()
.try_into()
.expect("Genesis block hash length must match, panic otherwise"),
)
} else {
if !block_number.is_one() {
frame_system::Pallet::<T>::deposit_log(DigestItem::future_pot_seed(
FuturePotSeed::<T>::get().expect(
"Is set at the end of `do_initialize` of every block after genesis; qed",
)
},
));
),
));
}

let pre_digest = <frame_system::Pallet<T>>::digest()
.logs
Expand Down
21 changes: 8 additions & 13 deletions crates/sc-proof-of-time/src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::marker::PhantomData;
use std::num::NonZeroU32;
use std::sync::Arc;
use std::thread;
use subspace_core_primitives::{BlockHash, PotCheckpoints, PotKey, PotSeed, SlotNumber};
use subspace_core_primitives::{PotCheckpoints, PotSeed, SlotNumber};
use subspace_proof_of_time::PotError;
use tracing::{debug, error};

Expand All @@ -28,12 +28,12 @@ pub struct PotSlotInfo {
pub struct PotSlotInfoStream(mpsc::Receiver<PotSlotInfo>);

/// Configuration for proof of time source
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Clone)]
pub struct PotSourceConfig {
/// Is this node a Timekeeper
pub is_timekeeper: bool,
/// PoT key used initially when PoT chain starts
pub initial_key: PotKey,
/// External entropy, used initially when PoT chain starts to derive the first seed
pub external_entropy: Vec<u8>,
vedhavyas marked this conversation as resolved.
Show resolved Hide resolved
}

/// Source of proofs of time.
Expand All @@ -51,7 +51,6 @@ pub struct PotSource<Block, Client> {
impl<Block, Client> PotSource<Block, Client>
where
Block: BlockT,
BlockHash: From<Block::Hash>,
Client: ProvideRuntimeApi<Block> + HeaderBackend<Block>,
Client::Api: SubspaceRuntimeApi<Block, FarmerPublicKey>,
{
Expand All @@ -62,13 +61,12 @@ where
let PotSourceConfig {
// TODO: Respect this boolean flag
is_timekeeper: _,
initial_key,
external_entropy,
} = config;
let info = client.info();
// TODO: All 3 are incorrect and should be able to continue after node restart
let start_slot = SlotNumber::MIN;
let start_seed = PotSeed::from_genesis_block_hash(BlockHash::from(info.genesis_hash));
let start_key = initial_key;
let start_seed = PotSeed::from_genesis(info.genesis_hash.as_ref(), &external_entropy);
#[cfg(feature = "pot")]
let best_hash = info.best_hash;
#[cfg(feature = "pot")]
Expand All @@ -85,8 +83,7 @@ where
thread::Builder::new()
.name("timekeeper".to_string())
.spawn(move || {
if let Err(error) =
run_timekeeper(start_seed, start_key, start_slot, iterations, slot_sender)
if let Err(error) = run_timekeeper(start_seed, start_slot, iterations, slot_sender)
{
error!(%error, "Timekeeper exited with an error");
}
Expand All @@ -113,16 +110,14 @@ where
/// Runs timekeeper, must be running on a fast dedicated CPU core
fn run_timekeeper(
mut seed: PotSeed,
mut key: PotKey,
mut slot: SlotNumber,
iterations: NonZeroU32,
mut slot_sender: mpsc::Sender<PotSlotInfo>,
) -> Result<(), PotError> {
loop {
let checkpoints = subspace_proof_of_time::prove(seed, key, iterations)?;
let checkpoints = subspace_proof_of_time::prove(seed, iterations)?;

seed = checkpoints.output().seed();
key = seed.key();

let slot_info = PotSlotInfo {
slot: Slot::from(slot),
Expand Down
7 changes: 4 additions & 3 deletions crates/sp-consensus-subspace/src/digests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,8 +583,10 @@ pub struct SubspaceDigestItems<PublicKey, RewardAddress, Signature> {
/// Root plot public key was updated
pub root_plot_public_key_update: Option<Option<FarmerPublicKey>>,
/// Future proof of time seed, essentially output of parent block's future proof of time.
///
/// This value is missing in block #1, but present in all blocks after that.
#[cfg(feature = "pot")]
pub future_pot_seed: PotSeed,
pub future_pot_seed: Option<PotSeed>,
}

/// Extract the Subspace global randomness from the given header.
Expand Down Expand Up @@ -799,8 +801,7 @@ where
enable_solution_range_adjustment_and_override: maybe_enable_and_override_solution_range,
root_plot_public_key_update: maybe_root_plot_public_key_update,
#[cfg(feature = "pot")]
future_pot_seed: maybe_future_pot_seed
.ok_or(Error::Missing(ErrorDigestType::FuturePotSeed))?,
future_pot_seed: maybe_future_pot_seed,
})
}

Expand Down
3 changes: 3 additions & 0 deletions crates/sp-consensus-subspace/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,9 @@ sp_api::decl_runtime_apis! {
/// Returns `Vec<SegmentHeader>` if a given extrinsic has them.
fn extract_segment_headers(ext: &Block::Extrinsic) -> Option<Vec<SegmentHeader >>;

/// Checks if the extrinsic is an inherent.
fn is_inherent(ext: &Block::Extrinsic) -> bool;

/// Returns root plot public key in case block authoring is restricted.
fn root_plot_public_key() -> Option<FarmerPublicKey>;

Expand Down
11 changes: 5 additions & 6 deletions crates/subspace-core-primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ extern crate alloc;

use crate::crypto::kzg::{Commitment, Witness};
use crate::crypto::{
blake2b_256_hash, blake2b_256_hash_list, blake2b_256_hash_with_key, blake3_hash, Scalar,
blake2b_256_hash, blake2b_256_hash_list, blake2b_256_hash_with_key, blake3_hash,
blake3_hash_list, Scalar,
};
#[cfg(feature = "serde")]
use ::serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -141,9 +142,6 @@ pub type SolutionRange = u64;
/// The closer solution's tag is to the target, the heavier it is.
pub type BlockWeight = u128;

/// Block hash (the bytes from H256)
pub type BlockHash = [u8; 32];

// TODO: New type
/// Segment commitment type.
pub type SegmentCommitment = Commitment;
Expand Down Expand Up @@ -302,9 +300,10 @@ impl PotSeed {

/// Derive initial PoT seed from genesis block hash
#[inline]
pub fn from_genesis_block_hash(block_hash: BlockHash) -> Self {
pub fn from_genesis(genesis_block_hash: &[u8], external_entropy: &[u8]) -> Self {
let hash = blake3_hash_list(&[genesis_block_hash, external_entropy]);
let mut seed = Self::default();
seed.copy_from_slice(&block_hash[..Self::SIZE]);
seed.copy_from_slice(&hash[..Self::SIZE]);
seed
}

Expand Down
1 change: 1 addition & 0 deletions crates/subspace-node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ frame-benchmarking = { version = "4.0.0-dev", git = "https://github.com/subspace
frame-benchmarking-cli = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71", default-features = false }
frame-support = { version = "4.0.0-dev", git = "https://github.com/subspace/substrate", rev = "55c157cff49b638a59d81a9f971f0f9a66829c71" }
futures = "0.3.28"
hex = "0.4.3"
hex-literal = "0.4.0"
log = "0.4.19"
once_cell = "1.18.0"
Expand Down
18 changes: 9 additions & 9 deletions crates/subspace-node/src/bin/subspace-node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,10 +425,10 @@ fn main() -> Result<(), Error> {
};

#[cfg(feature = "pot")]
let maybe_chain_spec_pot_initial_key = consensus_chain_config
let maybe_chain_spec_pot_external_entropy = consensus_chain_config
.chain_spec
.properties()
.get("potInitialKey")
.get("potExternalEntropy")
.map(|d| serde_json::from_value(d.clone()))
.transpose()
.map_err(|error| {
Expand All @@ -438,20 +438,20 @@ fn main() -> Result<(), Error> {
})?
.flatten();
#[cfg(feature = "pot")]
if maybe_chain_spec_pot_initial_key.is_some()
&& cli.pot_initial_key.is_some()
&& maybe_chain_spec_pot_initial_key != cli.pot_initial_key
if maybe_chain_spec_pot_external_entropy.is_some()
&& cli.pot_external_entropy.is_some()
&& maybe_chain_spec_pot_external_entropy != cli.pot_external_entropy
{
warn!(
"--pot-initial-key CLI argument was ignored due to chain spec having a \
different explicit value"
"--pot-external-entropy CLI argument was ignored due to chain spec having \
a different explicit value"
);
}
#[cfg(feature = "pot")]
let pot_source_config = PotSourceConfig {
is_timekeeper: cli.timekeeper,
initial_key: maybe_chain_spec_pot_initial_key
.or(cli.pot_initial_key)
external_entropy: maybe_chain_spec_pot_external_entropy
.or(cli.pot_external_entropy)
.unwrap_or_default(),
};

Expand Down
8 changes: 4 additions & 4 deletions crates/subspace-node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ pub fn gemini_3f_compiled() -> Result<ConsensusChainSpec<GenesisConfig>, String>
Some({
let mut properties = chain_spec_properties();
properties.insert(
"potInitialKey".to_string(),
"potExternalEntropy".to_string(),
serde_json::to_value(None::<PotKey>).expect("Serialization is not infallible; qed"),
);
properties
Expand Down Expand Up @@ -271,7 +271,7 @@ pub fn devnet_config_compiled() -> Result<ConsensusChainSpec<GenesisConfig>, Str
Some({
let mut properties = chain_spec_properties();
properties.insert(
"potInitialKey".to_string(),
"potExternalEntropy".to_string(),
serde_json::to_value(None::<PotKey>).expect("Serialization is not infallible; qed"),
);
properties
Expand Down Expand Up @@ -326,7 +326,7 @@ pub fn dev_config() -> Result<ConsensusChainSpec<GenesisConfig>, String> {
Some({
let mut properties = chain_spec_properties();
properties.insert(
"potInitialKey".to_string(),
"potExternalEntropy".to_string(),
serde_json::to_value(None::<PotKey>).expect("Serialization is not infallible; qed"),
);
properties
Expand Down Expand Up @@ -389,7 +389,7 @@ pub fn local_config() -> Result<ConsensusChainSpec<GenesisConfig>, String> {
Some({
let mut properties = chain_spec_properties();
properties.insert(
"potInitialKey".to_string(),
"potExternalEntropy".to_string(),
serde_json::to_value(None::<PotKey>).expect("Serialization is not infallible; qed"),
);
properties
Expand Down
15 changes: 8 additions & 7 deletions crates/subspace-node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ use sc_telemetry::serde_json;
use serde_json::Value;
use std::io::Write;
use std::{fs, io};
#[cfg(feature = "pot")]
use subspace_core_primitives::PotKey;
use subspace_networking::libp2p::Multiaddr;

/// Executor dispatch for subspace runtime
Expand Down Expand Up @@ -180,6 +178,11 @@ pub enum Subcommand {
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
}

#[cfg(feature = "pot")]
fn parse_pot_external_entropy(s: &str) -> Result<Vec<u8>, hex::FromHexError> {
hex::decode(s)
}

/// Subspace Cli.
#[derive(Debug, Parser)]
#[clap(
Expand Down Expand Up @@ -265,12 +268,10 @@ pub struct Cli {
#[cfg(feature = "pot")]
pub timekeeper: bool,

/// Initial PoT key (unless specified in chain spec already).
///
/// Key is a 16-byte hex string.
#[arg(long)]
/// External entropy, used initially when PoT chain starts to derive the first seed
#[arg(long, value_parser = parse_pot_external_entropy)]
#[cfg(feature = "pot")]
pub pot_initial_key: Option<PotKey>,
pub pot_external_entropy: Option<Vec<u8>>,
}

impl SubstrateCli for Cli {
Expand Down
13 changes: 5 additions & 8 deletions crates/subspace-proof-of-time/benches/pot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,32 @@ use core::num::NonZeroU32;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::{thread_rng, Rng};
use std::num::NonZeroU64;
use subspace_core_primitives::{PotKey, PotSeed};
use subspace_core_primitives::PotSeed;
use subspace_proof_of_time::{prove, verify};

fn criterion_benchmark(c: &mut Criterion) {
let mut seed = PotSeed::default();
thread_rng().fill(seed.as_mut());
let mut key = PotKey::default();
thread_rng().fill(key.as_mut());
// About 1s on 5.5 GHz Raptor Lake CPU
let pot_iterations = NonZeroU32::new(183_270_000).expect("Not zero; qed");

c.bench_function("prove", |b| {
b.iter(|| {
prove(black_box(seed), black_box(key), black_box(pot_iterations)).unwrap();
black_box(prove(black_box(seed), black_box(pot_iterations))).unwrap();
})
});

let checkpoints = prove(seed, key, pot_iterations).unwrap();
let checkpoints = prove(seed, pot_iterations).unwrap();

let pot_iterations = NonZeroU64::from(pot_iterations);

c.bench_function("verify", |b| {
b.iter(|| {
verify(
black_box(verify(
black_box(seed),
black_box(key),
black_box(pot_iterations),
black_box(&*checkpoints),
)
))
.unwrap();
})
});
Expand Down
Loading