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

Sassafras Protocol v0.3.2 #14139

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9375040
Introduce bandersnatch-vrfs (temporary)
davxy Apr 11, 2023
3016fd8
Merge branch 'master' into davxy-bandersnatch-vrf
davxy Apr 19, 2023
74e1aca
Align to last bandersnatch-vrf crate iteration
davxy Apr 19, 2023
9273581
Implementation of sign/verify methods
davxy Apr 20, 2023
09d2d41
Bandersnatch keystore integration
davxy Apr 21, 2023
fbd3e7a
Application crypto
davxy Apr 21, 2023
b038d9e
Global const signing context
davxy Apr 21, 2023
7b31bcd
make_bytes skeleton
davxy Apr 21, 2023
e258c1c
Remove cruft
davxy Apr 21, 2023
89e35e4
Merge branch 'master' into davxy-bandersnatch-vrf
davxy Apr 22, 2023
95c0358
Fix after master merge
davxy Apr 22, 2023
7d8c71a
Manage multiple VRF inputs
davxy Apr 25, 2023
1b2da2c
Disable std feature
davxy Apr 27, 2023
b88cba8
Merge branch 'master' into davxy-bandersnatch-vrf
davxy May 4, 2023
5ef6ed9
Fix after master merge
davxy May 4, 2023
80c9f0a
Patch no-std compatible w3f crates
davxy May 4, 2023
078b8cd
Merge branch 'master' into davxy-bandersnatch-vrf
davxy May 11, 2023
dc324db
put bandersnatch under experimental flag
davxy May 11, 2023
b02fc4b
point to patched repo
davxy May 11, 2023
216d7fc
Merge branch 'master' into davxy-bandersnatch-vrf
davxy May 11, 2023
59798e0
Bump sassafras version crates to v0.3.2-dev
davxy May 12, 2023
1a3dc5d
Integrate bandersnatch vrf
davxy May 12, 2023
030c7f9
Integration for pallet and primitives
davxy May 13, 2023
fc5a735
Use next epoch params for ticket check
davxy May 15, 2023
0fc66cc
Merge branch 'master' into sassafras-protocol-v32
davxy May 15, 2023
7ef968c
Fix frame tests after vrf upgrade
davxy May 15, 2023
8332ff8
Merge branch 'davxy-sassafras-protocol' into sassafras-protocol-v32
davxy May 15, 2023
4f0c37d
Bandersnatch tests keyring
davxy May 16, 2023
fd95365
Test for genesis config storage
davxy May 16, 2023
15b5ada
Fix authorities creation for bandersnatch keys
davxy May 16, 2023
29b8b2b
Introduce ed25519 erased signature
davxy May 16, 2023
ad29487
Proper data for erased signature
davxy May 18, 2023
819bc42
Fix tests
davxy May 18, 2023
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
356 changes: 244 additions & 112 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -338,3 +338,6 @@ inherits = "release"
lto = "fat"
# https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units
codegen-units = 1

#[patch."https://github.com/w3f/ring-vrf"]
# bandersnatch_vrfs = { path = "/mnt/ssd/users/develop/w3f/ring-vrf/bandersnatch_vrfs" }
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.1-dev"
version = "0.3.2-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.1-dev", path = "../../../client/consensus/sassafras" }
sp-consensus-sassafras = { version = "0.3.1-dev", path = "../../../primitives/consensus/sassafras" }
sc-consensus-sassafras = { version = "0.3.2-dev", path = "../../../client/consensus/sassafras" }
sp-consensus-sassafras = { version = "0.3.2-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.1-dev", path = "../runtime" }
node-sassafras-runtime = { version = "0.3.2-dev", path = "../runtime" }

# CLI-specific dependencies
try-runtime-cli = { version = "0.10.0-dev", optional = true, path = "../../../utils/frame/try-runtime/cli" }
Expand Down
2 changes: 1 addition & 1 deletion 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 = 32;
const SASSAFRAS_TICKETS_MAX_ATTEMPTS_NUMBER: u32 = 16;
const SASSAFRAS_TICKETS_REDUNDANCY_FACTOR: u32 = 1;

/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
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.1-dev"
version = "0.3.2-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.1-dev", default-features = false, path = "../../../frame/sassafras" }
pallet-sassafras = { version = "0.3.2-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 @@ -28,7 +28,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.1-dev", default-features = false, path = "../../../primitives/consensus/sassafras" }
sp-consensus-sassafras = { version = "0.3.2-dev", default-features = false, path = "../../../primitives/consensus/sassafras" }
sp-core = { version = "7.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
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.1-dev"
version = "0.3.2-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 = "7.0.0", path = "../../../primitives/applica
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.1-dev", path = "../../../primitives/consensus/sassafras" }
sp-consensus-sassafras = { version = "0.3.2-dev", path = "../../../primitives/consensus/sassafras" }
sp-consensus-slots = { version = "0.10.0-dev", path = "../../../primitives/consensus/slots" }
sp-core = { version = "7.0.0", path = "../../../primitives/core" }
sp-inherents = { version = "4.0.0-dev", path = "../../../primitives/inherents" }
Expand Down
61 changes: 33 additions & 28 deletions client/consensus/sassafras/src/authorship.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
use super::*;

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

use std::pin::Pin;

Expand All @@ -41,7 +41,7 @@ pub(crate) fn secondary_authority_index(
/// If ticket is `None`, then the slot should be claimed using the fallback mechanism.
pub(crate) fn claim_slot(
slot: Slot,
epoch: &Epoch,
epoch: &mut Epoch,
maybe_ticket: Option<(TicketId, TicketData)>,
keystore: &KeystorePtr,
) -> Option<(PreDigest, AuthorityId)> {
Expand All @@ -51,34 +51,38 @@ pub(crate) fn claim_slot(
return None
}

let mut vrf_sign_data = slot_claim_sign_data(&config.randomness, slot, epoch.epoch_idx);

let (authority_idx, ticket_claim) = match maybe_ticket {
Some((ticket_id, ticket_data)) => {
log::debug!(target: LOG_TARGET, "[TRY PRIMARY]");
let (authority_idx, ticket_secret) = epoch.tickets_aux.get(&ticket_id)?.clone();
log::debug!(target: LOG_TARGET, "[TRY PRIMARY (slot {slot}, tkt = {ticket_id:16x})]");
let (authority_idx, ticket_secret) = epoch.tickets_aux.remove(&ticket_id)?.clone();
log::debug!(
target: LOG_TARGET,
"Ticket = [ticket: {:x?}, auth: {}, attempt: {}]",
ticket_id,
" got ticket: auth: {}, attempt: {}",
authority_idx,
ticket_data.attempt_idx
);
// TODO DAVXY : using ticket_secret
let _ = ticket_secret;
let erased_signature = [0; 64];

vrf_sign_data.push_transcript_data(&ticket_data.encode());

let data = vrf_sign_data.challenge::<32>();
let erased_pair = ed25519::Pair::from_seed(&ticket_secret.erased_secret);
let erased_signature = *erased_pair.sign(&data).as_ref();

let claim = TicketClaim { erased_signature };
(authority_idx, Some(claim))
},
None => {
log::debug!(target: LOG_TARGET, "[TRY SECONDARY]");
log::debug!(target: LOG_TARGET, "[TRY SECONDARY (slot {slot})]");
(secondary_authority_index(slot, config), None)
},
};

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

let vrf_input = slot_claim_vrf_input(&config.randomness, slot, epoch.epoch_idx);
let vrf_signature = keystore
.sr25519_vrf_sign(AuthorityId::ID, authority_id.as_ref(), &vrf_input.into())
.bandersnatch_vrf_sign(AuthorityId::ID, authority_id.as_ref(), &vrf_sign_data)
.ok()
.flatten()?;

Expand All @@ -103,7 +107,8 @@ fn generate_epoch_tickets(epoch: &mut Epoch, keystore: &KeystorePtr) -> Vec<Tick
config.authorities.len() as u32,
);
// TODO-SASS-P4 remove me
log::debug!(target: LOG_TARGET, "Tickets threshold: {:016x}", threshold);
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 {
Expand All @@ -115,31 +120,32 @@ fn generate_epoch_tickets(epoch: &mut Epoch, keystore: &KeystorePtr) -> Vec<Tick
let vrf_input = ticket_id_vrf_input(&config.randomness, attempt_idx, epoch.epoch_idx);

let vrf_preout = keystore
.sr25519_vrf_output(AuthorityId::ID, authority_id.as_ref(), &vrf_input)
.bandersnatch_vrf_output(AuthorityId::ID, authority_id.as_ref(), &vrf_input)
.ok()??;

let ticket_id = ticket_id(&vrf_input, &vrf_preout);
if ticket_id >= threshold {
return None
}

// TODO DAVXY: compute proper erased_secret/public and revealed_public
let erased_secret = [0; 32];
let erased_public = [0; 32];
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 };

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

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

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

for attempt in 0..max_attempts {
if let Some((envelope, ticket_id, 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));
Expand Down Expand Up @@ -220,21 +226,16 @@ where
slot: Slot,
epoch_descriptor: &ViableEpochDescriptor<B::Hash, NumberFor<B>, Epoch>,
) -> Option<Self::Claim> {
debug!(target: LOG_TARGET, "Attempting to claim slot {}", slot);

// Get the next slot ticket from the runtime.
let maybe_ticket =
self.client.runtime_api().slot_ticket(parent_header.hash(), slot).ok()?;

// TODO-SASS-P2: remove me
debug!(target: LOG_TARGET, "parent {}", parent_header.hash());
let mut epoch_changes = self.epoch_changes.shared_data_locked();
let mut epoch = epoch_changes.viable_epoch_mut(epoch_descriptor, |slot| Epoch::genesis(&self.genesis_config, slot))?;

let claim = authorship::claim_slot(
slot,
self.epoch_changes
.shared_data()
.viable_epoch(epoch_descriptor, |slot| Epoch::genesis(&self.genesis_config, slot))?
.as_ref(),
&mut epoch.as_mut(),
maybe_ticket,
&self.keystore,
);
Expand Down Expand Up @@ -282,6 +283,10 @@ where
// TODO DAVXY SASS-32: this seal may be revisited.
// We already have a VRF signature, this could be completelly redundant.
// The header.hash() can be added to the VRF signed data.
// OR maybe we can maintain this seal but compute it using some of the data in the
// pre-digest
// Another option is to not recompute this signature and push (reuse) the one in the
// pre-digest as the seal
let signature = self
.keystore
.sign_with(
Expand Down
13 changes: 6 additions & 7 deletions client/consensus/sassafras/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ use sp_runtime::{
pub use sp_consensus_sassafras::{
digests::{CompatibleDigestItem, ConsensusLog, NextEpochDescriptor, PreDigest},
inherents::SassafrasInherentData,
slot_claim_vrf_input, ticket_id_vrf_input, AuthorityId, AuthorityIndex, AuthorityPair,
AuthoritySignature, SassafrasApi, SassafrasAuthorityWeight, SassafrasConfiguration,
SassafrasEpochConfiguration, TicketClaim, TicketData, TicketEnvelope, TicketId, TicketSecret,
RANDOMNESS_LENGTH, SASSAFRAS_ENGINE_ID,
slot_claim_sign_data, slot_claim_vrf_input, ticket_id_vrf_input, AuthorityId, AuthorityIndex,
AuthorityPair, AuthoritySignature, SassafrasApi, SassafrasAuthorityWeight,
SassafrasConfiguration, SassafrasEpochConfiguration, TicketClaim, TicketData, TicketEnvelope,
TicketId, TicketSecret, RANDOMNESS_LENGTH, SASSAFRAS_ENGINE_ID,
};

mod authorship;
Expand Down Expand Up @@ -284,11 +284,10 @@ fn find_pre_digest<B: BlockT>(header: &B::Header) -> Result<PreDigest, Error<B>>
if header.number().is_zero() {
// Genesis block doesn't contain a pre digest so let's generate a
// dummy one to not break any invariants in the rest of the code
use sp_consensus_sassafras::VrfInput;
use sp_core::crypto::VrfSecret;
let pair = sp_consensus_sassafras::AuthorityPair::from_seed(&[0u8; 32]);
let input = VrfInput::new(b"", &[]);
let vrf_signature = pair.as_ref().vrf_sign(&input.into());
let data = sp_consensus_sassafras::slot_claim_sign_data(&Default::default(), 0.into(), 0);
let vrf_signature = pair.as_ref().vrf_sign(&data);
return Ok(PreDigest { authority_idx: 0, slot: 0.into(), ticket_claim: None, vrf_signature })
}

Expand Down
Loading