mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-12 14:09:25 +00:00
Compare commits
4 Commits
be2098d2e1
...
8222ce78d8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8222ce78d8 | ||
|
|
cb906242e7 | ||
|
|
2a19e9da93 | ||
|
|
2226dd59cc |
2
.github/nightly-version
vendored
2
.github/nightly-version
vendored
@@ -1 +1 @@
|
|||||||
nightly-2024-07-01
|
nightly-2025-01-01
|
||||||
|
|||||||
2888
Cargo.lock
generated
2888
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@ use crate::{Client, Error};
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Response<'a>(pub(crate) hyper::Response<Incoming>, pub(crate) &'a Client);
|
pub struct Response<'a>(pub(crate) hyper::Response<Incoming>, pub(crate) &'a Client);
|
||||||
impl<'a> Response<'a> {
|
impl Response<'_> {
|
||||||
pub fn status(&self) -> StatusCode {
|
pub fn status(&self) -> StatusCode {
|
||||||
self.0.status()
|
self.0.status()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,24 @@ pub struct Cosign {
|
|||||||
pub cosigner: NetworkId,
|
pub cosigner: NetworkId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CosignIntent {
|
||||||
|
/// Convert this into a `Cosign`.
|
||||||
|
pub fn into_cosign(self, cosigner: NetworkId) -> Cosign {
|
||||||
|
let CosignIntent { global_session, block_number, block_hash, notable: _ } = self;
|
||||||
|
Cosign { global_session, block_number, block_hash, cosigner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Cosign {
|
||||||
|
/// The message to sign to sign this cosign.
|
||||||
|
///
|
||||||
|
/// This must be signed with schnorrkel, the context set to `COSIGN_CONTEXT`.
|
||||||
|
pub fn signature_message(&self) -> Vec<u8> {
|
||||||
|
// We use a schnorrkel context to domain-separate this
|
||||||
|
self.encode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A signed cosign.
|
/// A signed cosign.
|
||||||
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub struct SignedCosign {
|
pub struct SignedCosign {
|
||||||
@@ -118,7 +136,7 @@ impl SignedCosign {
|
|||||||
let Ok(signer) = schnorrkel::PublicKey::from_bytes(&signer.0) else { return false };
|
let Ok(signer) = schnorrkel::PublicKey::from_bytes(&signer.0) else { return false };
|
||||||
let Ok(signature) = schnorrkel::Signature::from_bytes(&self.signature) else { return false };
|
let Ok(signature) = schnorrkel::Signature::from_bytes(&self.signature) else { return false };
|
||||||
|
|
||||||
signer.verify_simple(COSIGN_CONTEXT, &self.cosign.encode(), &signature).is_ok()
|
signer.verify_simple(COSIGN_CONTEXT, &self.cosign.signature_message(), &signature).is_ok()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ tributary-sdk = { path = "../../tributary-sdk" }
|
|||||||
|
|
||||||
futures-util = { version = "0.3", default-features = false, features = ["std"] }
|
futures-util = { version = "0.3", default-features = false, features = ["std"] }
|
||||||
tokio = { version = "1", default-features = false, features = ["sync"] }
|
tokio = { version = "1", default-features = false, features = ["sync"] }
|
||||||
libp2p = { version = "0.52", default-features = false, features = ["tokio", "tcp", "noise", "yamux", "ping", "request-response", "gossipsub", "macros"] }
|
libp2p = { version = "0.54", default-features = false, features = ["tokio", "tcp", "noise", "yamux", "ping", "request-response", "gossipsub", "macros"] }
|
||||||
|
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
serai-task = { path = "../../../common/task", version = "0.1" }
|
serai-task = { path = "../../../common/task", version = "0.1" }
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ use serai_client::primitives::PublicKey as Public;
|
|||||||
|
|
||||||
use futures_util::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
use futures_util::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
use libp2p::{
|
use libp2p::{
|
||||||
core::UpgradeInfo,
|
core::upgrade::{UpgradeInfo, InboundConnectionUpgrade, OutboundConnectionUpgrade},
|
||||||
InboundUpgrade, OutboundUpgrade,
|
|
||||||
identity::{self, PeerId},
|
identity::{self, PeerId},
|
||||||
noise,
|
noise,
|
||||||
};
|
};
|
||||||
@@ -119,12 +118,18 @@ impl UpgradeInfo for OnlyValidators {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> InboundUpgrade<S> for OnlyValidators {
|
impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> InboundConnectionUpgrade<S>
|
||||||
|
for OnlyValidators
|
||||||
|
{
|
||||||
type Output = (PeerId, noise::Output<S>);
|
type Output = (PeerId, noise::Output<S>);
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>;
|
type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>;
|
||||||
|
|
||||||
fn upgrade_inbound(self, socket: S, info: Self::Info) -> Self::Future {
|
fn upgrade_inbound(
|
||||||
|
self,
|
||||||
|
socket: S,
|
||||||
|
info: <Self as UpgradeInfo>::Info,
|
||||||
|
) -> <Self as InboundConnectionUpgrade<S>>::Future {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let (dialer_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair)
|
let (dialer_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -147,12 +152,18 @@ impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> InboundUpgrade<S> for O
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> OutboundUpgrade<S> for OnlyValidators {
|
impl<S: 'static + Send + Unpin + AsyncRead + AsyncWrite> OutboundConnectionUpgrade<S>
|
||||||
|
for OnlyValidators
|
||||||
|
{
|
||||||
type Output = (PeerId, noise::Output<S>);
|
type Output = (PeerId, noise::Output<S>);
|
||||||
type Error = io::Error;
|
type Error = io::Error;
|
||||||
type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>;
|
type Future = Pin<Box<dyn Send + Future<Output = Result<Self::Output, Self::Error>>>>;
|
||||||
|
|
||||||
fn upgrade_outbound(self, socket: S, info: Self::Info) -> Self::Future {
|
fn upgrade_outbound(
|
||||||
|
self,
|
||||||
|
socket: S,
|
||||||
|
info: <Self as UpgradeInfo>::Info,
|
||||||
|
) -> <Self as OutboundConnectionUpgrade<S>>::Future {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let (listener_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair)
|
let (listener_noise_peer_id, mut socket) = noise::Config::new(&self.noise_keypair)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ mod ping;
|
|||||||
|
|
||||||
/// The request-response messages and behavior
|
/// The request-response messages and behavior
|
||||||
mod reqres;
|
mod reqres;
|
||||||
use reqres::{RequestId, Request, Response};
|
use reqres::{InboundRequestId, Request, Response};
|
||||||
|
|
||||||
/// The gossip messages and behavior
|
/// The gossip messages and behavior
|
||||||
mod gossip;
|
mod gossip;
|
||||||
@@ -66,14 +66,6 @@ use dial::DialTask;
|
|||||||
|
|
||||||
const PORT: u16 = 30563; // 5132 ^ (('c' << 8) | 'o')
|
const PORT: u16 = 30563; // 5132 ^ (('c' << 8) | 'o')
|
||||||
|
|
||||||
// usize::max, manually implemented, as max isn't a const fn
|
|
||||||
const MAX_LIBP2P_MESSAGE_SIZE: usize =
|
|
||||||
if gossip::MAX_LIBP2P_GOSSIP_MESSAGE_SIZE > reqres::MAX_LIBP2P_REQRES_MESSAGE_SIZE {
|
|
||||||
gossip::MAX_LIBP2P_GOSSIP_MESSAGE_SIZE
|
|
||||||
} else {
|
|
||||||
reqres::MAX_LIBP2P_REQRES_MESSAGE_SIZE
|
|
||||||
};
|
|
||||||
|
|
||||||
fn peer_id_from_public(public: PublicKey) -> PeerId {
|
fn peer_id_from_public(public: PublicKey) -> PeerId {
|
||||||
// 0 represents the identity Multihash, that no hash was performed
|
// 0 represents the identity Multihash, that no hash was performed
|
||||||
// It's an internal constant so we can't refer to the constant inside libp2p
|
// It's an internal constant so we can't refer to the constant inside libp2p
|
||||||
@@ -143,9 +135,9 @@ struct Libp2pInner {
|
|||||||
signed_cosigns: Mutex<mpsc::UnboundedReceiver<SignedCosign>>,
|
signed_cosigns: Mutex<mpsc::UnboundedReceiver<SignedCosign>>,
|
||||||
signed_cosigns_send: mpsc::UnboundedSender<SignedCosign>,
|
signed_cosigns_send: mpsc::UnboundedSender<SignedCosign>,
|
||||||
|
|
||||||
heartbeat_requests: Mutex<mpsc::UnboundedReceiver<(RequestId, ValidatorSet, [u8; 32])>>,
|
heartbeat_requests: Mutex<mpsc::UnboundedReceiver<(InboundRequestId, ValidatorSet, [u8; 32])>>,
|
||||||
notable_cosign_requests: Mutex<mpsc::UnboundedReceiver<(RequestId, [u8; 32])>>,
|
notable_cosign_requests: Mutex<mpsc::UnboundedReceiver<(InboundRequestId, [u8; 32])>>,
|
||||||
inbound_request_responses: mpsc::UnboundedSender<(RequestId, Response)>,
|
inbound_request_responses: mpsc::UnboundedSender<(InboundRequestId, Response)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The libp2p-backed P2P implementation.
|
/// The libp2p-backed P2P implementation.
|
||||||
@@ -176,19 +168,9 @@ impl Libp2p {
|
|||||||
Ok(OnlyValidators { serai_key: serai_key.clone(), noise_keypair: noise_keypair.clone() })
|
Ok(OnlyValidators { serai_key: serai_key.clone(), noise_keypair: noise_keypair.clone() })
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_yamux = || {
|
|
||||||
let mut config = yamux::Config::default();
|
|
||||||
// 1 MiB default + max message size
|
|
||||||
config.set_max_buffer_size((1024 * 1024) + MAX_LIBP2P_MESSAGE_SIZE);
|
|
||||||
// 256 KiB default + max message size
|
|
||||||
config
|
|
||||||
.set_receive_window_size(((256 * 1024) + MAX_LIBP2P_MESSAGE_SIZE).try_into().unwrap());
|
|
||||||
config
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut swarm = SwarmBuilder::with_existing_identity(identity::Keypair::generate_ed25519())
|
let mut swarm = SwarmBuilder::with_existing_identity(identity::Keypair::generate_ed25519())
|
||||||
.with_tokio()
|
.with_tokio()
|
||||||
.with_tcp(TcpConfig::default().nodelay(true), new_only_validators, new_yamux)
|
.with_tcp(TcpConfig::default().nodelay(true), new_only_validators, yamux::Config::default)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.with_behaviour(|_| Behavior {
|
.with_behaviour(|_| Behavior {
|
||||||
allow_list: allow_block_list::Behaviour::default(),
|
allow_list: allow_block_list::Behaviour::default(),
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use futures_util::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
|||||||
use libp2p::request_response::{
|
use libp2p::request_response::{
|
||||||
self, Codec as CodecTrait, Event as GenericEvent, Config, Behaviour, ProtocolSupport,
|
self, Codec as CodecTrait, Event as GenericEvent, Config, Behaviour, ProtocolSupport,
|
||||||
};
|
};
|
||||||
pub use request_response::{RequestId, Message};
|
pub use request_response::{InboundRequestId, Message};
|
||||||
|
|
||||||
use serai_cosign::SignedCosign;
|
use serai_cosign::SignedCosign;
|
||||||
|
|
||||||
@@ -129,7 +129,6 @@ pub(crate) type Event = GenericEvent<Request, Response>;
|
|||||||
|
|
||||||
pub(crate) type Behavior = Behaviour<Codec>;
|
pub(crate) type Behavior = Behaviour<Codec>;
|
||||||
pub(crate) fn new_behavior() -> Behavior {
|
pub(crate) fn new_behavior() -> Behavior {
|
||||||
let mut config = Config::default();
|
let config = Config::default().with_request_timeout(Duration::from_secs(5));
|
||||||
config.set_request_timeout(Duration::from_secs(5));
|
|
||||||
Behavior::new([(PROTOCOL, ProtocolSupport::Full)], config)
|
Behavior::new([(PROTOCOL, ProtocolSupport::Full)], config)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ use serai_cosign::SignedCosign;
|
|||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use libp2p::{
|
use libp2p::{
|
||||||
identity::PeerId,
|
identity::PeerId,
|
||||||
request_response::{RequestId, ResponseChannel},
|
request_response::{InboundRequestId, OutboundRequestId, ResponseChannel},
|
||||||
swarm::{dial_opts::DialOpts, SwarmEvent, Swarm},
|
swarm::{dial_opts::DialOpts, SwarmEvent, Swarm},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,12 +65,12 @@ pub(crate) struct SwarmTask {
|
|||||||
tributary_gossip: mpsc::UnboundedSender<([u8; 32], Vec<u8>)>,
|
tributary_gossip: mpsc::UnboundedSender<([u8; 32], Vec<u8>)>,
|
||||||
|
|
||||||
outbound_requests: mpsc::UnboundedReceiver<(PeerId, Request, oneshot::Sender<Response>)>,
|
outbound_requests: mpsc::UnboundedReceiver<(PeerId, Request, oneshot::Sender<Response>)>,
|
||||||
outbound_request_responses: HashMap<RequestId, oneshot::Sender<Response>>,
|
outbound_request_responses: HashMap<OutboundRequestId, oneshot::Sender<Response>>,
|
||||||
|
|
||||||
inbound_request_response_channels: HashMap<RequestId, ResponseChannel<Response>>,
|
inbound_request_response_channels: HashMap<InboundRequestId, ResponseChannel<Response>>,
|
||||||
heartbeat_requests: mpsc::UnboundedSender<(RequestId, ValidatorSet, [u8; 32])>,
|
heartbeat_requests: mpsc::UnboundedSender<(InboundRequestId, ValidatorSet, [u8; 32])>,
|
||||||
notable_cosign_requests: mpsc::UnboundedSender<(RequestId, [u8; 32])>,
|
notable_cosign_requests: mpsc::UnboundedSender<(InboundRequestId, [u8; 32])>,
|
||||||
inbound_request_responses: mpsc::UnboundedReceiver<(RequestId, Response)>,
|
inbound_request_responses: mpsc::UnboundedReceiver<(InboundRequestId, Response)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SwarmTask {
|
impl SwarmTask {
|
||||||
@@ -222,24 +222,20 @@ impl SwarmTask {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SwarmEvent::Behaviour(
|
SwarmEvent::Behaviour(event) => {
|
||||||
BehaviorEvent::AllowList(event) | BehaviorEvent::ConnectionLimits(event)
|
match event {
|
||||||
) => {
|
BehaviorEvent::AllowList(event) | BehaviorEvent::ConnectionLimits(event) => {
|
||||||
// This *is* an exhaustive match as these events are empty enums
|
// This *is* an exhaustive match as these events are empty enums
|
||||||
match event {}
|
match event {}
|
||||||
}
|
}
|
||||||
SwarmEvent::Behaviour(
|
BehaviorEvent::Ping(ping::Event { peer: _, connection, result, }) => {
|
||||||
BehaviorEvent::Ping(ping::Event { peer: _, connection, result, })
|
|
||||||
) => {
|
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
self.swarm.close_connection(connection);
|
self.swarm.close_connection(connection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SwarmEvent::Behaviour(BehaviorEvent::Reqres(event)) => {
|
BehaviorEvent::Reqres(event) => self.handle_reqres(event),
|
||||||
self.handle_reqres(event)
|
BehaviorEvent::Gossip(event) => self.handle_gossip(event),
|
||||||
}
|
}
|
||||||
SwarmEvent::Behaviour(BehaviorEvent::Gossip(event)) => {
|
|
||||||
self.handle_gossip(event)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't handle any of these
|
// We don't handle any of these
|
||||||
@@ -250,7 +246,14 @@ impl SwarmTask {
|
|||||||
SwarmEvent::ExpiredListenAddr { .. } |
|
SwarmEvent::ExpiredListenAddr { .. } |
|
||||||
SwarmEvent::ListenerClosed { .. } |
|
SwarmEvent::ListenerClosed { .. } |
|
||||||
SwarmEvent::ListenerError { .. } |
|
SwarmEvent::ListenerError { .. } |
|
||||||
SwarmEvent::Dialing { .. } => {}
|
SwarmEvent::Dialing { .. } |
|
||||||
|
SwarmEvent::NewExternalAddrCandidate { .. } |
|
||||||
|
SwarmEvent::ExternalAddrConfirmed { .. } |
|
||||||
|
SwarmEvent::ExternalAddrExpired { .. } |
|
||||||
|
SwarmEvent::NewExternalAddrOfPeer { .. } => {}
|
||||||
|
|
||||||
|
// Requires as SwarmEvent is non-exhaustive
|
||||||
|
_ => log::warn!("unhandled SwarmEvent: {event:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,9 +324,9 @@ impl SwarmTask {
|
|||||||
|
|
||||||
outbound_requests: mpsc::UnboundedReceiver<(PeerId, Request, oneshot::Sender<Response>)>,
|
outbound_requests: mpsc::UnboundedReceiver<(PeerId, Request, oneshot::Sender<Response>)>,
|
||||||
|
|
||||||
heartbeat_requests: mpsc::UnboundedSender<(RequestId, ValidatorSet, [u8; 32])>,
|
heartbeat_requests: mpsc::UnboundedSender<(InboundRequestId, ValidatorSet, [u8; 32])>,
|
||||||
notable_cosign_requests: mpsc::UnboundedSender<(RequestId, [u8; 32])>,
|
notable_cosign_requests: mpsc::UnboundedSender<(InboundRequestId, [u8; 32])>,
|
||||||
inbound_request_responses: mpsc::UnboundedReceiver<(RequestId, Response)>,
|
inbound_request_responses: mpsc::UnboundedReceiver<(InboundRequestId, Response)>,
|
||||||
) {
|
) {
|
||||||
tokio::spawn(
|
tokio::spawn(
|
||||||
SwarmTask {
|
SwarmTask {
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ struct ScanBlock<'a, TD: Db, TDT: DbTxn, P: P2p> {
|
|||||||
total_weight: u16,
|
total_weight: u16,
|
||||||
validator_weights: &'a HashMap<SeraiAddress, u16>,
|
validator_weights: &'a HashMap<SeraiAddress, u16>,
|
||||||
}
|
}
|
||||||
impl<'a, TD: Db, TDT: DbTxn, P: P2p> ScanBlock<'a, TD, TDT, P> {
|
impl<TD: Db, TDT: DbTxn, P: P2p> ScanBlock<'_, TD, TDT, P> {
|
||||||
fn potentially_start_cosign(&mut self) {
|
fn potentially_start_cosign(&mut self) {
|
||||||
// Don't start a new cosigning instance if we're actively running one
|
// Don't start a new cosigning instance if we're actively running one
|
||||||
if TributaryDb::actively_cosigning(self.tributary_txn, self.set.set).is_some() {
|
if TributaryDb::actively_cosigning(self.tributary_txn, self.set.set).is_some() {
|
||||||
@@ -173,7 +173,7 @@ impl<'a, TD: Db, TDT: DbTxn, P: P2p> ScanBlock<'a, TD, TDT, P> {
|
|||||||
self.set.set,
|
self.set.set,
|
||||||
messages::coordinator::CoordinatorMessage::CosignSubstrateBlock {
|
messages::coordinator::CoordinatorMessage::CosignSubstrateBlock {
|
||||||
session: self.set.set.session,
|
session: self.set.set.session,
|
||||||
intent,
|
cosign: intent.into_cosign(self.set.set.network),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,10 +365,12 @@ impl Transaction {
|
|||||||
Transaction::DkgConfirmationPreprocess { ref mut signed, .. } => signed,
|
Transaction::DkgConfirmationPreprocess { ref mut signed, .. } => signed,
|
||||||
Transaction::DkgConfirmationShare { ref mut signed, .. } => signed,
|
Transaction::DkgConfirmationShare { ref mut signed, .. } => signed,
|
||||||
|
|
||||||
Transaction::Cosign { .. } => panic!("signing CosignSubstrateBlock"),
|
Transaction::Cosign { .. } => panic!("signing Cosign transaction (provided)"),
|
||||||
Transaction::Cosigned { .. } => panic!("signing Cosigned"),
|
Transaction::Cosigned { .. } => panic!("signing Cosigned transaction (provided)"),
|
||||||
Transaction::SubstrateBlock { .. } => panic!("signing SubstrateBlock"),
|
Transaction::SubstrateBlock { .. } => {
|
||||||
Transaction::Batch { .. } => panic!("signing Batch"),
|
panic!("signing SubstrateBlock transaction (provided)")
|
||||||
|
}
|
||||||
|
Transaction::Batch { .. } => panic!("signing Batch transaction (provided)"),
|
||||||
|
|
||||||
Transaction::Sign { ref mut signed, .. } => signed,
|
Transaction::Sign { ref mut signed, .. } => signed,
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ impl Neg for FieldElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Neg for &'a FieldElement {
|
impl Neg for &FieldElement {
|
||||||
type Output = FieldElement;
|
type Output = FieldElement;
|
||||||
fn neg(self) -> Self::Output {
|
fn neg(self) -> Self::Output {
|
||||||
(*self).neg()
|
(*self).neg()
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ pub(crate) fn challenge<T: Transcript, F: PrimeField>(transcript: &mut T) -> F {
|
|||||||
// Get a wide amount of bytes to safely reduce without bias
|
// Get a wide amount of bytes to safely reduce without bias
|
||||||
// In most cases, <=1.5x bytes is enough. 2x is still standard and there's some theoretical
|
// In most cases, <=1.5x bytes is enough. 2x is still standard and there's some theoretical
|
||||||
// groups which may technically require more than 1.5x bytes for this to work as intended
|
// groups which may technically require more than 1.5x bytes for this to work as intended
|
||||||
let target_bytes = ((usize::try_from(F::NUM_BITS).unwrap() + 7) / 8) * 2;
|
let target_bytes = usize::try_from(F::NUM_BITS).unwrap().div_ceil(8) * 2;
|
||||||
let mut challenge_bytes = transcript.challenge(b"challenge");
|
let mut challenge_bytes = transcript.challenge(b"challenge");
|
||||||
let challenge_bytes_len = challenge_bytes.as_ref().len();
|
let challenge_bytes_len = challenge_bytes.as_ref().len();
|
||||||
// If the challenge is 32 bytes, and we need 64, we need two challenges
|
// If the challenge is 32 bytes, and we need 64, we need two challenges
|
||||||
let needed_challenges = (target_bytes + (challenge_bytes_len - 1)) / challenge_bytes_len;
|
let needed_challenges = target_bytes.div_ceil(challenge_bytes_len);
|
||||||
|
|
||||||
// The following algorithm should be equivalent to a wide reduction of the challenges,
|
// The following algorithm should be equivalent to a wide reduction of the challenges,
|
||||||
// interpreted as concatenated, big-endian byte string
|
// interpreted as concatenated, big-endian byte string
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ pub struct ArithmeticCircuitStatement<'a, C: Ciphersuite> {
|
|||||||
V: PointVector<C>,
|
V: PointVector<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: Ciphersuite> Zeroize for ArithmeticCircuitStatement<'a, C> {
|
impl<C: Ciphersuite> Zeroize for ArithmeticCircuitStatement<'_, C> {
|
||||||
fn zeroize(&mut self) {
|
fn zeroize(&mut self) {
|
||||||
self.constraints.zeroize();
|
self.constraints.zeroize();
|
||||||
self.C.zeroize();
|
self.C.zeroize();
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ impl<C: Ciphersuite> Generators<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, C: Ciphersuite> ProofGenerators<'a, C> {
|
impl<C: Ciphersuite> ProofGenerators<'_, C> {
|
||||||
pub(crate) fn len(&self) -> usize {
|
pub(crate) fn len(&self) -> usize {
|
||||||
self.g_bold.len()
|
self.g_bold.len()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,14 +203,15 @@ pub trait SignMachine<S>: Send + Sync + Sized {
|
|||||||
/// SignatureMachine this SignMachine turns into.
|
/// SignatureMachine this SignMachine turns into.
|
||||||
type SignatureMachine: SignatureMachine<S, SignatureShare = Self::SignatureShare>;
|
type SignatureMachine: SignatureMachine<S, SignatureShare = Self::SignatureShare>;
|
||||||
|
|
||||||
/// Cache this preprocess for usage later. This cached preprocess MUST only be used once. Reuse
|
/// Cache this preprocess for usage later.
|
||||||
/// of it enables recovery of your private key share. Third-party recovery of a cached preprocess
|
///
|
||||||
/// also enables recovery of your private key share, so this MUST be treated with the same
|
/// This cached preprocess MUST only be used once. Reuse of it enables recovery of your private
|
||||||
/// security as your private key share.
|
/// key share. Third-party recovery of a cached preprocess also enables recovery of your private
|
||||||
|
/// key share, so this MUST be treated with the same security as your private key share.
|
||||||
fn cache(self) -> CachedPreprocess;
|
fn cache(self) -> CachedPreprocess;
|
||||||
|
|
||||||
/// Create a sign machine from a cached preprocess.
|
/// Create a sign machine from a cached preprocess.
|
||||||
|
///
|
||||||
/// After this, the preprocess must be deleted so it's never reused. Any reuse will presumably
|
/// After this, the preprocess must be deleted so it's never reused. Any reuse will presumably
|
||||||
/// cause the signer to leak their secret share.
|
/// cause the signer to leak their secret share.
|
||||||
fn from_cache(
|
fn from_cache(
|
||||||
@@ -219,11 +220,14 @@ pub trait SignMachine<S>: Send + Sync + Sized {
|
|||||||
cache: CachedPreprocess,
|
cache: CachedPreprocess,
|
||||||
) -> (Self, Self::Preprocess);
|
) -> (Self, Self::Preprocess);
|
||||||
|
|
||||||
/// Read a Preprocess message. Despite taking self, this does not save the preprocess.
|
/// Read a Preprocess message.
|
||||||
/// It must be externally cached and passed into sign.
|
///
|
||||||
|
/// Despite taking self, this does not save the preprocess. It must be externally cached and
|
||||||
|
/// passed into sign.
|
||||||
fn read_preprocess<R: Read>(&self, reader: &mut R) -> io::Result<Self::Preprocess>;
|
fn read_preprocess<R: Read>(&self, reader: &mut R) -> io::Result<Self::Preprocess>;
|
||||||
|
|
||||||
/// Sign a message.
|
/// Sign a message.
|
||||||
|
///
|
||||||
/// Takes in the participants' preprocess messages. Returns the signature share to be broadcast
|
/// Takes in the participants' preprocess messages. Returns the signature share to be broadcast
|
||||||
/// to all participants, over an authenticated channel. The parties who participate here will
|
/// to all participants, over an authenticated channel. The parties who participate here will
|
||||||
/// become the signing set for this session.
|
/// become the signing set for this session.
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ pub(crate) fn prep_bits<G: Group<Scalar: PrimeFieldBits>>(
|
|||||||
for pair in pairs {
|
for pair in pairs {
|
||||||
let p = groupings.len();
|
let p = groupings.len();
|
||||||
let mut bits = pair.0.to_le_bits();
|
let mut bits = pair.0.to_le_bits();
|
||||||
groupings.push(vec![0; (bits.len() + (w_usize - 1)) / w_usize]);
|
groupings.push(vec![0; bits.len().div_ceil(w_usize)]);
|
||||||
|
|
||||||
for (i, mut bit) in bits.iter_mut().enumerate() {
|
for (i, mut bit) in bits.iter_mut().enumerate() {
|
||||||
let mut bit = u8_from_bool(&mut bit);
|
let mut bit = u8_from_bool(&mut bit);
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ ciphersuite = { path = "../../crypto/ciphersuite", default-features = false, fea
|
|||||||
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std", "evrf-ristretto"] }
|
dkg = { path = "../../crypto/dkg", default-features = false, features = ["std", "evrf-ristretto"] }
|
||||||
|
|
||||||
serai-client = { path = "../../substrate/client", default-features = false }
|
serai-client = { path = "../../substrate/client", default-features = false }
|
||||||
|
serai-cosign = { path = "../../coordinator/cosign" }
|
||||||
|
|
||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
env_logger = { version = "0.10", default-features = false, features = ["humantime"] }
|
env_logger = { version = "0.10", default-features = false, features = ["humantime"] }
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ use std::sync::{LazyLock, Arc, Mutex};
|
|||||||
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
use serai_client::{
|
use serai_client::{
|
||||||
primitives::Signature, validator_sets::primitives::Session,
|
primitives::Signature,
|
||||||
|
validator_sets::primitives::{Session, SlashReport},
|
||||||
in_instructions::primitives::SignedBatch,
|
in_instructions::primitives::SignedBatch,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use serai_cosign::SignedCosign;
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn, Db, create_db, db_channel};
|
use serai_db::{Get, DbTxn, Db, create_db, db_channel};
|
||||||
|
|
||||||
use scanner::ScannerFeed;
|
use scanner::ScannerFeed;
|
||||||
@@ -181,17 +183,11 @@ impl signers::Coordinator for CoordinatorSend {
|
|||||||
|
|
||||||
fn publish_cosign(
|
fn publish_cosign(
|
||||||
&mut self,
|
&mut self,
|
||||||
block_number: u64,
|
cosign: SignedCosign,
|
||||||
block: [u8; 32],
|
|
||||||
signature: Signature,
|
|
||||||
) -> impl Send + Future<Output = Result<(), Self::EphemeralError>> {
|
) -> impl Send + Future<Output = Result<(), Self::EphemeralError>> {
|
||||||
async move {
|
async move {
|
||||||
self.send(&messages::ProcessorMessage::Coordinator(
|
self.send(&messages::ProcessorMessage::Coordinator(
|
||||||
messages::coordinator::ProcessorMessage::CosignedBlock {
|
messages::coordinator::ProcessorMessage::CosignedBlock { cosign },
|
||||||
block_number,
|
|
||||||
block,
|
|
||||||
signature: signature.encode(),
|
|
||||||
},
|
|
||||||
));
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -212,13 +208,15 @@ impl signers::Coordinator for CoordinatorSend {
|
|||||||
fn publish_slash_report_signature(
|
fn publish_slash_report_signature(
|
||||||
&mut self,
|
&mut self,
|
||||||
session: Session,
|
session: Session,
|
||||||
|
slash_report: SlashReport,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
) -> impl Send + Future<Output = Result<(), Self::EphemeralError>> {
|
) -> impl Send + Future<Output = Result<(), Self::EphemeralError>> {
|
||||||
async move {
|
async move {
|
||||||
self.send(&messages::ProcessorMessage::Coordinator(
|
self.send(&messages::ProcessorMessage::Coordinator(
|
||||||
messages::coordinator::ProcessorMessage::SignedSlashReport {
|
messages::coordinator::ProcessorMessage::SignedSlashReport {
|
||||||
session,
|
session,
|
||||||
signature: signature.encode(),
|
slash_report,
|
||||||
|
signature: signature.0,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -221,20 +221,16 @@ pub async fn main_loop<
|
|||||||
signers.queue_message(txn, &msg)
|
signers.queue_message(txn, &msg)
|
||||||
}
|
}
|
||||||
messages::CoordinatorMessage::Coordinator(
|
messages::CoordinatorMessage::Coordinator(
|
||||||
messages::coordinator::CoordinatorMessage::CosignSubstrateBlock {
|
messages::coordinator::CoordinatorMessage::CosignSubstrateBlock { session, cosign },
|
||||||
session,
|
|
||||||
block_number,
|
|
||||||
block,
|
|
||||||
},
|
|
||||||
) => {
|
) => {
|
||||||
let txn = txn.take().unwrap();
|
let txn = txn.take().unwrap();
|
||||||
signers.cosign_block(txn, session, block_number, block)
|
signers.cosign_block(txn, session, &cosign)
|
||||||
}
|
}
|
||||||
messages::CoordinatorMessage::Coordinator(
|
messages::CoordinatorMessage::Coordinator(
|
||||||
messages::coordinator::CoordinatorMessage::SignSlashReport { session, report },
|
messages::coordinator::CoordinatorMessage::SignSlashReport { session, slash_report },
|
||||||
) => {
|
) => {
|
||||||
let txn = txn.take().unwrap();
|
let txn = txn.take().unwrap();
|
||||||
signers.sign_slash_report(txn, session, &report)
|
signers.sign_slash_report(txn, session, &slash_report)
|
||||||
}
|
}
|
||||||
|
|
||||||
messages::CoordinatorMessage::Substrate(msg) => match msg {
|
messages::CoordinatorMessage::Substrate(msg) => match msg {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use validator_sets_primitives::{Session, KeyPair, SlashReport};
|
|||||||
use coins_primitives::OutInstructionWithBalance;
|
use coins_primitives::OutInstructionWithBalance;
|
||||||
use in_instructions_primitives::SignedBatch;
|
use in_instructions_primitives::SignedBatch;
|
||||||
|
|
||||||
use serai_cosign::{CosignIntent, SignedCosign};
|
use serai_cosign::{Cosign, SignedCosign};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)]
|
||||||
pub struct SubstrateContext {
|
pub struct SubstrateContext {
|
||||||
@@ -166,7 +166,7 @@ pub mod coordinator {
|
|||||||
/// Cosign the specified Substrate block.
|
/// Cosign the specified Substrate block.
|
||||||
///
|
///
|
||||||
/// This is sent by the Coordinator's Tributary scanner.
|
/// This is sent by the Coordinator's Tributary scanner.
|
||||||
CosignSubstrateBlock { session: Session, intent: CosignIntent },
|
CosignSubstrateBlock { session: Session, cosign: Cosign },
|
||||||
/// Sign the slash report for this session.
|
/// Sign the slash report for this session.
|
||||||
///
|
///
|
||||||
/// This is sent by the Coordinator's Tributary scanner.
|
/// This is sent by the Coordinator's Tributary scanner.
|
||||||
@@ -322,8 +322,8 @@ impl CoordinatorMessage {
|
|||||||
CoordinatorMessage::Coordinator(msg) => {
|
CoordinatorMessage::Coordinator(msg) => {
|
||||||
let (sub, id) = match msg {
|
let (sub, id) = match msg {
|
||||||
// We only cosign a block once, and Reattempt is a separate message
|
// We only cosign a block once, and Reattempt is a separate message
|
||||||
coordinator::CoordinatorMessage::CosignSubstrateBlock { intent, .. } => {
|
coordinator::CoordinatorMessage::CosignSubstrateBlock { cosign, .. } => {
|
||||||
(0, intent.block_number.encode())
|
(0, cosign.block_number.encode())
|
||||||
}
|
}
|
||||||
// We only sign one slash report, and Reattempt is a separate message
|
// We only sign one slash report, and Reattempt is a separate message
|
||||||
coordinator::CoordinatorMessage::SignSlashReport { session, .. } => (1, session.encode()),
|
coordinator::CoordinatorMessage::SignSlashReport { session, .. } => (1, session.encode()),
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ pub trait TransactionPlanner<S: ScannerFeed, A>: 'static + Send + Sync {
|
|||||||
///
|
///
|
||||||
/// Returns `None` if the fee exceeded the inputs, or `Some` otherwise.
|
/// Returns `None` if the fee exceeded the inputs, or `Some` otherwise.
|
||||||
// TODO: Enum for Change of None, Some, Mandatory
|
// TODO: Enum for Change of None, Some, Mandatory
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
fn plan_transaction_with_fee_amortization(
|
fn plan_transaction_with_fee_amortization(
|
||||||
&self,
|
&self,
|
||||||
operating_costs: &mut u64,
|
operating_costs: &mut u64,
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ serai-db = { path = "../../common/db" }
|
|||||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "sync", "time", "macros"] }
|
tokio = { version = "1", default-features = false, features = ["rt-multi-thread", "sync", "time", "macros"] }
|
||||||
|
|
||||||
|
serai-cosign = { path = "../../coordinator/cosign" }
|
||||||
messages = { package = "serai-processor-messages", path = "../messages" }
|
messages = { package = "serai-processor-messages", path = "../messages" }
|
||||||
primitives = { package = "serai-processor-primitives", path = "../primitives" }
|
primitives = { package = "serai-processor-primitives", path = "../primitives" }
|
||||||
scanner = { package = "serai-processor-scanner", path = "../scanner" }
|
scanner = { package = "serai-processor-scanner", path = "../scanner" }
|
||||||
|
|||||||
@@ -69,7 +69,12 @@ impl<D: Db, E: GroupEncoding> BatchSignerTask<D, E> {
|
|||||||
|
|
||||||
let mut machines = Vec::with_capacity(keys.len());
|
let mut machines = Vec::with_capacity(keys.len());
|
||||||
for keys in &keys {
|
for keys in &keys {
|
||||||
machines.push(WrappedSchnorrkelMachine::new(keys.clone(), batch_message(&batch)));
|
// TODO: Fetch the context for this from a constant instead of re-defining it
|
||||||
|
machines.push(WrappedSchnorrkelMachine::new(
|
||||||
|
keys.clone(),
|
||||||
|
b"substrate",
|
||||||
|
batch_message(&batch),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
attempt_manager.register(VariantSignId::Batch(id), machines);
|
attempt_manager.register(VariantSignId::Batch(id), machines);
|
||||||
}
|
}
|
||||||
@@ -106,7 +111,12 @@ impl<D: Db, E: Send + GroupEncoding> ContinuallyRan for BatchSignerTask<D, E> {
|
|||||||
|
|
||||||
let mut machines = Vec::with_capacity(self.keys.len());
|
let mut machines = Vec::with_capacity(self.keys.len());
|
||||||
for keys in &self.keys {
|
for keys in &self.keys {
|
||||||
machines.push(WrappedSchnorrkelMachine::new(keys.clone(), batch_message(&batch)));
|
// TODO: Also fetch the constant here
|
||||||
|
machines.push(WrappedSchnorrkelMachine::new(
|
||||||
|
keys.clone(),
|
||||||
|
b"substrate",
|
||||||
|
batch_message(&batch),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
for msg in self.attempt_manager.register(VariantSignId::Batch(batch_hash), machines) {
|
for msg in self.attempt_manager.register(VariantSignId::Batch(batch_hash), machines) {
|
||||||
BatchSignerToCoordinatorMessages::send(&mut txn, self.session, &msg);
|
BatchSignerToCoordinatorMessages::send(&mut txn, self.session, &msg);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use core::future::Future;
|
use core::future::Future;
|
||||||
|
|
||||||
use scale::Decode;
|
use serai_primitives::Signature;
|
||||||
|
|
||||||
use serai_db::{DbTxn, Db};
|
use serai_db::{DbTxn, Db};
|
||||||
|
|
||||||
use primitives::task::ContinuallyRan;
|
use primitives::task::ContinuallyRan;
|
||||||
@@ -99,17 +100,11 @@ impl<D: Db, C: Coordinator> ContinuallyRan for CoordinatorTask<D, C> {
|
|||||||
// Publish the cosigns from this session
|
// Publish the cosigns from this session
|
||||||
{
|
{
|
||||||
let mut txn = self.db.txn();
|
let mut txn = self.db.txn();
|
||||||
while let Some(((block_number, block_id), signature)) =
|
while let Some(signed_cosign) = Cosign::try_recv(&mut txn, session) {
|
||||||
Cosign::try_recv(&mut txn, session)
|
|
||||||
{
|
|
||||||
iterated = true;
|
iterated = true;
|
||||||
self
|
self
|
||||||
.coordinator
|
.coordinator
|
||||||
.publish_cosign(
|
.publish_cosign(signed_cosign)
|
||||||
block_number,
|
|
||||||
block_id,
|
|
||||||
<_>::decode(&mut signature.as_slice()).unwrap(),
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("couldn't publish Cosign: {e:?}"))?;
|
.map_err(|e| format!("couldn't publish Cosign: {e:?}"))?;
|
||||||
}
|
}
|
||||||
@@ -119,15 +114,12 @@ impl<D: Db, C: Coordinator> ContinuallyRan for CoordinatorTask<D, C> {
|
|||||||
// If this session signed its slash report, publish its signature
|
// If this session signed its slash report, publish its signature
|
||||||
{
|
{
|
||||||
let mut txn = self.db.txn();
|
let mut txn = self.db.txn();
|
||||||
if let Some(slash_report_signature) = SlashReportSignature::try_recv(&mut txn, session) {
|
if let Some((slash_report, signature)) = SignedSlashReport::try_recv(&mut txn, session) {
|
||||||
iterated = true;
|
iterated = true;
|
||||||
|
|
||||||
self
|
self
|
||||||
.coordinator
|
.coordinator
|
||||||
.publish_slash_report_signature(
|
.publish_slash_report_signature(session, slash_report, Signature(signature))
|
||||||
session,
|
|
||||||
<_>::decode(&mut slash_report_signature.as_slice()).unwrap(),
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
format!("couldn't send slash report signature to the coordinator: {e:?}")
|
format!("couldn't send slash report signature to the coordinator: {e:?}")
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ use serai_validator_sets_primitives::Session;
|
|||||||
|
|
||||||
use serai_db::{DbTxn, Db};
|
use serai_db::{DbTxn, Db};
|
||||||
|
|
||||||
use messages::{sign::VariantSignId, coordinator::cosign_block_msg};
|
use serai_cosign::{COSIGN_CONTEXT, Cosign as CosignStruct, SignedCosign};
|
||||||
|
use messages::sign::VariantSignId;
|
||||||
|
|
||||||
use primitives::task::{DoesNotError, ContinuallyRan};
|
use primitives::task::{DoesNotError, ContinuallyRan};
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ pub(crate) struct CosignerTask<D: Db> {
|
|||||||
session: Session,
|
session: Session,
|
||||||
keys: Vec<ThresholdKeys<Ristretto>>,
|
keys: Vec<ThresholdKeys<Ristretto>>,
|
||||||
|
|
||||||
current_cosign: Option<(u64, [u8; 32])>,
|
current_cosign: Option<CosignStruct>,
|
||||||
attempt_manager: AttemptManager<D, WrappedSchnorrkelMachine>,
|
attempt_manager: AttemptManager<D, WrappedSchnorrkelMachine>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,26 +63,34 @@ impl<D: Db> ContinuallyRan for CosignerTask<D> {
|
|||||||
let mut txn = self.db.txn();
|
let mut txn = self.db.txn();
|
||||||
if let Some(cosign) = ToCosign::get(&txn, self.session) {
|
if let Some(cosign) = ToCosign::get(&txn, self.session) {
|
||||||
// If this wasn't already signed for...
|
// If this wasn't already signed for...
|
||||||
if LatestCosigned::get(&txn, self.session) < Some(cosign.0) {
|
if LatestCosigned::get(&txn, self.session) < Some(cosign.block_number) {
|
||||||
// If this isn't the cosign we're currently working on, meaning it's fresh
|
// If this isn't the cosign we're currently working on, meaning it's fresh
|
||||||
if self.current_cosign != Some(cosign) {
|
if self.current_cosign.as_ref() != Some(&cosign) {
|
||||||
// Retire the current cosign
|
// Retire the current cosign
|
||||||
if let Some(current_cosign) = self.current_cosign {
|
if let Some(current_cosign) = &self.current_cosign {
|
||||||
assert!(current_cosign.0 < cosign.0);
|
assert!(current_cosign.block_number < cosign.block_number);
|
||||||
self.attempt_manager.retire(&mut txn, VariantSignId::Cosign(current_cosign.0));
|
self
|
||||||
|
.attempt_manager
|
||||||
|
.retire(&mut txn, VariantSignId::Cosign(current_cosign.block_number));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the cosign being worked on
|
// Set the cosign being worked on
|
||||||
self.current_cosign = Some(cosign);
|
self.current_cosign = Some(cosign.clone());
|
||||||
|
|
||||||
let mut machines = Vec::with_capacity(self.keys.len());
|
let mut machines = Vec::with_capacity(self.keys.len());
|
||||||
{
|
{
|
||||||
let message = cosign_block_msg(cosign.0, cosign.1);
|
let message = cosign.signature_message();
|
||||||
for keys in &self.keys {
|
for keys in &self.keys {
|
||||||
machines.push(WrappedSchnorrkelMachine::new(keys.clone(), message.clone()));
|
machines.push(WrappedSchnorrkelMachine::new(
|
||||||
|
keys.clone(),
|
||||||
|
COSIGN_CONTEXT,
|
||||||
|
message.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for msg in self.attempt_manager.register(VariantSignId::Cosign(cosign.0), machines) {
|
for msg in
|
||||||
|
self.attempt_manager.register(VariantSignId::Cosign(cosign.block_number), machines)
|
||||||
|
{
|
||||||
CosignerToCoordinatorMessages::send(&mut txn, self.session, &msg);
|
CosignerToCoordinatorMessages::send(&mut txn, self.session, &msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,12 +118,19 @@ impl<D: Db> ContinuallyRan for CosignerTask<D> {
|
|||||||
let VariantSignId::Cosign(block_number) = id else {
|
let VariantSignId::Cosign(block_number) = id else {
|
||||||
panic!("CosignerTask signed a non-Cosign")
|
panic!("CosignerTask signed a non-Cosign")
|
||||||
};
|
};
|
||||||
assert_eq!(Some(block_number), self.current_cosign.map(|cosign| cosign.0));
|
assert_eq!(
|
||||||
|
Some(block_number),
|
||||||
|
self.current_cosign.as_ref().map(|cosign| cosign.block_number)
|
||||||
|
);
|
||||||
|
|
||||||
let cosign = self.current_cosign.take().unwrap();
|
let cosign = self.current_cosign.take().unwrap();
|
||||||
LatestCosigned::set(&mut txn, self.session, &cosign.0);
|
LatestCosigned::set(&mut txn, self.session, &cosign.block_number);
|
||||||
|
let cosign = SignedCosign {
|
||||||
|
cosign,
|
||||||
|
signature: Signature::from(signature).encode().try_into().unwrap(),
|
||||||
|
};
|
||||||
// Send the cosign
|
// Send the cosign
|
||||||
Cosign::send(&mut txn, self.session, &(cosign, Signature::from(signature).encode()));
|
Cosign::send(&mut txn, self.session, &cosign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use serai_validator_sets_primitives::{Session, Slash};
|
use serai_validator_sets_primitives::{Session, SlashReport as SlashReportStruct};
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn, create_db, db_channel};
|
use serai_db::{Get, DbTxn, create_db, db_channel};
|
||||||
|
|
||||||
|
use serai_cosign::{Cosign as CosignStruct, SignedCosign};
|
||||||
|
|
||||||
use messages::sign::{ProcessorMessage, CoordinatorMessage};
|
use messages::sign::{ProcessorMessage, CoordinatorMessage};
|
||||||
|
|
||||||
create_db! {
|
create_db! {
|
||||||
@@ -11,16 +13,16 @@ create_db! {
|
|||||||
LatestRetiredSession: () -> Session,
|
LatestRetiredSession: () -> Session,
|
||||||
ToCleanup: () -> Vec<(Session, Vec<u8>)>,
|
ToCleanup: () -> Vec<(Session, Vec<u8>)>,
|
||||||
|
|
||||||
ToCosign: (session: Session) -> (u64, [u8; 32]),
|
ToCosign: (session: Session) -> CosignStruct,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db_channel! {
|
db_channel! {
|
||||||
SignersGlobal {
|
SignersGlobal {
|
||||||
Cosign: (session: Session) -> ((u64, [u8; 32]), Vec<u8>),
|
Cosign: (session: Session) -> SignedCosign,
|
||||||
|
|
||||||
SlashReport: (session: Session) -> Vec<Slash>,
|
SlashReport: (session: Session) -> SlashReportStruct,
|
||||||
SlashReportSignature: (session: Session) -> Vec<u8>,
|
SignedSlashReport: (session: Session) -> (SlashReportStruct, [u8; 64]),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: Most of these are pointless? We drop all active signing sessions on reboot. It's
|
TODO: Most of these are pointless? We drop all active signing sessions on reboot. It's
|
||||||
|
|||||||
@@ -11,11 +11,13 @@ use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto};
|
|||||||
use frost::dkg::{ThresholdCore, ThresholdKeys};
|
use frost::dkg::{ThresholdCore, ThresholdKeys};
|
||||||
|
|
||||||
use serai_primitives::Signature;
|
use serai_primitives::Signature;
|
||||||
use serai_validator_sets_primitives::{Session, Slash};
|
use serai_validator_sets_primitives::{Session, SlashReport};
|
||||||
use serai_in_instructions_primitives::SignedBatch;
|
use serai_in_instructions_primitives::SignedBatch;
|
||||||
|
|
||||||
use serai_db::{DbTxn, Db};
|
use serai_db::{DbTxn, Db};
|
||||||
|
|
||||||
|
use serai_cosign::{Cosign, SignedCosign};
|
||||||
|
|
||||||
use messages::sign::{VariantSignId, ProcessorMessage, CoordinatorMessage};
|
use messages::sign::{VariantSignId, ProcessorMessage, CoordinatorMessage};
|
||||||
|
|
||||||
use primitives::task::{Task, TaskHandle, ContinuallyRan};
|
use primitives::task::{Task, TaskHandle, ContinuallyRan};
|
||||||
@@ -59,9 +61,7 @@ pub trait Coordinator: 'static + Send + Sync {
|
|||||||
/// Publish a cosign.
|
/// Publish a cosign.
|
||||||
fn publish_cosign(
|
fn publish_cosign(
|
||||||
&mut self,
|
&mut self,
|
||||||
block_number: u64,
|
signed_cosign: SignedCosign,
|
||||||
block_id: [u8; 32],
|
|
||||||
signature: Signature,
|
|
||||||
) -> impl Send + Future<Output = Result<(), Self::EphemeralError>>;
|
) -> impl Send + Future<Output = Result<(), Self::EphemeralError>>;
|
||||||
|
|
||||||
/// Publish a `SignedBatch`.
|
/// Publish a `SignedBatch`.
|
||||||
@@ -74,6 +74,7 @@ pub trait Coordinator: 'static + Send + Sync {
|
|||||||
fn publish_slash_report_signature(
|
fn publish_slash_report_signature(
|
||||||
&mut self,
|
&mut self,
|
||||||
session: Session,
|
session: Session,
|
||||||
|
slash_report: SlashReport,
|
||||||
signature: Signature,
|
signature: Signature,
|
||||||
) -> impl Send + Future<Output = Result<(), Self::EphemeralError>>;
|
) -> impl Send + Future<Output = Result<(), Self::EphemeralError>>;
|
||||||
}
|
}
|
||||||
@@ -408,19 +409,13 @@ impl<
|
|||||||
/// Cosign a block.
|
/// Cosign a block.
|
||||||
///
|
///
|
||||||
/// This is a cheap call and able to be done inline from a higher-level loop.
|
/// This is a cheap call and able to be done inline from a higher-level loop.
|
||||||
pub fn cosign_block(
|
pub fn cosign_block(&mut self, mut txn: impl DbTxn, session: Session, cosign: &Cosign) {
|
||||||
&mut self,
|
|
||||||
mut txn: impl DbTxn,
|
|
||||||
session: Session,
|
|
||||||
block_number: u64,
|
|
||||||
block: [u8; 32],
|
|
||||||
) {
|
|
||||||
// Don't cosign blocks with already retired keys
|
// Don't cosign blocks with already retired keys
|
||||||
if Some(session.0) <= db::LatestRetiredSession::get(&txn).map(|session| session.0) {
|
if Some(session.0) <= db::LatestRetiredSession::get(&txn).map(|session| session.0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
db::ToCosign::set(&mut txn, session, &(block_number, block));
|
db::ToCosign::set(&mut txn, session, cosign);
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
|
||||||
if let Some(tasks) = self.tasks.get(&session) {
|
if let Some(tasks) = self.tasks.get(&session) {
|
||||||
@@ -435,7 +430,7 @@ impl<
|
|||||||
&mut self,
|
&mut self,
|
||||||
mut txn: impl DbTxn,
|
mut txn: impl DbTxn,
|
||||||
session: Session,
|
session: Session,
|
||||||
slash_report: &Vec<Slash>,
|
slash_report: &SlashReport,
|
||||||
) {
|
) {
|
||||||
// Don't sign slash reports with already retired keys
|
// Don't sign slash reports with already retired keys
|
||||||
if Some(session.0) <= db::LatestRetiredSession::get(&txn).map(|session| session.0) {
|
if Some(session.0) <= db::LatestRetiredSession::get(&txn).map(|session| session.0) {
|
||||||
|
|||||||
@@ -3,11 +3,8 @@ use core::{marker::PhantomData, future::Future};
|
|||||||
use ciphersuite::Ristretto;
|
use ciphersuite::Ristretto;
|
||||||
use frost::dkg::ThresholdKeys;
|
use frost::dkg::ThresholdKeys;
|
||||||
|
|
||||||
use scale::Encode;
|
|
||||||
use serai_primitives::Signature;
|
use serai_primitives::Signature;
|
||||||
use serai_validator_sets_primitives::{
|
use serai_validator_sets_primitives::Session;
|
||||||
Session, ValidatorSet, SlashReport as SlashReportStruct, report_slashes_message,
|
|
||||||
};
|
|
||||||
|
|
||||||
use serai_db::{DbTxn, Db};
|
use serai_db::{DbTxn, Db};
|
||||||
|
|
||||||
@@ -20,7 +17,7 @@ use frost_attempt_manager::*;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::{
|
db::{
|
||||||
SlashReport, SlashReportSignature, CoordinatorToSlashReportSignerMessages,
|
SlashReport, SignedSlashReport, CoordinatorToSlashReportSignerMessages,
|
||||||
SlashReportSignerToCoordinatorMessages,
|
SlashReportSignerToCoordinatorMessages,
|
||||||
},
|
},
|
||||||
WrappedSchnorrkelMachine,
|
WrappedSchnorrkelMachine,
|
||||||
@@ -72,12 +69,14 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for SlashReportSignerTask<D, S> {
|
|||||||
|
|
||||||
let mut machines = Vec::with_capacity(self.keys.len());
|
let mut machines = Vec::with_capacity(self.keys.len());
|
||||||
{
|
{
|
||||||
let message = report_slashes_message(
|
let message = slash_report.report_slashes_message();
|
||||||
&ValidatorSet { network: S::NETWORK, session: self.session },
|
|
||||||
&SlashReportStruct(slash_report.try_into().unwrap()),
|
|
||||||
);
|
|
||||||
for keys in &self.keys {
|
for keys in &self.keys {
|
||||||
machines.push(WrappedSchnorrkelMachine::new(keys.clone(), message.clone()));
|
// TODO: Fetch this constant from somewhere instead of inlining it
|
||||||
|
machines.push(WrappedSchnorrkelMachine::new(
|
||||||
|
keys.clone(),
|
||||||
|
b"substrate",
|
||||||
|
message.clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut txn = self.db.txn();
|
let mut txn = self.db.txn();
|
||||||
@@ -105,12 +104,12 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for SlashReportSignerTask<D, S> {
|
|||||||
Response::Signature { id, signature } => {
|
Response::Signature { id, signature } => {
|
||||||
assert_eq!(id, VariantSignId::SlashReport);
|
assert_eq!(id, VariantSignId::SlashReport);
|
||||||
// Drain the channel
|
// Drain the channel
|
||||||
SlashReport::try_recv(&mut txn, self.session).unwrap();
|
let slash_report = SlashReport::try_recv(&mut txn, self.session).unwrap();
|
||||||
// Send the signature
|
// Send the signature
|
||||||
SlashReportSignature::send(
|
SignedSlashReport::send(
|
||||||
&mut txn,
|
&mut txn,
|
||||||
self.session,
|
self.session,
|
||||||
&Signature::from(signature).encode(),
|
&(slash_report, Signature::from(signature).0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ use frost_schnorrkel::Schnorrkel;
|
|||||||
|
|
||||||
// This wraps a Schnorrkel sign machine into one with a preset message.
|
// This wraps a Schnorrkel sign machine into one with a preset message.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct WrappedSchnorrkelMachine(ThresholdKeys<Ristretto>, Vec<u8>);
|
pub(crate) struct WrappedSchnorrkelMachine(ThresholdKeys<Ristretto>, &'static [u8], Vec<u8>);
|
||||||
impl WrappedSchnorrkelMachine {
|
impl WrappedSchnorrkelMachine {
|
||||||
pub(crate) fn new(keys: ThresholdKeys<Ristretto>, msg: Vec<u8>) -> Self {
|
pub(crate) fn new(keys: ThresholdKeys<Ristretto>, context: &'static [u8], msg: Vec<u8>) -> Self {
|
||||||
Self(keys, msg)
|
Self(keys, context, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,10 +39,10 @@ impl PreprocessMachine for WrappedSchnorrkelMachine {
|
|||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> (Self::SignMachine, Preprocess<Ristretto, <Schnorrkel as Algorithm<Ristretto>>::Addendum>)
|
) -> (Self::SignMachine, Preprocess<Ristretto, <Schnorrkel as Algorithm<Ristretto>>::Addendum>)
|
||||||
{
|
{
|
||||||
let WrappedSchnorrkelMachine(keys, batch) = self;
|
let WrappedSchnorrkelMachine(keys, context, msg) = self;
|
||||||
let (machine, preprocess) =
|
let (machine, preprocess) =
|
||||||
AlgorithmMachine::new(Schnorrkel::new(b"substrate"), keys).preprocess(rng);
|
AlgorithmMachine::new(Schnorrkel::new(context), keys).preprocess(rng);
|
||||||
(WrappedSchnorrkelSignMachine(machine, batch), preprocess)
|
(WrappedSchnorrkelSignMachine(machine, msg), preprocess)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ pub type CoinsEvent = serai_abi::coins::Event;
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct SeraiCoins<'a>(pub(crate) &'a TemporalSerai<'a>);
|
pub struct SeraiCoins<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||||
impl<'a> SeraiCoins<'a> {
|
impl SeraiCoins<'_> {
|
||||||
pub async fn mint_events(&self) -> Result<Vec<CoinsEvent>, SeraiError> {
|
pub async fn mint_events(&self) -> Result<Vec<CoinsEvent>, SeraiError> {
|
||||||
self
|
self
|
||||||
.0
|
.0
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const PALLET: &str = "Dex";
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct SeraiDex<'a>(pub(crate) &'a TemporalSerai<'a>);
|
pub struct SeraiDex<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||||
impl<'a> SeraiDex<'a> {
|
impl SeraiDex<'_> {
|
||||||
pub async fn events(&self) -> Result<Vec<DexEvent>, SeraiError> {
|
pub async fn events(&self) -> Result<Vec<DexEvent>, SeraiError> {
|
||||||
self
|
self
|
||||||
.0
|
.0
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const PALLET: &str = "GenesisLiquidity";
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct SeraiGenesisLiquidity<'a>(pub(crate) &'a TemporalSerai<'a>);
|
pub struct SeraiGenesisLiquidity<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||||
impl<'a> SeraiGenesisLiquidity<'a> {
|
impl SeraiGenesisLiquidity<'_> {
|
||||||
pub async fn events(&self) -> Result<Vec<GenesisLiquidityEvent>, SeraiError> {
|
pub async fn events(&self) -> Result<Vec<GenesisLiquidityEvent>, SeraiError> {
|
||||||
self
|
self
|
||||||
.0
|
.0
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const PALLET: &str = "InInstructions";
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct SeraiInInstructions<'a>(pub(crate) &'a TemporalSerai<'a>);
|
pub struct SeraiInInstructions<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||||
impl<'a> SeraiInInstructions<'a> {
|
impl SeraiInInstructions<'_> {
|
||||||
pub async fn last_batch_for_network(
|
pub async fn last_batch_for_network(
|
||||||
&self,
|
&self,
|
||||||
network: NetworkId,
|
network: NetworkId,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const PALLET: &str = "LiquidityTokens";
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct SeraiLiquidityTokens<'a>(pub(crate) &'a TemporalSerai<'a>);
|
pub struct SeraiLiquidityTokens<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||||
impl<'a> SeraiLiquidityTokens<'a> {
|
impl SeraiLiquidityTokens<'_> {
|
||||||
pub async fn token_supply(&self, coin: Coin) -> Result<Amount, SeraiError> {
|
pub async fn token_supply(&self, coin: Coin) -> Result<Amount, SeraiError> {
|
||||||
Ok(self.0.storage(PALLET, "Supply", coin).await?.unwrap_or(Amount(0)))
|
Ok(self.0.storage(PALLET, "Supply", coin).await?.unwrap_or(Amount(0)))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ pub struct TemporalSerai<'a> {
|
|||||||
block: [u8; 32],
|
block: [u8; 32],
|
||||||
events: RwLock<Option<EventsInBlock>>,
|
events: RwLock<Option<EventsInBlock>>,
|
||||||
}
|
}
|
||||||
impl<'a> Clone for TemporalSerai<'a> {
|
impl Clone for TemporalSerai<'_> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self { serai: self.serai, block: self.block, events: RwLock::new(None) }
|
Self { serai: self.serai, block: self.block, events: RwLock::new(None) }
|
||||||
}
|
}
|
||||||
@@ -319,7 +319,7 @@ impl Serai {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TemporalSerai<'a> {
|
impl TemporalSerai<'_> {
|
||||||
async fn events<E>(
|
async fn events<E>(
|
||||||
&self,
|
&self,
|
||||||
filter_map: impl Fn(&Event) -> Option<E>,
|
filter_map: impl Fn(&Event) -> Option<E>,
|
||||||
@@ -389,27 +389,27 @@ impl<'a> TemporalSerai<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn coins(&'a self) -> SeraiCoins<'a> {
|
pub fn coins(&self) -> SeraiCoins<'_> {
|
||||||
SeraiCoins(self)
|
SeraiCoins(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dex(&'a self) -> SeraiDex<'a> {
|
pub fn dex(&self) -> SeraiDex<'_> {
|
||||||
SeraiDex(self)
|
SeraiDex(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn in_instructions(&'a self) -> SeraiInInstructions<'a> {
|
pub fn in_instructions(&self) -> SeraiInInstructions<'_> {
|
||||||
SeraiInInstructions(self)
|
SeraiInInstructions(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validator_sets(&'a self) -> SeraiValidatorSets<'a> {
|
pub fn validator_sets(&self) -> SeraiValidatorSets<'_> {
|
||||||
SeraiValidatorSets(self)
|
SeraiValidatorSets(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn genesis_liquidity(&'a self) -> SeraiGenesisLiquidity {
|
pub fn genesis_liquidity(&self) -> SeraiGenesisLiquidity {
|
||||||
SeraiGenesisLiquidity(self)
|
SeraiGenesisLiquidity(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn liquidity_tokens(&'a self) -> SeraiLiquidityTokens {
|
pub fn liquidity_tokens(&self) -> SeraiLiquidityTokens {
|
||||||
SeraiLiquidityTokens(self)
|
SeraiLiquidityTokens(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ pub type ValidatorSetsEvent = serai_abi::validator_sets::Event;
|
|||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct SeraiValidatorSets<'a>(pub(crate) &'a TemporalSerai<'a>);
|
pub struct SeraiValidatorSets<'a>(pub(crate) &'a TemporalSerai<'a>);
|
||||||
impl<'a> SeraiValidatorSets<'a> {
|
impl SeraiValidatorSets<'_> {
|
||||||
pub async fn new_set_events(&self) -> Result<Vec<ValidatorSetsEvent>, SeraiError> {
|
pub async fn new_set_events(&self) -> Result<Vec<ValidatorSetsEvent>, SeraiError> {
|
||||||
self
|
self
|
||||||
.0
|
.0
|
||||||
|
|||||||
@@ -20,71 +20,71 @@ workspace = true
|
|||||||
name = "serai-node"
|
name = "serai-node"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand_core = "0.6"
|
#rand_core = "0.6"
|
||||||
zeroize = "1"
|
#zeroize = "1"
|
||||||
hex = "0.4"
|
#hex = "0.4"
|
||||||
log = "0.4"
|
#log = "0.4"
|
||||||
|
|
||||||
schnorrkel = "0.11"
|
#schnorrkel = "0.11"
|
||||||
|
|
||||||
ciphersuite = { path = "../../crypto/ciphersuite" }
|
#ciphersuite = { path = "../../crypto/ciphersuite" }
|
||||||
embedwards25519 = { path = "../../crypto/evrf/embedwards25519" }
|
#embedwards25519 = { path = "../../crypto/evrf/embedwards25519" }
|
||||||
secq256k1 = { path = "../../crypto/evrf/secq256k1" }
|
#secq256k1 = { path = "../../crypto/evrf/secq256k1" }
|
||||||
|
|
||||||
libp2p = "0.52"
|
#libp2p = "0.52"
|
||||||
|
|
||||||
sp-core = { git = "https://github.com/serai-dex/substrate" }
|
#sp-core = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-keystore = { git = "https://github.com/serai-dex/substrate" }
|
#sp-keystore = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-timestamp = { git = "https://github.com/serai-dex/substrate" }
|
#sp-timestamp = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-io = { git = "https://github.com/serai-dex/substrate" }
|
#sp-io = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-blockchain = { git = "https://github.com/serai-dex/substrate" }
|
#sp-blockchain = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-api = { git = "https://github.com/serai-dex/substrate" }
|
#sp-api = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-block-builder = { git = "https://github.com/serai-dex/substrate" }
|
#sp-block-builder = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sp-consensus-babe = { git = "https://github.com/serai-dex/substrate" }
|
#sp-consensus-babe = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
frame-benchmarking = { git = "https://github.com/serai-dex/substrate" }
|
#frame-benchmarking = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
serai-runtime = { path = "../runtime", features = ["std"] }
|
#serai-runtime = { path = "../runtime", features = ["std"] }
|
||||||
|
|
||||||
clap = { version = "4", features = ["derive"] }
|
#clap = { version = "4", features = ["derive"] }
|
||||||
|
|
||||||
futures-util = "0.3"
|
#futures-util = "0.3"
|
||||||
tokio = { version = "1", features = ["sync", "rt-multi-thread"] }
|
#tokio = { version = "1", features = ["sync", "rt-multi-thread"] }
|
||||||
jsonrpsee = { version = "0.16", features = ["server"] }
|
#jsonrpsee = { version = "0.16", features = ["server"] }
|
||||||
|
|
||||||
sc-offchain = { git = "https://github.com/serai-dex/substrate" }
|
#sc-offchain = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-transaction-pool = { git = "https://github.com/serai-dex/substrate" }
|
#sc-transaction-pool = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-transaction-pool-api = { git = "https://github.com/serai-dex/substrate" }
|
#sc-transaction-pool-api = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-basic-authorship = { git = "https://github.com/serai-dex/substrate" }
|
#sc-basic-authorship = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-executor = { git = "https://github.com/serai-dex/substrate" }
|
#sc-executor = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-service = { git = "https://github.com/serai-dex/substrate" }
|
#sc-service = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-client-api = { git = "https://github.com/serai-dex/substrate" }
|
#sc-client-api = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-network-common = { git = "https://github.com/serai-dex/substrate" }
|
#sc-network-common = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-network = { git = "https://github.com/serai-dex/substrate" }
|
#sc-network = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
sc-consensus = { git = "https://github.com/serai-dex/substrate" }
|
#sc-consensus = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-consensus-babe = { git = "https://github.com/serai-dex/substrate" }
|
#sc-consensus-babe = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-consensus-grandpa = { git = "https://github.com/serai-dex/substrate" }
|
#sc-consensus-grandpa = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-authority-discovery = { git = "https://github.com/serai-dex/substrate" }
|
#sc-authority-discovery = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
sc-telemetry = { git = "https://github.com/serai-dex/substrate" }
|
#sc-telemetry = { git = "https://github.com/serai-dex/substrate" }
|
||||||
sc-cli = { git = "https://github.com/serai-dex/substrate" }
|
#sc-cli = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
sc-rpc-api = { git = "https://github.com/serai-dex/substrate" }
|
#sc-rpc-api = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
substrate-frame-rpc-system = { git = "https://github.com/serai-dex/substrate" }
|
#substrate-frame-rpc-system = { git = "https://github.com/serai-dex/substrate" }
|
||||||
pallet-transaction-payment-rpc = { git = "https://github.com/serai-dex/substrate" }
|
#pallet-transaction-payment-rpc = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
serai-env = { path = "../../common/env" }
|
#serai-env = { path = "../../common/env" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
substrate-build-script-utils = { git = "https://github.com/serai-dex/substrate" }
|
#substrate-build-script-utils = { git = "https://github.com/serai-dex/substrate" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
#default = []
|
||||||
fast-epoch = ["serai-runtime/fast-epoch"]
|
#fast-epoch = ["serai-runtime/fast-epoch"]
|
||||||
runtime-benchmarks = [
|
#runtime-benchmarks = [
|
||||||
"frame-benchmarking/runtime-benchmarks",
|
# "frame-benchmarking/runtime-benchmarks",
|
||||||
|
|
||||||
"serai-runtime/runtime-benchmarks",
|
# "serai-runtime/runtime-benchmarks",
|
||||||
]
|
#]
|
||||||
|
|||||||
@@ -234,9 +234,12 @@ impl TryFrom<Vec<Slash>> for SlashReport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is assumed binding to the ValidatorSet via the key signed with
|
impl SlashReport {
|
||||||
pub fn report_slashes_message(slashes: &SlashReport) -> Vec<u8> {
|
/// The message to sign when publishing this SlashReport.
|
||||||
(b"ValidatorSets-report_slashes", slashes).encode()
|
// This is assumed binding to the ValidatorSet via the key signed with
|
||||||
|
pub fn report_slashes_message(&self) -> Vec<u8> {
|
||||||
|
(b"ValidatorSets-report_slashes", &self.0).encode()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user