mirror of
https://github.com/serai-dex/serai.git
synced 2025-04-22 14:08:17 +00:00
Convert coordinator/tributary/nonce_decider to use create_db macro (#423)
* chore: convert nonce_deicer to use create_db macro * Restore pub NonceDecider * Remove extraneous comma I forgot to run git commit --amend on the prior commit :/ --------- Co-authored-by: Luke Parker <lukeparker5132@gmail.com>
This commit is contained in:
parent
995734c960
commit
c328e5ea68
5 changed files with 50 additions and 71 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -7578,6 +7578,7 @@ dependencies = [
|
|||
"serai-env",
|
||||
"serai-message-queue",
|
||||
"serai-processor-messages",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sp-application-crypto",
|
||||
"sp-runtime",
|
||||
|
|
|
@ -41,6 +41,7 @@ serai-client = { path = "../substrate/client", default-features = false, feature
|
|||
|
||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||
bincode = { version = "1", default-features = false }
|
||||
serde = "1"
|
||||
serde_json = { version = "1", default-features = false, features = ["std"] }
|
||||
|
||||
log = { version = "0.4", default-features = false, features = ["std"] }
|
||||
|
|
|
@ -740,7 +740,7 @@ async fn handle_processor_message<D: Db, P: P2p>(
|
|||
|
||||
let nonce = loop {
|
||||
let Some(nonce) =
|
||||
NonceDecider::<D>::nonce(&txn, genesis, &tx).expect("signed TX didn't have nonce")
|
||||
NonceDecider::nonce(&txn, genesis, &tx).expect("signed TX didn't have nonce")
|
||||
else {
|
||||
// This can be None if the following events occur, in order:
|
||||
// 1) We scanned the relevant transaction(s) in a Tributary block
|
||||
|
|
|
@ -501,7 +501,7 @@ pub(crate) async fn handle_application_tx<
|
|||
Transaction::Batch(_, batch) => {
|
||||
// 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);
|
||||
let nonce = NonceDecider::handle_batch(txn, genesis, batch);
|
||||
recognized_id(spec.set(), genesis, RecognizedIdType::Batch, batch.to_vec(), nonce).await;
|
||||
}
|
||||
|
||||
|
@ -511,7 +511,7 @@ pub(crate) async fn handle_application_tx<
|
|||
despite us not providing that transaction",
|
||||
);
|
||||
|
||||
let nonces = NonceDecider::<D>::handle_substrate_block(txn, genesis, &plan_ids);
|
||||
let nonces = NonceDecider::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.to_vec(), nonce).await;
|
||||
|
@ -534,7 +534,7 @@ 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);
|
||||
NonceDecider::selected_for_signing_batch(txn, genesis, data.plan);
|
||||
let key = TributaryDb::<D>::key_pair(txn, spec.set()).unwrap().0 .0;
|
||||
processors
|
||||
.send(
|
||||
|
@ -602,7 +602,7 @@ pub(crate) async fn handle_application_tx<
|
|||
) {
|
||||
Accumulation::Ready(DataSet::Participating(mut preprocesses)) => {
|
||||
unflatten(spec, &mut preprocesses);
|
||||
NonceDecider::<D>::selected_for_signing_plan(txn, genesis, data.plan);
|
||||
NonceDecider::selected_for_signing_plan(txn, genesis, data.plan);
|
||||
processors
|
||||
.send(
|
||||
spec.set().network,
|
||||
|
|
|
@ -1,89 +1,70 @@
|
|||
use core::marker::PhantomData;
|
||||
|
||||
use serai_db::{Get, DbTxn, Db};
|
||||
use serai_db::{Get, DbTxn, create_db};
|
||||
|
||||
use crate::tributary::Transaction;
|
||||
|
||||
/// Decides the nonce which should be used for a transaction on a Tributary.
|
||||
///
|
||||
/// Deterministically builds a list of nonces to use based on the on-chain events and expected
|
||||
/// transactions in response. Enables rebooting/rebuilding validators with full safety.
|
||||
pub struct NonceDecider<D: Db>(PhantomData<D>);
|
||||
use scale::Encode;
|
||||
|
||||
const BATCH_CODE: u8 = 0;
|
||||
const BATCH_SIGNING_CODE: u8 = 1;
|
||||
const PLAN_CODE: u8 = 2;
|
||||
const PLAN_SIGNING_CODE: u8 = 3;
|
||||
|
||||
impl<D: Db> NonceDecider<D> {
|
||||
fn next_nonce_key(genesis: [u8; 32]) -> Vec<u8> {
|
||||
D::key(b"coordinator_tributary_nonce", b"next", genesis)
|
||||
create_db!(
|
||||
NonceDeciderDb {
|
||||
NextNonceDb: (genesis: [u8; 32]) -> u32,
|
||||
ItemNonceDb: (genesis: [u8; 32], code: u8, id: &[u8]) -> u32
|
||||
}
|
||||
fn allocate_nonce(txn: &mut D::Transaction<'_>, genesis: [u8; 32]) -> u32 {
|
||||
let key = Self::next_nonce_key(genesis);
|
||||
let next =
|
||||
txn.get(&key).map(|bytes| u32::from_le_bytes(bytes.try_into().unwrap())).unwrap_or(3);
|
||||
txn.put(key, (next + 1).to_le_bytes());
|
||||
);
|
||||
|
||||
impl NextNonceDb {
|
||||
pub fn allocate_nonce(txn: &mut impl DbTxn, genesis: [u8; 32]) -> u32 {
|
||||
let next = Self::get(txn, genesis).unwrap_or(3);
|
||||
Self::set(txn, genesis, &(next + 1));
|
||||
next
|
||||
}
|
||||
}
|
||||
|
||||
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].concat(),
|
||||
)
|
||||
}
|
||||
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]) -> 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; 5]) -> u32 {
|
||||
let nonce_for = Self::allocate_nonce(txn, genesis);
|
||||
Self::set_nonce(txn, genesis, BATCH_CODE, &batch, nonce_for);
|
||||
/// Decides the nonce which should be used for a transaction on a Tributary.
|
||||
///
|
||||
/// Deterministically builds a list of nonces to use based on the on-chain events and expected
|
||||
/// transactions in response. Enables rebooting/rebuilding validators with full safety.
|
||||
pub struct NonceDecider;
|
||||
impl NonceDecider {
|
||||
pub fn handle_batch(txn: &mut impl DbTxn, genesis: [u8; 32], batch: [u8; 5]) -> u32 {
|
||||
let nonce_for = NextNonceDb::allocate_nonce(txn, genesis);
|
||||
ItemNonceDb::set(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
|
||||
// detect when we're expecting shares for an aborted protocol and insert a dummy transaction
|
||||
// there.
|
||||
pub fn selected_for_signing_batch(
|
||||
txn: &mut D::Transaction<'_>,
|
||||
genesis: [u8; 32],
|
||||
batch: [u8; 5],
|
||||
) {
|
||||
let nonce_for = Self::allocate_nonce(txn, genesis);
|
||||
Self::set_nonce(txn, genesis, BATCH_SIGNING_CODE, &batch, nonce_for);
|
||||
}
|
||||
|
||||
pub fn handle_substrate_block(
|
||||
txn: &mut D::Transaction<'_>,
|
||||
txn: &mut impl DbTxn,
|
||||
genesis: [u8; 32],
|
||||
plans: &[[u8; 32]],
|
||||
) -> Vec<u32> {
|
||||
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);
|
||||
let nonce_for = NextNonceDb::allocate_nonce(txn, genesis);
|
||||
ItemNonceDb::set(txn, genesis, PLAN_CODE, plan, &nonce_for);
|
||||
res.push(nonce_for);
|
||||
}
|
||||
res
|
||||
}
|
||||
// TODO: Same TODO as selected_for_signing_batch
|
||||
pub fn selected_for_signing_plan(
|
||||
txn: &mut D::Transaction<'_>,
|
||||
genesis: [u8; 32],
|
||||
plan: [u8; 32],
|
||||
) {
|
||||
let nonce_for = Self::allocate_nonce(txn, genesis);
|
||||
Self::set_nonce(txn, genesis, PLAN_SIGNING_CODE, &plan, nonce_for);
|
||||
|
||||
// TODO: The processor won't yield shares for this if the signing protocol aborts. We need to
|
||||
// detect when we're expecting shares for an aborted protocol and insert a dummy transaction
|
||||
// there.
|
||||
pub fn selected_for_signing_batch(txn: &mut impl DbTxn, genesis: [u8; 32], batch: [u8; 5]) {
|
||||
let nonce_for = NextNonceDb::allocate_nonce(txn, genesis);
|
||||
ItemNonceDb::set(txn, genesis, BATCH_SIGNING_CODE, &batch, &nonce_for);
|
||||
}
|
||||
|
||||
pub fn nonce<G: Get>(getter: &G, genesis: [u8; 32], tx: &Transaction) -> Option<Option<u32>> {
|
||||
// TODO: Same TODO as selected_for_signing_batch
|
||||
pub fn selected_for_signing_plan(txn: &mut impl DbTxn, genesis: [u8; 32], plan: [u8; 32]) {
|
||||
let nonce_for = NextNonceDb::allocate_nonce(txn, genesis);
|
||||
ItemNonceDb::set(txn, genesis, PLAN_SIGNING_CODE, &plan, &nonce_for);
|
||||
}
|
||||
|
||||
pub fn nonce(getter: &impl Get, genesis: [u8; 32], tx: &Transaction) -> Option<Option<u32>> {
|
||||
match tx {
|
||||
Transaction::RemoveParticipant(_) => None,
|
||||
|
||||
|
@ -105,28 +86,24 @@ impl<D: Db> NonceDecider<D> {
|
|||
assert_eq!(*attempt, 0);
|
||||
Some(Some(2))
|
||||
}
|
||||
|
||||
Transaction::Batch(_, _) => None,
|
||||
Transaction::SubstrateBlock(_) => None,
|
||||
|
||||
Transaction::BatchPreprocess(data) => {
|
||||
assert_eq!(data.attempt, 0);
|
||||
Some(Self::db_nonce(getter, genesis, BATCH_CODE, &data.plan))
|
||||
Some(ItemNonceDb::get(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(ItemNonceDb::get(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(ItemNonceDb::get(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(ItemNonceDb::get(getter, genesis, PLAN_SIGNING_CODE, &data.plan))
|
||||
}
|
||||
|
||||
Transaction::SignCompleted { .. } => None,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue