mirror of
https://github.com/serai-dex/serai.git
synced 2024-11-17 01:17:36 +00:00
Create a vote transaction upon GeneratedKeyPair
This commit is contained in:
parent
c95bdb6752
commit
168f2899f0
4 changed files with 90 additions and 11 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -1319,6 +1319,7 @@ dependencies = [
|
||||||
"ciphersuite",
|
"ciphersuite",
|
||||||
"flexible-transcript",
|
"flexible-transcript",
|
||||||
"futures",
|
"futures",
|
||||||
|
"hex",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"modular-frost",
|
"modular-frost",
|
||||||
|
@ -1326,6 +1327,7 @@ dependencies = [
|
||||||
"processor-messages",
|
"processor-messages",
|
||||||
"rand_core 0.6.4",
|
"rand_core 0.6.4",
|
||||||
"schnorr-signatures",
|
"schnorr-signatures",
|
||||||
|
"schnorrkel",
|
||||||
"serai-client",
|
"serai-client",
|
||||||
"serai-db",
|
"serai-db",
|
||||||
"sp-application-crypto",
|
"sp-application-crypto",
|
||||||
|
|
|
@ -29,6 +29,7 @@ frost = { package = "modular-frost", path = "../crypto/frost" }
|
||||||
|
|
||||||
scale = { package = "parity-scale-codec", version = "3", features = ["derive"] }
|
scale = { package = "parity-scale-codec", version = "3", features = ["derive"] }
|
||||||
|
|
||||||
|
schnorrkel = "0.10"
|
||||||
sp-application-crypto = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
sp-application-crypto = { git = "https://github.com/serai-dex/substrate", default-features = false }
|
||||||
|
|
||||||
serai-db = { path = "../common/db" }
|
serai-db = { path = "../common/db" }
|
||||||
|
@ -38,6 +39,7 @@ tributary = { package = "tributary-chain", path = "./tributary" }
|
||||||
|
|
||||||
serai-client = { path = "../substrate/client", features = ["serai"] }
|
serai-client = { path = "../substrate/client", features = ["serai"] }
|
||||||
|
|
||||||
|
hex = "0.4"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,22 @@ use std::{
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
use rand_core::OsRng;
|
use rand_core::OsRng;
|
||||||
|
|
||||||
use ciphersuite::{group::ff::Field, Ciphersuite, Ristretto};
|
use blake2::Digest;
|
||||||
|
|
||||||
|
use ciphersuite::{
|
||||||
|
group::{
|
||||||
|
ff::{Field, PrimeField},
|
||||||
|
GroupEncoding,
|
||||||
|
},
|
||||||
|
Ciphersuite, Ristretto,
|
||||||
|
};
|
||||||
|
|
||||||
use serai_db::{DbTxn, Db, MemDb};
|
use serai_db::{DbTxn, Db, MemDb};
|
||||||
use serai_client::Serai;
|
|
||||||
|
use serai_client::{
|
||||||
|
subxt::{config::extrinsic_params::BaseExtrinsicParamsBuilder, tx::Signer},
|
||||||
|
Public, PairSigner, Serai,
|
||||||
|
};
|
||||||
|
|
||||||
use tokio::{
|
use tokio::{
|
||||||
sync::{
|
sync::{
|
||||||
|
@ -316,8 +328,11 @@ pub async fn handle_p2p<D: Db, P: P2p>(
|
||||||
// missing
|
// missing
|
||||||
// sync_block waiting is preferable since we know the block is valid by its commit, meaning
|
// sync_block waiting is preferable since we know the block is valid by its commit, meaning
|
||||||
// we are the node behind
|
// we are the node behind
|
||||||
// A for 1/2, 1 may be preferable since this message may frequently occur
|
// As for 1/2, 1 may be preferable since this message may frequently occur
|
||||||
// We at least need to check if we take value from this message before running spawn
|
// This is suitably performant, as tokio HTTP servers will even spawn a new task per
|
||||||
|
// connection
|
||||||
|
// In order to reduce congestion though, we should at least check if we take value from
|
||||||
|
// this message before running spawn
|
||||||
// TODO
|
// TODO
|
||||||
tokio::spawn({
|
tokio::spawn({
|
||||||
let tributaries = tributaries.clone();
|
let tributaries = tributaries.clone();
|
||||||
|
@ -362,11 +377,25 @@ pub async fn publish_transaction<D: Db, P: P2p>(
|
||||||
pub async fn handle_processors<D: Db, Pro: Processors, P: P2p>(
|
pub async fn handle_processors<D: Db, Pro: Processors, P: P2p>(
|
||||||
mut db: D,
|
mut db: D,
|
||||||
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
key: Zeroizing<<Ristretto as Ciphersuite>::F>,
|
||||||
|
serai: Serai,
|
||||||
mut processors: Pro,
|
mut processors: Pro,
|
||||||
tributaries: Arc<RwLock<HashMap<[u8; 32], ActiveTributary<D, P>>>>,
|
tributaries: Arc<RwLock<HashMap<[u8; 32], ActiveTributary<D, P>>>>,
|
||||||
) {
|
) {
|
||||||
let pub_key = Ristretto::generator() * key.deref();
|
let pub_key = Ristretto::generator() * key.deref();
|
||||||
|
|
||||||
|
// TODO: This is cursed. serai_client has to handle this for us
|
||||||
|
let substrate_signer = {
|
||||||
|
let mut bytes = Zeroizing::new([0; 96]);
|
||||||
|
// Private key
|
||||||
|
bytes[.. 32].copy_from_slice(&key.to_repr());
|
||||||
|
// Nonce
|
||||||
|
let nonce = Zeroizing::new(blake2::Blake2s256::digest(&bytes));
|
||||||
|
bytes[32 .. 64].copy_from_slice(nonce.as_ref());
|
||||||
|
// Public key
|
||||||
|
bytes[64 ..].copy_from_slice(&pub_key.to_bytes());
|
||||||
|
PairSigner::new(schnorrkel::keys::Keypair::from_bytes(bytes.as_ref()).unwrap().into())
|
||||||
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let msg = processors.recv().await;
|
let msg = processors.recv().await;
|
||||||
|
|
||||||
|
@ -384,15 +413,57 @@ pub async fn handle_processors<D: Db, Pro: Processors, P: P2p>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let tx = match msg.msg {
|
let tx = match msg.msg {
|
||||||
ProcessorMessage::KeyGen(msg) => match msg {
|
ProcessorMessage::KeyGen(inner_msg) => match inner_msg {
|
||||||
key_gen::ProcessorMessage::Commitments { id, commitments } => {
|
key_gen::ProcessorMessage::Commitments { id, commitments } => {
|
||||||
Some(Transaction::DkgCommitments(id.attempt, commitments, Transaction::empty_signed()))
|
Some(Transaction::DkgCommitments(id.attempt, commitments, Transaction::empty_signed()))
|
||||||
}
|
}
|
||||||
key_gen::ProcessorMessage::Shares { id, shares } => {
|
key_gen::ProcessorMessage::Shares { id, shares } => {
|
||||||
Some(Transaction::DkgShares(id.attempt, shares, Transaction::empty_signed()))
|
Some(Transaction::DkgShares(id.attempt, shares, Transaction::empty_signed()))
|
||||||
}
|
}
|
||||||
// TODO
|
key_gen::ProcessorMessage::GeneratedKeyPair { id, substrate_key, coin_key } => {
|
||||||
key_gen::ProcessorMessage::GeneratedKeyPair { .. } => todo!(),
|
assert_eq!(
|
||||||
|
id.set.network, msg.network,
|
||||||
|
"processor claimed to be a different network than it was for SubstrateBlockAck",
|
||||||
|
);
|
||||||
|
// TODO: Also check the other KeyGenId fields
|
||||||
|
|
||||||
|
// TODO: Is this safe?
|
||||||
|
let Ok(nonce) = serai.get_nonce(&substrate_signer.address()).await else {
|
||||||
|
log::error!("couldn't connect to Serai node to get nonce");
|
||||||
|
todo!(); // TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
let tx = serai
|
||||||
|
.sign(
|
||||||
|
&substrate_signer,
|
||||||
|
&Serai::vote(
|
||||||
|
msg.network,
|
||||||
|
(
|
||||||
|
Public(substrate_key),
|
||||||
|
coin_key
|
||||||
|
.try_into()
|
||||||
|
.expect("external key from processor exceeded max external key length"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
nonce,
|
||||||
|
BaseExtrinsicParamsBuilder::new(),
|
||||||
|
)
|
||||||
|
.expect(
|
||||||
|
"tried to sign an invalid payload despite creating the payload via serai_client",
|
||||||
|
);
|
||||||
|
|
||||||
|
match serai.publish(&tx).await {
|
||||||
|
Ok(hash) => {
|
||||||
|
log::info!("voted on key pair for {:?} in TX {}", id.set, hex::encode(hash))
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("couldn't connect to Serai node to publish TX: {:?}", e);
|
||||||
|
todo!(); // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
},
|
},
|
||||||
ProcessorMessage::Sign(msg) => match msg {
|
ProcessorMessage::Sign(msg) => match msg {
|
||||||
sign::ProcessorMessage::Preprocess { id, preprocess } => {
|
sign::ProcessorMessage::Preprocess { id, preprocess } => {
|
||||||
|
@ -423,8 +494,8 @@ pub async fn handle_processors<D: Db, Pro: Processors, P: P2p>(
|
||||||
ProcessorMessage::Coordinator(inner_msg) => match inner_msg {
|
ProcessorMessage::Coordinator(inner_msg) => match inner_msg {
|
||||||
coordinator::ProcessorMessage::SubstrateBlockAck { network, block, plans } => {
|
coordinator::ProcessorMessage::SubstrateBlockAck { network, block, plans } => {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
msg.network, network,
|
network, msg.network,
|
||||||
"processor claimed to be a different network than it was",
|
"processor claimed to be a different network than it was for SubstrateBlockAck",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Safe to use its own txn since this is static and just needs to be written before we
|
// Safe to use its own txn since this is static and just needs to be written before we
|
||||||
|
@ -600,7 +671,7 @@ pub async fn run<D: Db, Pro: Processors, P: P2p>(
|
||||||
tokio::spawn(handle_p2p(Ristretto::generator() * key.deref(), p2p, tributaries.clone()));
|
tokio::spawn(handle_p2p(Ristretto::generator() * key.deref(), p2p, tributaries.clone()));
|
||||||
|
|
||||||
// Handle all messages from processors
|
// Handle all messages from processors
|
||||||
handle_processors(raw_db, key, processors, tributaries).await;
|
handle_processors(raw_db, key, serai, processors, tributaries).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
|
|
@ -4,7 +4,10 @@ use scale::{Encode, Decode, Compact};
|
||||||
mod scale_value;
|
mod scale_value;
|
||||||
pub(crate) use scale_value::{Value, Composite, scale_value, scale_composite};
|
pub(crate) use scale_value::{Value, Composite, scale_value, scale_composite};
|
||||||
|
|
||||||
use sp_core::{Pair as PairTrait, sr25519::Pair};
|
pub use sp_core::{
|
||||||
|
Pair as PairTrait,
|
||||||
|
sr25519::{Public, Pair},
|
||||||
|
};
|
||||||
|
|
||||||
pub use subxt;
|
pub use subxt;
|
||||||
use subxt::{
|
use subxt::{
|
||||||
|
@ -294,6 +297,7 @@ impl Serai {
|
||||||
TxClient::new(self.0.offline())
|
TxClient::new(self.0.offline())
|
||||||
.create_signed_with_nonce(payload, signer, nonce, params)
|
.create_signed_with_nonce(payload, signer, nonce, params)
|
||||||
.map(|tx| Encoded(tx.into_encoded()))
|
.map(|tx| Encoded(tx.into_encoded()))
|
||||||
|
// TODO: Don't have this potentially return an error (requires modifying the Payload type)
|
||||||
.map_err(|_| SeraiError::InvalidRuntime)
|
.map_err(|_| SeraiError::InvalidRuntime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue