Skip to content

Commit

Permalink
Restore Sassafras (#2585)
Browse files Browse the repository at this point in the history
Revive outdated Sassafras
  • Loading branch information
davxy authored Dec 5, 2023
1 parent 46bfecc commit 15859f7
Show file tree
Hide file tree
Showing 21 changed files with 129 additions and 83 deletions.
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.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -552,15 +552,15 @@ yamux = { opt-level = 3 }
zeroize = { opt-level = 3 }

# [patch."/~https://github.com/w3f/ring-vrf"]
# bandersnatch_vrfs = { git = "/~https://github.com/davxy/ring-vrf", branch = "davxy-patch" }
# # bandersnatch_vrfs = { git = "/~https://github.com/davxy/ring-vrf", branch = "davxy-patch" }
# bandersnatch_vrfs = { path = "../../w3f/ring-vrf/bandersnatch_vrfs" }

# [patch."/~https://github.com/w3f/ring-proof"]
# ring = { git = "/~https://github.com/davxy/ring-proof", branch = "davxy-patch" }
# common = { git = "/~https://github.com/davxy/ring-proof", branch = "davxy-patch" }
# # ring = { git = "/~https://github.com/davxy/ring-proof", branch = "davxy-patch" }
# # common = { git = "/~https://github.com/davxy/ring-proof", branch = "davxy-patch" }
# ring = { path = "../../w3f/ring-proof/ring" }
# common = { path = "../../w3f/ring-proof/common" }

# [patch."/~https://github.com/w3f/fflonk"]
# fflonk = { git = "/~https://github.com/davxy/fflonk", branch = "davxy-patch" }
# # fflonk = { git = "/~https://github.com/davxy/fflonk", branch = "davxy-patch" }
# fflonk = { path = "../../w3f/fflonk" }
38 changes: 38 additions & 0 deletions benchmark.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#!/bin/bash

binary="./target/release/node-sassafras"

steps=20
repeat=3

export RUST_LOG="sassafras=debug"

pallet='pallet_sassafras'

extrinsic=$1

if [[ $extrinsic == "" ]]; then
list=$($binary benchmark pallet --list | grep $pallet | cut -d ',' -f 2)

echo "Usage: $0 <benchmark>"
echo ""
echo "Available benchmarks:"
for bench in $list; do
echo "- $bench"
done
echo "- all"
exit
fi

if [[ $extrinsic == "all" ]]; then
extrinsic='*'
fi

$binary benchmark pallet \
--chain dev \
--pallet $pallet \
--extrinsic "$extrinsic" \
--steps $steps \
--repeat $repeat \
--output weights.rs \
--template substrate/.maintain/frame-weight-template.hbs
5 changes: 5 additions & 0 deletions substrate/bin/node-sassafras/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ substrate-build-script-utils = { path = "../../../utils/build-script-utils" }
[features]
default = []
runtime-benchmarks = [
"frame-benchmarking-cli/runtime-benchmarks",
"frame-benchmarking/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"node-sassafras-runtime/runtime-benchmarks",
"sc-service/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
use-session-pallet = [
"node-sassafras-runtime/use-session-pallet",
Expand Down
8 changes: 7 additions & 1 deletion substrate/bin/node-sassafras/node/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,13 @@ fn testnet_genesis(
"balances": {
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
},
"session": SessionConfig {
"sassafras": {
"epochConfig": sp_consensus_sassafras::EpochConfiguration {
attempts_number: SASSAFRAS_TICKETS_MAX_ATTEMPTS_NUMBER,
redundancy_factor: SASSAFRAS_TICKETS_REDUNDANCY_FACTOR,
},
},
"session": {
"keys": initial_authorities
.iter()
.map(|x| {
Expand Down
4 changes: 4 additions & 0 deletions substrate/bin/node-sassafras/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@ substrate-wasm-builder = { path = "../../../utils/wasm-builder" }
default = ["std"]
std = [
"codec/std",
"frame-benchmarking/std",
"frame-executive/std",
"frame-support/std",
"frame-system-benchmarking/std",
"frame-system-rpc-runtime-api/std",
"frame-system/std",
"pallet-balances/std",
Expand All @@ -77,6 +79,7 @@ std = [
"sp-runtime/std",
"sp-session/std",
"sp-std/std",
"sp-storage/std",
"sp-transaction-pool/std",
"sp-version/std",
]
Expand All @@ -88,6 +91,7 @@ runtime-benchmarks = [
"pallet-balances/runtime-benchmarks",
"pallet-grandpa/runtime-benchmarks",
"pallet-sassafras/runtime-benchmarks",
"pallet-sudo/runtime-benchmarks",
"pallet-timestamp/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
Expand Down
2 changes: 1 addition & 1 deletion substrate/client/consensus/sassafras/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ sp-inherents = { path = "../../../primitives/inherents" }
sp-keystore = { path = "../../../primitives/keystore" }
sp-runtime = { path = "../../../primitives/runtime" }
sp-timestamp = { path = "../../../primitives/timestamp" }
env_logger = "0.10.0"

[dev-dependencies]
sc-block-builder = { path = "../../block-builder" }
Expand All @@ -50,3 +49,4 @@ sc-network-test = { path = "../../network/test" }
sp-keyring = { path = "../../../primitives/keyring" }
substrate-test-runtime-client = { path = "../../../test-utils/runtime/client" }
tokio = "1.22.0"
env_logger = "0.10.1"
12 changes: 5 additions & 7 deletions substrate/client/consensus/sassafras/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
Client module for Sassafras consensus
Client module for SASSAFRAS consensus

# ⚠️ WARNING ⚠️

The crate interfaces and structures are highly experimental and may be subject
to significant changes.
- Tracking issue: /~https://github.com/paritytech/polkadot-sdk/issues/41
- Protocol RFC proposal: /~https://github.com/polkadot-fellows/RFCs/pull/26

Depends on upstream experimental feature: `bandersnatch-experimental`.
# ⚠️ WARNING ⚠️

Tracking issue: /~https://github.com/paritytech/polkadot-sdk/issues/41
The crate interfaces and structures are experimental and may be subject to changes.
6 changes: 3 additions & 3 deletions substrate/client/consensus/sassafras/src/authorship.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ use sp_consensus_sassafras::{
digests::SlotClaim, ticket_id_threshold, vrf::RingContext, AuthorityId, Slot, TicketBody,
TicketClaim, TicketEnvelope, TicketId,
};
use sp_core::{ed25519::Pair as EphemeralPair, twox_64, ByteArray};
use sp_core::{ed25519::Pair as EphemeralPair, hashing::blake2_64, ByteArray};
use std::pin::Pin;

/// Get secondary authority index for the given epoch and slot.
pub(crate) fn secondary_authority_index(slot: Slot, epoch: &Epoch) -> AuthorityIndex {
// TODO @davxy twox -> blake2
u64::from_le_bytes((epoch.randomness, slot).using_encoded(twox_64)) as AuthorityIndex %
epoch.authorities.len() as AuthorityIndex
let hash = u64::from_le_bytes((epoch.randomness, slot).using_encoded(blake2_64));
(hash % epoch.authorities.len() as u64) as AuthorityIndex
}

/// Try to claim an epoch slot.
Expand Down
68 changes: 35 additions & 33 deletions substrate/client/consensus/sassafras/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use super::*;
use futures::executor::block_on;
use std::sync::Arc;

use sc_block_builder::BlockBuilderProvider;
use sc_block_builder::BlockBuilderBuilder;
use sc_client_api::Finalizer;
use sc_consensus::{BlockImport, BoxJustificationImport};
use sc_network_test::*;
Expand Down Expand Up @@ -83,10 +83,10 @@ type SassafrasVerifier = crate::SassafrasVerifier<

type SassafrasLink = crate::SassafrasLink<TestBlock>;

// Epoch duration is slots
const EPOCH_DURATION: u64 = 6;
// Epoch length in slots
const EPOCH_LENGTH: u32 = 6;
// Slot duration is milliseconds
const SLOT_DURATION: u64 = 1000;
const SLOT_DURATION: SlotDuration = SlotDuration::from_millis(1000_u64);

struct TestProposer {
client: Arc<TestClient>,
Expand Down Expand Up @@ -114,8 +114,13 @@ impl Proposer<TestBlock> for TestProposer {
_: Duration,
_: Option<usize>,
) -> Self::Proposal {
let block_builder =
self.client.new_block_at(self.parent_hash, inherent_digests, false).unwrap();
let block_builder = BlockBuilderBuilder::new(&*self.client)
.on_parent_block(self.parent_hash)
.fetch_parent_block_number(&*self.client)
.unwrap()
.with_inherent_digests(inherent_digests)
.build()
.unwrap();

let block = match block_builder.build().map_err(|e| e.into()) {
Ok(b) => b.block,
Expand All @@ -140,9 +145,8 @@ fn create_test_verifier(
link: &SassafrasLink,
config: Epoch,
) -> SassafrasVerifier {
let slot_duration = config.slot_duration;
let create_inherent_data_providers = Box::new(move |_, _| async move {
let slot = InherentDataProvider::from_timestamp(Timestamp::current(), slot_duration);
let slot = InherentDataProvider::from_timestamp(Timestamp::current(), SLOT_DURATION);
Ok((slot,))
});

Expand Down Expand Up @@ -176,16 +180,15 @@ fn create_test_keystore(authority: Keyring) -> KeystorePtr {

fn create_test_epoch() -> Epoch {
sp_consensus_sassafras::Epoch {
epoch_idx: 0,
start_slot: 0.into(),
slot_duration: SlotDuration::from_millis(SLOT_DURATION),
epoch_duration: EPOCH_DURATION,
index: 0,
start: 0.into(),
length: EPOCH_LENGTH,
randomness: [0; 32],
authorities: vec![
Keyring::Alice.public().into(),
Keyring::Bob.public().into(),
Keyring::Charlie.public().into(),
],
randomness: [0; 32],
config: EpochConfiguration { redundancy_factor: 1, attempts_number: 32 },
}
.into()
Expand Down Expand Up @@ -296,7 +299,7 @@ impl TestContext {
// TODO @davxy: maybe here we can use the epoch.randomness???
let epoch = self.epoch_data(&parent_hash, parent_number, slot);
let sign_data =
vrf::slot_claim_sign_data(&self.link.genesis_config.randomness, slot, epoch.epoch_idx);
vrf::slot_claim_sign_data(&self.link.genesis_config.randomness, slot, epoch.index);
let vrf_signature = self
.keystore
.bandersnatch_vrf_sign(SASSAFRAS, &public, &sign_data)
Expand Down Expand Up @@ -362,18 +365,18 @@ fn tests_assumptions_sanity_check() {
#[test]
fn claim_secondary_slots_works() {
let mut epoch = create_test_epoch();
epoch.epoch_idx = 1;
epoch.start_slot = 6.into();
epoch.index = 1;
epoch.start = 6.into();
epoch.randomness = [2; 32];

let authorities = [Keyring::Alice, Keyring::Bob, Keyring::Charlie];

let mut assignments = vec![usize::MAX; epoch.epoch_duration as usize];
let mut assignments = vec![usize::MAX; epoch.length as usize];

for (auth_idx, auth_id) in authorities.iter().enumerate() {
let keystore = create_test_keystore(*auth_id);

for slot in 0..epoch.epoch_duration {
for slot in 0..epoch.length as u64 {
if let Some((claim, auth_id2)) =
authorship::claim_slot(slot.into(), &mut epoch, None, &keystore)
{
Expand Down Expand Up @@ -401,15 +404,15 @@ fn claim_primary_slots_works() {
// ticket auxiliary information.
let mut epoch = create_test_epoch();
epoch.randomness = [2; 32];
epoch.epoch_idx = 1;
epoch.start_slot = 6.into();
epoch.index = 1;
epoch.start = 6.into();

let keystore = create_test_keystore(Keyring::Alice);
let alice_authority_idx = 0_u32;

let ticket_id = 123;
let erased_public = EphemeralPublic::unchecked_from([0; 32]);
let revealed_public = erased_public.clone();
let revealed_public = erased_public;
let ticket_body = TicketBody { attempt_idx: 0, erased_public, revealed_public };
let ticket_secret = TicketSecret { attempt_idx: 0, seed: [0; 32] };

Expand Down Expand Up @@ -497,9 +500,9 @@ fn import_rejects_block_with_missing_epoch_changes() {
let mut env = TestContext::new();

let blocks =
env.propose_and_import_blocks(env.client.info().genesis_hash, EPOCH_DURATION as usize);
env.propose_and_import_blocks(env.client.info().genesis_hash, EPOCH_LENGTH as usize);

let mut import_params = env.propose_block(blocks[EPOCH_DURATION as usize - 1], None);
let mut import_params = env.propose_block(blocks[EPOCH_LENGTH as usize - 1], None);

let digest = import_params.header.digest_mut();
// Remove the epoch change announcement.
Expand Down Expand Up @@ -561,8 +564,8 @@ fn allows_to_skip_epochs() {
number: 1,
})
.unwrap();
assert_eq!(data.epoch_idx, 0);
assert_eq!(data.start_slot, Slot::from(1));
assert_eq!(data.index, 0);
assert_eq!(data.start, Slot::from(1));

// First block in E0 (B1) also announces E1
let data = epoch_changes
Expand All @@ -572,8 +575,8 @@ fn allows_to_skip_epochs() {
number: 1,
})
.unwrap();
assert_eq!(data.epoch_idx, 1);
assert_eq!(data.start_slot, Slot::from(7));
assert_eq!(data.index, 1);
assert_eq!(data.start, Slot::from(7));

// First block in E1 (B7) announces E2
// NOTE: config is used by E3 without altering epoch node values.
Expand All @@ -586,8 +589,8 @@ fn allows_to_skip_epochs() {
number: 7,
})
.unwrap();
assert_eq!(data.epoch_idx, 2);
assert_eq!(data.start_slot, Slot::from(13));
assert_eq!(data.index, 2);
assert_eq!(data.start, Slot::from(13));

// First block in E3 (B8) announced E4.
let data = epoch_changes
Expand All @@ -597,8 +600,8 @@ fn allows_to_skip_epochs() {
number: 8,
})
.unwrap();
assert_eq!(data.epoch_idx, 4);
assert_eq!(data.start_slot, Slot::from(25));
assert_eq!(data.index, 4);
assert_eq!(data.start, Slot::from(25));
}

#[test]
Expand Down Expand Up @@ -752,7 +755,7 @@ fn verify_block_claimed_via_secondary_method() {

let blocks = env.propose_and_import_blocks(env.client.info().genesis_hash, 7);

let in_params = env.propose_block(blocks[6], Some(9.into()));
let in_params = env.propose_block(blocks[6], Some(6.into()));

let _out_params = env.verify_block(in_params);
}
Expand Down Expand Up @@ -886,7 +889,6 @@ async fn sassafras_network_progress() {
.for_each(|_| future::ready(()));
import_notifications.push(import_futures);

//let slot_duration = data.link.genesis_config.slot_duration();
let client_clone = client.clone();
let create_inherent_data_providers = Box::new(move |parent, _| {
// Get the slot of the parent header and just increase this slot.
Expand Down
7 changes: 6 additions & 1 deletion substrate/client/consensus/sassafras/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,12 @@ fn check_header<B: BlockT + Sized>(
debug!(target: LOG_TARGET, "checking secondary");
let idx = authorship::secondary_authority_index(claim.slot, epoch);
if idx != claim.authority_idx {
error!(target: LOG_TARGET, "Bad secondary authority index");
error!(
target: LOG_TARGET,
"Bad secondary authority index (expected: {}, got {})",
idx,
claim.authority_idx
);
return Err(Error::SlotAuthorNotFound)
}
},
Expand Down
4 changes: 3 additions & 1 deletion substrate/frame/sassafras/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,20 @@ std = [
"sp-runtime/std",
"sp-std/std",
]
session-pallet-support = ["pallet-session"]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-session?/try-runtime",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-session?/try-runtime",
"sp-runtime/try-runtime",
]
# Construct dummy ring context on genesis.
# Mostly used for testing and development.
construct-dummy-ring-context = []
session-pallet-support = ["pallet-session"]
Loading

0 comments on commit 15859f7

Please sign in to comment.