Add dedicated BatchSignId

This commit is contained in:
Luke Parker
2023-11-06 19:50:32 -05:00
parent 96f94966b7
commit c03fb6c71b
17 changed files with 112 additions and 116 deletions

View File

@@ -106,14 +106,14 @@ impl<D: Db> MainDb<D> {
res
}
fn first_preprocess_key(network: NetworkId, id_type: RecognizedIdType, id: [u8; 32]) -> Vec<u8> {
fn first_preprocess_key(network: NetworkId, id_type: RecognizedIdType, id: &[u8]) -> Vec<u8> {
Self::main_key(b"first_preprocess", (network, id_type, id).encode())
}
pub fn save_first_preprocess(
txn: &mut D::Transaction<'_>,
network: NetworkId,
id_type: RecognizedIdType,
id: [u8; 32],
id: &[u8],
preprocess: Vec<Vec<u8>>,
) {
let preprocess = preprocess.encode();
@@ -128,7 +128,7 @@ impl<D: Db> MainDb<D> {
getter: &G,
network: NetworkId,
id_type: RecognizedIdType,
id: [u8; 32],
id: &[u8],
) -> Option<Vec<Vec<u8>>> {
getter
.get(Self::first_preprocess_key(network, id_type, id))

View File

@@ -488,7 +488,7 @@ async fn handle_processor_message<D: Db, P: P2p>(
&mut txn,
network,
RecognizedIdType::Plan,
id.id,
&id.id,
preprocesses,
);
@@ -547,7 +547,7 @@ async fn handle_processor_message<D: Db, P: P2p>(
&mut txn,
spec.set().network,
RecognizedIdType::Batch,
id.id,
&id.id,
preprocesses,
);
@@ -877,7 +877,7 @@ pub async fn run<D: Db, Pro: Processors, P: P2p>(
}
});
move |set: ValidatorSet, genesis, id_type, id, nonce| {
move |set: ValidatorSet, genesis, id_type, id: Vec<u8>, nonce| {
let mut raw_db = raw_db.clone();
let key = key.clone();
let tributaries = tributaries.clone();
@@ -899,16 +899,16 @@ pub async fn run<D: Db, Pro: Processors, P: P2p>(
let mut tx = match id_type {
RecognizedIdType::Batch => Transaction::BatchPreprocess(SignData {
plan: id,
data: get_preprocess(&raw_db, id_type, &id).await,
plan: id.try_into().unwrap(),
attempt: 0,
data: get_preprocess(&raw_db, id_type, id).await,
signed: Transaction::empty_signed(),
}),
RecognizedIdType::Plan => Transaction::SignPreprocess(SignData {
plan: id,
data: get_preprocess(&raw_db, id_type, &id).await,
plan: id.try_into().unwrap(),
attempt: 0,
data: get_preprocess(&raw_db, id_type, id).await,
signed: Transaction::empty_signed(),
}),
};

View File

@@ -28,8 +28,8 @@ fn random_vec<R: RngCore>(rng: &mut R, limit: usize) -> Vec<u8> {
res
}
fn random_sign_data<R: RngCore>(rng: &mut R) -> SignData {
let mut plan = [0; 32];
fn random_sign_data<R: RngCore, const N: usize>(rng: &mut R) -> SignData<N> {
let mut plan = [0; N];
rng.fill_bytes(&mut plan);
SignData {
@@ -80,7 +80,10 @@ fn tx_size_limit() {
#[test]
fn serialize_sign_data() {
test_read_write(random_sign_data(&mut OsRng));
test_read_write(random_sign_data::<_, 3>(&mut OsRng));
test_read_write(random_sign_data::<_, 8>(&mut OsRng));
test_read_write(random_sign_data::<_, 16>(&mut OsRng));
test_read_write(random_sign_data::<_, 24>(&mut OsRng));
}
#[test]
@@ -143,7 +146,7 @@ fn serialize_transaction() {
{
let mut block = [0; 32];
OsRng.fill_bytes(&mut block);
let mut batch = [0; 32];
let mut batch = [0; 5];
OsRng.fill_bytes(&mut batch);
test_read_write(Transaction::Batch(block, batch));
}

View File

@@ -16,7 +16,7 @@ use crate::tributary::TributarySpec;
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Topic {
Dkg,
Batch([u8; 32]),
Batch([u8; 5]),
Sign([u8; 32]),
}

View File

@@ -18,7 +18,7 @@ use tributary::Signed;
use processor_messages::{
key_gen::{self, KeyGenId},
coordinator,
coordinator::{self, BatchSignId},
sign::{self, SignId},
};
@@ -370,7 +370,7 @@ pub(crate) async fn handle_application_tx<
// Because this Batch has achieved synchrony, its batch ID should be authorized
TributaryDb::<D>::recognize_topic(txn, genesis, Topic::Batch(batch));
let nonce = NonceDecider::<D>::handle_batch(txn, genesis, batch);
recognized_id(spec.set(), genesis, RecognizedIdType::Batch, batch, nonce).await;
recognized_id(spec.set(), genesis, RecognizedIdType::Batch, batch.to_vec(), nonce).await;
}
Transaction::SubstrateBlock(block) => {
@@ -382,7 +382,7 @@ pub(crate) async fn handle_application_tx<
let nonces = NonceDecider::<D>::handle_substrate_block(txn, genesis, &plan_ids);
for (nonce, id) in nonces.into_iter().zip(plan_ids.into_iter()) {
TributaryDb::<D>::recognize_topic(txn, genesis, Topic::Sign(id));
recognized_id(spec.set(), genesis, RecognizedIdType::Plan, id, nonce).await;
recognized_id(spec.set(), genesis, RecognizedIdType::Plan, id.to_vec(), nonce).await;
}
}
@@ -403,12 +403,12 @@ pub(crate) async fn handle_application_tx<
Accumulation::Ready(DataSet::Participating(mut preprocesses)) => {
unflatten(spec, &mut preprocesses);
NonceDecider::<D>::selected_for_signing_batch(txn, genesis, data.plan);
let key = TributaryDb::<D>::key_pair(txn, spec.set()).unwrap().0 .0.to_vec();
let key = TributaryDb::<D>::key_pair(txn, spec.set()).unwrap().0 .0;
processors
.send(
spec.set().network,
coordinator::CoordinatorMessage::BatchPreprocesses {
id: SignId { key, id: data.plan, attempt: data.attempt },
id: BatchSignId { key, id: data.plan, attempt: data.attempt },
preprocesses,
},
)
@@ -434,12 +434,12 @@ pub(crate) async fn handle_application_tx<
) {
Accumulation::Ready(DataSet::Participating(mut shares)) => {
unflatten(spec, &mut shares);
let key = TributaryDb::<D>::key_pair(txn, spec.set()).unwrap().0 .0.to_vec();
let key = TributaryDb::<D>::key_pair(txn, spec.set()).unwrap().0 .0;
processors
.send(
spec.set().network,
coordinator::CoordinatorMessage::BatchShares {
id: SignId { key, id: data.plan, attempt: data.attempt },
id: BatchSignId { key, id: data.plan, attempt: data.attempt },
shares: shares
.into_iter()
.map(|(validator, share)| (validator, share.try_into().unwrap()))

View File

@@ -167,8 +167,8 @@ impl TributarySpec {
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct SignData {
pub plan: [u8; 32],
pub struct SignData<const N: usize> {
pub plan: [u8; N],
pub attempt: u32,
pub data: Vec<Vec<u8>>,
@@ -176,9 +176,9 @@ pub struct SignData {
pub signed: Signed,
}
impl ReadWrite for SignData {
impl<const N: usize> ReadWrite for SignData<N> {
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
let mut plan = [0; 32];
let mut plan = [0; N];
reader.read_exact(&mut plan)?;
let mut attempt = [0; 4];
@@ -249,16 +249,16 @@ pub enum Transaction {
// which would be binding over the block hash and automatically achieve synchrony on all
// relevant batches. ExternalBlock was removed for this due to complexity around the pipeline
// with the current processor, yet it would still be an improvement.
Batch([u8; 32], [u8; 32]),
Batch([u8; 32], [u8; 5]),
// When a Serai block is finalized, with the contained batches, we can allow the associated plan
// IDs
SubstrateBlock(u64),
BatchPreprocess(SignData),
BatchShare(SignData),
BatchPreprocess(SignData<5>),
BatchShare(SignData<5>),
SignPreprocess(SignData),
SignShare(SignData),
SignPreprocess(SignData<32>),
SignShare(SignData<32>),
// This is defined as an Unsigned transaction in order to de-duplicate SignCompleted amongst
// reporters (who should all report the same thing)
// We do still track the signer in order to prevent a single signer from publishing arbitrarily
@@ -367,7 +367,7 @@ impl ReadWrite for Transaction {
3 => {
let mut block = [0; 32];
reader.read_exact(&mut block)?;
let mut batch = [0; 32];
let mut batch = [0; 5];
reader.read_exact(&mut batch)?;
Ok(Transaction::Batch(block, batch))
}

View File

@@ -27,31 +27,25 @@ impl<D: Db> NonceDecider<D> {
next
}
fn item_nonce_key(genesis: [u8; 32], code: u8, id: [u8; 32]) -> Vec<u8> {
fn item_nonce_key(genesis: [u8; 32], code: u8, id: &[u8]) -> Vec<u8> {
D::key(
b"coordinator_tributary_nonce",
b"item",
[genesis.as_slice(), [code].as_ref(), id.as_ref()].concat(),
[genesis.as_slice(), [code].as_ref(), id].concat(),
)
}
fn set_nonce(
txn: &mut D::Transaction<'_>,
genesis: [u8; 32],
code: u8,
id: [u8; 32],
nonce: u32,
) {
fn set_nonce(txn: &mut D::Transaction<'_>, genesis: [u8; 32], code: u8, id: &[u8], nonce: u32) {
txn.put(Self::item_nonce_key(genesis, code, id), nonce.to_le_bytes())
}
fn db_nonce<G: Get>(getter: &G, genesis: [u8; 32], code: u8, id: [u8; 32]) -> Option<u32> {
fn db_nonce<G: Get>(getter: &G, genesis: [u8; 32], code: u8, id: &[u8]) -> Option<u32> {
getter
.get(Self::item_nonce_key(genesis, code, id))
.map(|bytes| u32::from_le_bytes(bytes.try_into().unwrap()))
}
pub fn handle_batch(txn: &mut D::Transaction<'_>, genesis: [u8; 32], batch: [u8; 32]) -> u32 {
pub fn handle_batch(txn: &mut D::Transaction<'_>, genesis: [u8; 32], batch: [u8; 5]) -> u32 {
let nonce_for = Self::allocate_nonce(txn, genesis);
Self::set_nonce(txn, genesis, BATCH_CODE, batch, nonce_for);
Self::set_nonce(txn, genesis, BATCH_CODE, &batch, nonce_for);
nonce_for
}
// TODO: The processor won't yield shares for this if the signing protocol aborts. We need to
@@ -60,10 +54,10 @@ impl<D: Db> NonceDecider<D> {
pub fn selected_for_signing_batch(
txn: &mut D::Transaction<'_>,
genesis: [u8; 32],
batch: [u8; 32],
batch: [u8; 5],
) {
let nonce_for = Self::allocate_nonce(txn, genesis);
Self::set_nonce(txn, genesis, BATCH_SIGNING_CODE, batch, nonce_for);
Self::set_nonce(txn, genesis, BATCH_SIGNING_CODE, &batch, nonce_for);
}
pub fn handle_substrate_block(
@@ -74,7 +68,7 @@ impl<D: Db> NonceDecider<D> {
let mut res = Vec::with_capacity(plans.len());
for plan in plans {
let nonce_for = Self::allocate_nonce(txn, genesis);
Self::set_nonce(txn, genesis, PLAN_CODE, *plan, nonce_for);
Self::set_nonce(txn, genesis, PLAN_CODE, plan, nonce_for);
res.push(nonce_for);
}
res
@@ -86,7 +80,7 @@ impl<D: Db> NonceDecider<D> {
plan: [u8; 32],
) {
let nonce_for = Self::allocate_nonce(txn, genesis);
Self::set_nonce(txn, genesis, PLAN_SIGNING_CODE, plan, nonce_for);
Self::set_nonce(txn, genesis, PLAN_SIGNING_CODE, &plan, nonce_for);
}
pub fn nonce<G: Get>(getter: &G, genesis: [u8; 32], tx: &Transaction) -> Option<Option<u32>> {
@@ -109,20 +103,20 @@ impl<D: Db> NonceDecider<D> {
Transaction::BatchPreprocess(data) => {
assert_eq!(data.attempt, 0);
Some(Self::db_nonce(getter, genesis, BATCH_CODE, data.plan))
Some(Self::db_nonce(getter, genesis, BATCH_CODE, &data.plan))
}
Transaction::BatchShare(data) => {
assert_eq!(data.attempt, 0);
Some(Self::db_nonce(getter, genesis, BATCH_SIGNING_CODE, data.plan))
Some(Self::db_nonce(getter, genesis, BATCH_SIGNING_CODE, &data.plan))
}
Transaction::SignPreprocess(data) => {
assert_eq!(data.attempt, 0);
Some(Self::db_nonce(getter, genesis, PLAN_CODE, data.plan))
Some(Self::db_nonce(getter, genesis, PLAN_CODE, &data.plan))
}
Transaction::SignShare(data) => {
assert_eq!(data.attempt, 0);
Some(Self::db_nonce(getter, genesis, PLAN_SIGNING_CODE, data.plan))
Some(Self::db_nonce(getter, genesis, PLAN_SIGNING_CODE, &data.plan))
}
Transaction::SignCompleted { .. } => None,

View File

@@ -35,10 +35,10 @@ pub enum RecognizedIdType {
}
pub(crate) trait RIDTrait<FRid>:
Clone + Fn(ValidatorSet, [u8; 32], RecognizedIdType, [u8; 32], u32) -> FRid
Clone + Fn(ValidatorSet, [u8; 32], RecognizedIdType, Vec<u8>, u32) -> FRid
{
}
impl<FRid, F: Clone + Fn(ValidatorSet, [u8; 32], RecognizedIdType, [u8; 32], u32) -> FRid>
impl<FRid, F: Clone + Fn(ValidatorSet, [u8; 32], RecognizedIdType, Vec<u8>, u32) -> FRid>
RIDTrait<FRid> for F
{
}