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

Commit

Permalink
work from previous bitfield signing effort
Browse files Browse the repository at this point in the history
There were large merge issues with the old bitfield signing PR, so
we're just copying all the work from that onto this and restarting.

Much of the existing work will be discarded because we now have better
tools available, but that's fine.
  • Loading branch information
coriolinus committed Jul 20, 2020
1 parent 485e9a9 commit 6a062fa
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 2 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ members = [
"service",
"validation",

"node/bitfield-signing",
"node/core/proposer",
"node/network/bridge",
"node/network/pov-distribution",
Expand Down
12 changes: 12 additions & 0 deletions node/bitfield-signing/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "polkadot-node-bitfield-signing"
version = "0.1.0"
authors = ["Peter Goodspeed-Niklaus <peter.r.goodspeedniklaus@gmail.com>"]
edition = "2018"

[dependencies]
futures = "0.3.5"
log = "0.4.8"
polkadot-primitives = { path = "../../primitives" }
polkadot-node-subsystem = { path = "../subsystem" }
wasm-timer = "0.2.4"
136 changes: 136 additions & 0 deletions node/bitfield-signing/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot 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.

// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! The bitfield signing subsystem produces `SignedAvailabilityBitfield`s once per block.

use futures::{
channel::{mpsc, oneshot},
future::{abortable, AbortHandle},
prelude::*,
Future,
};
use polkadot_node_subsystem::{
messages::{AllMessages, BitfieldSigningMessage},
OverseerSignal, SubsystemResult,
};
use polkadot_node_subsystem::{FromOverseer, SpawnedSubsystem, Subsystem, SubsystemContext};
use polkadot_primitives::Hash;
use std::{
collections::HashMap,
pin::Pin,
time::{Duration, Instant},
};

/// Delay between starting a bitfield signing job and its attempting to create a bitfield.
const JOB_DELAY: Duration = Duration::from_millis(1500);

/// JobCanceler aborts all abort handles on drop.
#[derive(Debug, Default)]
struct JobCanceler(HashMap<Hash, AbortHandle>);

// AbortHandle doesn't impl Drop on its own, so we wrap it
// in this struct to get free cancellation on drop.
impl Drop for JobCanceler {
fn drop(&mut self) {
for abort_handle in self.0.values() {
abort_handle.abort();
}
}
}

/// Bitfield signing subsystem.
struct BitfieldSigning;

impl BitfieldSigning {
async fn run<Context>(mut ctx: Context) -> SubsystemResult<()>
where
Context: SubsystemContext<Message = BitfieldSigningMessage> + Clone,
{
let mut active_jobs = JobCanceler::default();

loop {
use FromOverseer::*;
use OverseerSignal::*;
match ctx.recv().await {
Ok(Communication { msg: _ }) => {
unreachable!("BitfieldSigningMessage is uninstantiable; qed")
}
Ok(Signal(StartWork(hash))) => {
let (future, abort_handle) =
abortable(bitfield_signing_job(hash.clone(), ctx.clone()));
// future currently returns a Result based on whether or not it was aborted;
// let's ignore all that and return () unconditionally, to fit the interface.
let future = async move {
let _ = future.await;
};
active_jobs.0.insert(hash.clone(), abort_handle);
ctx.spawn(Box::pin(future)).await?;
}
Ok(Signal(StopWork(hash))) => {
if let Some(abort_handle) = active_jobs.0.remove(&hash) {
abort_handle.abort();
}
}
Ok(Signal(Conclude)) => break,
Err(err) => {
return Err(err);
}
}
}

Ok(())
}
}

impl<Context> Subsystem<Context> for BitfieldSigning
where
Context: SubsystemContext<Message = BitfieldSigningMessage> + Clone,
{
fn start(self, ctx: Context) -> SpawnedSubsystem {
SpawnedSubsystem(Box::pin(async move {
if let Err(err) = Self::run(ctx).await {
log::error!("{:?}", err);
};
}))
}
}

async fn bitfield_signing_job<Context>(hash: Hash, ctx: Context)
where
Context: SubsystemContext<Message = BitfieldSigningMessage>,
{
// first up, figure out when we need to wait until
let delay = wasm_timer::Delay::new_at(Instant::now() + JOB_DELAY);
// next, do some prerequisite work
todo!();
// now, wait for the delay to be complete
if let Err(_) = delay.await {
return;
}
// let (tx, _) = oneshot::channel();

// ctx.send_message(AllMessages::CandidateValidation(
// CandidateValidationMessage::Validate(
// Default::default(),
// Default::default(),
// PoVBlock {
// block_data: BlockData(Vec::new()),
// },
// tx,
// )
// )).await.unwrap();
unimplemented!()
}
15 changes: 15 additions & 0 deletions node/subsystem/src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,19 @@ impl BitfieldDistributionMessage {
}
}

/// Bitfield signing message.
///
/// Currently non-instantiable.
#[derive(Debug)]
pub enum BitfieldSigningMessage {}

impl BitfieldSigningMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option<Hash> {
None
}
}

/// Availability store subsystem message.
#[derive(Debug)]
pub enum AvailabilityStoreMessage {
Expand Down Expand Up @@ -398,6 +411,8 @@ pub enum AllMessages {
AvailabilityDistribution(AvailabilityDistributionMessage),
/// Message for the bitfield distribution subsystem.
BitfieldDistribution(BitfieldDistributionMessage),
/// Message for the bitfield signing subsystem.
BitfieldSigning(BitfieldSigningMessage),
/// Message for the Provisioner subsystem.
Provisioner(ProvisionerMessage),
/// Message for the PoV Distribution subsystem.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ Upon onset of a new relay-chain head with `StartWork`, launch bitfield signing j
Localized to a specific relay-parent `r`
If not running as a validator, do nothing.

- Begin by waiting a fixed period of time so availability distribution has the chance to make candidates available.
- Determine our validator index `i`, the set of backed candidates pending availability in `r`, and which bit of the bitfield each corresponds to.
- Start with an empty bitfield. For each bit in the bitfield, if there is a candidate pending availability, query the [Availability Store](../utility/availability-store.md) for whether we have the availability chunk for our validator index.
- For all chunks we have, set the corresponding bit in the bitfield.
- Sign the bitfield and dispatch a `BitfieldDistribution::DistributeBitfield` message.

Note that because the bitfield signing job is launched once per block and executes immediately, the signed availability statement for block `N` is best considered as a report of the candidates available at the end of block `N-1`.

0 comments on commit 6a062fa

Please sign in to comment.