Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Sassafras protocol v0.3.3 (#14362)
Browse files Browse the repository at this point in the history
- bump version to 0.3.3
- integration of ring-vrf with zk ring proof crypto primitive
- tickets authoring and verification via ring zk proof
  • Loading branch information
davxy authored Jun 16, 2023
1 parent 1074d37 commit 0f148d7
Show file tree
Hide file tree
Showing 29 changed files with 661 additions and 174 deletions.
29 changes: 13 additions & 16 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,7 @@ common = { git = "https://github.com/davxy/ring-proof", branch = "working-fork"
ring = { git = "https://github.com/davxy/ring-proof", branch = "working-fork" }
# common = { path = "/mnt/ssd/develop/w3f/ring-proof/common" }
# ring = { path = "/mnt/ssd/develop/w3f/ring-proof/ring" }

[patch.crates-io]
#parity-scale-codec = { git = "https://github.com/koute/parity-scale-codec", branch = "master_fix_stack_overflow" }
codec = { package = "parity-scale-codec", git = "https://github.com/koute/parity-scale-codec", branch = "master_fix_stack_overflow" }
8 changes: 4 additions & 4 deletions bin/node-sassafras/node/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "node-sassafras"
version = "0.3.2-dev"
version = "0.3.3-dev"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Node testbed for Sassafras consensus."
homepage = "https://substrate.io/"
Expand All @@ -27,8 +27,8 @@ sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" }
sc-keystore = { version = "4.0.0-dev", path = "../../../client/keystore" }
sc-transaction-pool = { version = "4.0.0-dev", path = "../../../client/transaction-pool" }
sc-transaction-pool-api = { version = "4.0.0-dev", path = "../../../client/transaction-pool/api" }
sc-consensus-sassafras = { version = "0.3.2-dev", path = "../../../client/consensus/sassafras" }
sp-consensus-sassafras = { version = "0.3.2-dev", path = "../../../primitives/consensus/sassafras" }
sc-consensus-sassafras = { version = "0.3.3-dev", path = "../../../client/consensus/sassafras" }
sp-consensus-sassafras = { version = "0.3.3-dev", path = "../../../primitives/consensus/sassafras" }
sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" }
sc-consensus = { version = "0.10.0-dev", path = "../../../client/consensus/common" }
sc-consensus-grandpa = { version = "0.10.0-dev", path = "../../../client/consensus/grandpa" }
Expand Down Expand Up @@ -57,7 +57,7 @@ frame-benchmarking = { version = "4.0.0-dev", path = "../../../frame/benchmarkin
frame-benchmarking-cli = { version = "4.0.0-dev", path = "../../../utils/frame/benchmarking-cli" }

# Local Dependencies
node-sassafras-runtime = { version = "0.3.2-dev", path = "../runtime" }
node-sassafras-runtime = { version = "0.3.3-dev", path = "../runtime" }

[build-dependencies]
substrate-build-script-utils = { version = "3.0.0", path = "../../../utils/build-script-utils" }
Expand Down
6 changes: 3 additions & 3 deletions bin/node-sassafras/node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use sp_core::{sr25519, Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};

// Genesis constants for Sassafras parameters configuration.
const SASSAFRAS_TICKETS_MAX_ATTEMPTS_NUMBER: u32 = 16;
const SASSAFRAS_TICKETS_MAX_ATTEMPTS_NUMBER: u32 = 8;
const SASSAFRAS_TICKETS_REDUNDANCY_FACTOR: u32 = 1;

/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
Expand Down Expand Up @@ -127,9 +127,9 @@ fn testnet_genesis(
},
sassafras: SassafrasConfig {
#[cfg(feature = "use-session-pallet")]
authorities: vec![],
authorities: Vec::new(),
#[cfg(not(feature = "use-session-pallet"))]
authorities: initial_authorities.iter().map(|x| (x.1.clone(), 0)).collect(),
authorities: initial_authorities.iter().map(|x| x.1.clone()).collect(),
epoch_config: SassafrasEpochConfiguration {
attempts_number: SASSAFRAS_TICKETS_MAX_ATTEMPTS_NUMBER,
redundancy_factor: SASSAFRAS_TICKETS_REDUNDANCY_FACTOR,
Expand Down
6 changes: 3 additions & 3 deletions bin/node-sassafras/runtime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "node-sassafras-runtime"
version = "0.3.2-dev"
version = "0.3.3-dev"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Runtime testbed for Sassafras consensus."
homepage = "https://substrate.io/"
Expand All @@ -15,7 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }

pallet-sassafras = { version = "0.3.2-dev", default-features = false, path = "../../../frame/sassafras" }
pallet-sassafras = { version = "0.3.3-dev", default-features = false, path = "../../../frame/sassafras" }
pallet-balances = { version = "4.0.0-dev", default-features = false, path = "../../../frame/balances" }
pallet-session = { version = "4.0.0-dev", default-features = false, path = "../../../frame/session" }
frame-support = { version = "4.0.0-dev", default-features = false, path = "../../../frame/support" }
Expand All @@ -27,7 +27,7 @@ pallet-transaction-payment = { version = "4.0.0-dev", default-features = false,
frame-executive = { version = "4.0.0-dev", default-features = false, path = "../../../frame/executive" }
sp-api = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/api" }
sp-block-builder = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/block-builder"}
sp-consensus-sassafras = { version = "0.3.2-dev", default-features = false, path = "../../../primitives/consensus/sassafras" }
sp-consensus-sassafras = { version = "0.3.3-dev", default-features = false, path = "../../../primitives/consensus/sassafras" }
sp-core = { version = "21.0.0", default-features = false, path = "../../../primitives/core" }
sp-inherents = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/inherents"}
sp-offchain = { version = "4.0.0-dev", default-features = false, path = "../../../primitives/offchain" }
Expand Down
6 changes: 5 additions & 1 deletion bin/node-sassafras/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,10 @@ impl_runtime_apis! {
}

impl sp_consensus_sassafras::SassafrasApi<Block> for Runtime {
fn ring_context() -> Option<sp_consensus_sassafras::RingVrfContext> {
Sassafras::ring_context()
}

fn submit_tickets_unsigned_extrinsic(
tickets: Vec<sp_consensus_sassafras::TicketEnvelope>
) -> bool {
Expand All @@ -397,7 +401,7 @@ impl_runtime_apis! {
Sassafras::slot_ticket_id(slot)
}

fn slot_ticket(slot: sp_consensus_sassafras::Slot) -> Option<(sp_consensus_sassafras::TicketId, sp_consensus_sassafras::TicketData)> {
fn slot_ticket(slot: sp_consensus_sassafras::Slot) -> Option<(sp_consensus_sassafras::TicketId, sp_consensus_sassafras::TicketBody)> {
Sassafras::slot_ticket(slot)
}

Expand Down
4 changes: 2 additions & 2 deletions client/consensus/sassafras/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sc-consensus-sassafras"
version = "0.3.2-dev"
version = "0.3.3-dev"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Sassafras consensus algorithm for substrate"
edition = "2021"
Expand Down Expand Up @@ -32,7 +32,7 @@ sp-application-crypto = { version = "23.0.0", path = "../../../primitives/applic
sp-block-builder = { version = "4.0.0-dev", path = "../../../primitives/block-builder" }
sp-blockchain = { version = "4.0.0-dev", path = "../../../primitives/blockchain" }
sp-consensus = { version = "0.10.0-dev", path = "../../../primitives/consensus/common" }
sp-consensus-sassafras = { version = "0.3.2-dev", path = "../../../primitives/consensus/sassafras" }
sp-consensus-sassafras = { version = "0.3.3-dev", path = "../../../primitives/consensus/sassafras" }
sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" }
sp-core = { version = "21.0.0", path = "../../../primitives/core" }
sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" }
Expand Down
77 changes: 55 additions & 22 deletions client/consensus/sassafras/src/authorship.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,9 @@ use super::*;

use sp_consensus_sassafras::{
digests::PreDigest, slot_claim_sign_data, ticket_id, ticket_id_threshold, AuthorityId, Slot,
TicketClaim, TicketData, TicketEnvelope, TicketId,
TicketBody, TicketClaim, TicketEnvelope, TicketId,
};
use sp_core::{ed25519, twox_64, ByteArray};

use sp_core::{bandersnatch::ring_vrf::RingVrfContext, ed25519, twox_64, ByteArray};
use std::pin::Pin;

/// Get secondary authority index for the given epoch and slot.
Expand All @@ -42,7 +41,7 @@ pub(crate) fn secondary_authority_index(
pub(crate) fn claim_slot(
slot: Slot,
epoch: &mut Epoch,
maybe_ticket: Option<(TicketId, TicketData)>,
maybe_ticket: Option<(TicketId, TicketBody)>,
keystore: &KeystorePtr,
) -> Option<(PreDigest, AuthorityId)> {
let config = &epoch.config;
Expand Down Expand Up @@ -79,7 +78,7 @@ pub(crate) fn claim_slot(
},
};

let authority_id = config.authorities.get(authority_idx as usize).map(|auth| &auth.0)?;
let authority_id = config.authorities.get(authority_idx as usize)?;

let vrf_signature = keystore
.bandersnatch_vrf_sign(AuthorityId::ID, authority_id.as_ref(), &vrf_sign_data)
Expand All @@ -92,9 +91,14 @@ pub(crate) fn claim_slot(
}

/// Generate the tickets for the given epoch.
///
/// Tickets additional information will be stored within the `Epoch` structure.
/// The additional information will be used later during session to claim slots.
fn generate_epoch_tickets(epoch: &mut Epoch, keystore: &KeystorePtr) -> Vec<TicketEnvelope> {
/// The additional information will be used later during the epoch to claim slots.
fn generate_epoch_tickets(
epoch: &mut Epoch,
keystore: &KeystorePtr,
ring_ctx: &RingVrfContext,
) -> Vec<TicketEnvelope> {
let config = &epoch.config;
let max_attempts = config.threshold_params.attempts_number;
let redundancy_factor = config.threshold_params.redundancy_factor;
Expand All @@ -110,12 +114,18 @@ fn generate_epoch_tickets(epoch: &mut Epoch, keystore: &KeystorePtr) -> Vec<Tick
log::debug!(target: LOG_TARGET, "Generating tickets for epoch {} @ slot {}", epoch.epoch_idx, epoch.start_slot);
log::debug!(target: LOG_TARGET, " threshold: {threshold:016x}");

let authorities = config.authorities.iter().enumerate().map(|(index, a)| (index, &a.0));
for (authority_idx, authority_id) in authorities {
// We need a list of raw unwrapped keys
let pks: Vec<_> = config.authorities.iter().map(|a| *a.as_ref()).collect();

for (authority_idx, authority_id) in config.authorities.iter().enumerate() {
if !keystore.has_keys(&[(authority_id.to_raw_vec(), AuthorityId::ID)]) {
continue
}

debug!(target: LOG_TARGET, ">>> Generating new ring prover key...");
let prover = ring_ctx.prover(&pks, authority_idx).unwrap();
debug!(target: LOG_TARGET, ">>> ...done");

let make_ticket = |attempt_idx| {
let vrf_input = ticket_id_vrf_input(&config.randomness, attempt_idx, epoch.epoch_idx);

Expand All @@ -131,25 +141,36 @@ fn generate_epoch_tickets(epoch: &mut Epoch, keystore: &KeystorePtr) -> Vec<Tick
let (erased_pair, erased_seed) = ed25519::Pair::generate();

let erased_public: [u8; 32] = *erased_pair.public().as_ref();
let revealed_public = [0; 32];
let data = TicketData { attempt_idx, erased_public, revealed_public };
let ticket_body = TicketBody { attempt_idx, erased_public };

debug!(target: LOG_TARGET, ">>> Creating ring proof for attempt {}", attempt_idx);
let mut sign_data = ticket_body_sign_data(&ticket_body);
sign_data.push_vrf_input(vrf_input).expect("Can't fail");

let ring_signature = keystore
.bandersnatch_ring_vrf_sign(
AuthorityId::ID,
authority_id.as_ref(),
&sign_data,
&prover,
)
.ok()??;
debug!(target: LOG_TARGET, ">>> ...done");

// TODO DAVXY: placeholder
let ring_proof = ();
let ticket_envelope = TicketEnvelope { data, vrf_preout, ring_proof };
let ticket_envelope = TicketEnvelope { body: ticket_body, ring_signature };

let ticket_secret = TicketSecret { attempt_idx, erased_secret: erased_seed };

Some((ticket_envelope, ticket_id, ticket_secret))
Some((ticket_id, ticket_envelope, ticket_secret))
};

for attempt in 0..max_attempts {
if let Some((envelope, ticket_id, ticket_secret)) = make_ticket(attempt) {
if let Some((ticket_id, ticket_envelope, ticket_secret)) = make_ticket(attempt) {
log::debug!(target: LOG_TARGET, " → {ticket_id:016x}");
epoch
.tickets_aux
.insert(ticket_id, (authority_idx as AuthorityIndex, ticket_secret));
tickets.push(envelope);
tickets.push(ticket_envelope);
}
}
}
Expand Down Expand Up @@ -415,11 +436,6 @@ async fn start_tickets_worker<B, C, SC>(
},
};

let tickets = generate_epoch_tickets(&mut epoch, &keystore);
if tickets.is_empty() {
continue
}

// Get the best block on which we will publish the tickets.
let best_hash = match select_chain.best_chain().await {
Ok(header) => header.hash(),
Expand All @@ -429,6 +445,23 @@ async fn start_tickets_worker<B, C, SC>(
},
};

let ring_ctx = match client.runtime_api().ring_context(best_hash) {
Ok(Some(ctx)) => ctx,
Ok(None) => {
info!(target: LOG_TARGET, "Ring context not initialized yet");
continue
},
Err(err) => {
error!(target: LOG_TARGET, "Unable to read ring context: {}", err);
continue
},
};

let tickets = generate_epoch_tickets(&mut epoch, &keystore, &ring_ctx);
if tickets.is_empty() {
continue
}

let err = match client.runtime_api().submit_tickets_unsigned_extrinsic(best_hash, tickets) {
Err(err) => Some(err.to_string()),
Ok(false) => Some("Unknown reason".to_string()),
Expand Down
6 changes: 3 additions & 3 deletions client/consensus/sassafras/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ use sp_runtime::{
pub use sp_consensus_sassafras::{
digests::{CompatibleDigestItem, ConsensusLog, NextEpochDescriptor, PreDigest},
inherents::SassafrasInherentData,
slot_claim_sign_data, slot_claim_vrf_input, ticket_id_vrf_input, AuthorityId, AuthorityIndex,
AuthorityPair, AuthoritySignature, SassafrasApi, SassafrasAuthorityWeight,
SassafrasConfiguration, SassafrasEpochConfiguration, TicketClaim, TicketData, TicketEnvelope,
slot_claim_sign_data, slot_claim_vrf_input, ticket_body_sign_data, ticket_id_vrf_input,
AuthorityId, AuthorityIndex, AuthorityPair, AuthoritySignature, SassafrasApi,
SassafrasConfiguration, SassafrasEpochConfiguration, TicketBody, TicketClaim, TicketEnvelope,
TicketId, TicketSecret, RANDOMNESS_LENGTH, SASSAFRAS_ENGINE_ID,
};

Expand Down
Loading

0 comments on commit 0f148d7

Please sign in to comment.