mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +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:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -7578,6 +7578,7 @@ dependencies = [
|
|||||||
"serai-env",
|
"serai-env",
|
||||||
"serai-message-queue",
|
"serai-message-queue",
|
||||||
"serai-processor-messages",
|
"serai-processor-messages",
|
||||||
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sp-application-crypto",
|
"sp-application-crypto",
|
||||||
"sp-runtime",
|
"sp-runtime",
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ serai-client = { path = "../substrate/client", default-features = false, feature
|
|||||||
|
|
||||||
hex = { version = "0.4", default-features = false, features = ["std"] }
|
hex = { version = "0.4", default-features = false, features = ["std"] }
|
||||||
bincode = { version = "1", default-features = false }
|
bincode = { version = "1", default-features = false }
|
||||||
|
serde = "1"
|
||||||
serde_json = { version = "1", default-features = false, features = ["std"] }
|
serde_json = { version = "1", default-features = false, features = ["std"] }
|
||||||
|
|
||||||
log = { version = "0.4", 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 nonce = loop {
|
||||||
let Some(nonce) =
|
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 {
|
else {
|
||||||
// This can be None if the following events occur, in order:
|
// This can be None if the following events occur, in order:
|
||||||
// 1) We scanned the relevant transaction(s) in a Tributary block
|
// 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) => {
|
Transaction::Batch(_, batch) => {
|
||||||
// Because this Batch has achieved synchrony, its batch ID should be authorized
|
// Because this Batch has achieved synchrony, its batch ID should be authorized
|
||||||
TributaryDb::<D>::recognize_topic(txn, genesis, Topic::Batch(batch));
|
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;
|
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",
|
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()) {
|
for (nonce, id) in nonces.into_iter().zip(plan_ids.into_iter()) {
|
||||||
TributaryDb::<D>::recognize_topic(txn, genesis, Topic::Sign(id));
|
TributaryDb::<D>::recognize_topic(txn, genesis, Topic::Sign(id));
|
||||||
recognized_id(spec.set(), genesis, RecognizedIdType::Plan, id.to_vec(), nonce).await;
|
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)) => {
|
Accumulation::Ready(DataSet::Participating(mut preprocesses)) => {
|
||||||
unflatten(spec, &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;
|
let key = TributaryDb::<D>::key_pair(txn, spec.set()).unwrap().0 .0;
|
||||||
processors
|
processors
|
||||||
.send(
|
.send(
|
||||||
@@ -602,7 +602,7 @@ pub(crate) async fn handle_application_tx<
|
|||||||
) {
|
) {
|
||||||
Accumulation::Ready(DataSet::Participating(mut preprocesses)) => {
|
Accumulation::Ready(DataSet::Participating(mut preprocesses)) => {
|
||||||
unflatten(spec, &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
|
processors
|
||||||
.send(
|
.send(
|
||||||
spec.set().network,
|
spec.set().network,
|
||||||
|
|||||||
@@ -1,89 +1,70 @@
|
|||||||
use core::marker::PhantomData;
|
use serai_db::{Get, DbTxn, create_db};
|
||||||
|
|
||||||
use serai_db::{Get, DbTxn, Db};
|
|
||||||
|
|
||||||
use crate::tributary::Transaction;
|
use crate::tributary::Transaction;
|
||||||
|
|
||||||
/// Decides the nonce which should be used for a transaction on a Tributary.
|
use scale::Encode;
|
||||||
///
|
|
||||||
/// 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>);
|
|
||||||
|
|
||||||
const BATCH_CODE: u8 = 0;
|
const BATCH_CODE: u8 = 0;
|
||||||
const BATCH_SIGNING_CODE: u8 = 1;
|
const BATCH_SIGNING_CODE: u8 = 1;
|
||||||
const PLAN_CODE: u8 = 2;
|
const PLAN_CODE: u8 = 2;
|
||||||
const PLAN_SIGNING_CODE: u8 = 3;
|
const PLAN_SIGNING_CODE: u8 = 3;
|
||||||
|
|
||||||
impl<D: Db> NonceDecider<D> {
|
create_db!(
|
||||||
fn next_nonce_key(genesis: [u8; 32]) -> Vec<u8> {
|
NonceDeciderDb {
|
||||||
D::key(b"coordinator_tributary_nonce", b"next", genesis)
|
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 =
|
impl NextNonceDb {
|
||||||
txn.get(&key).map(|bytes| u32::from_le_bytes(bytes.try_into().unwrap())).unwrap_or(3);
|
pub fn allocate_nonce(txn: &mut impl DbTxn, genesis: [u8; 32]) -> u32 {
|
||||||
txn.put(key, (next + 1).to_le_bytes());
|
let next = Self::get(txn, genesis).unwrap_or(3);
|
||||||
|
Self::set(txn, genesis, &(next + 1));
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn item_nonce_key(genesis: [u8; 32], code: u8, id: &[u8]) -> Vec<u8> {
|
/// Decides the nonce which should be used for a transaction on a Tributary.
|
||||||
D::key(
|
///
|
||||||
b"coordinator_tributary_nonce",
|
/// Deterministically builds a list of nonces to use based on the on-chain events and expected
|
||||||
b"item",
|
/// transactions in response. Enables rebooting/rebuilding validators with full safety.
|
||||||
[genesis.as_slice(), [code].as_ref(), id].concat(),
|
pub struct NonceDecider;
|
||||||
)
|
impl NonceDecider {
|
||||||
}
|
pub fn handle_batch(txn: &mut impl DbTxn, genesis: [u8; 32], batch: [u8; 5]) -> u32 {
|
||||||
fn set_nonce(txn: &mut D::Transaction<'_>, genesis: [u8; 32], code: u8, id: &[u8], nonce: u32) {
|
let nonce_for = NextNonceDb::allocate_nonce(txn, genesis);
|
||||||
txn.put(Self::item_nonce_key(genesis, code, id), nonce.to_le_bytes())
|
ItemNonceDb::set(txn, genesis, BATCH_CODE, &batch, &nonce_for);
|
||||||
}
|
|
||||||
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);
|
|
||||||
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(
|
pub fn handle_substrate_block(
|
||||||
txn: &mut D::Transaction<'_>,
|
txn: &mut impl DbTxn,
|
||||||
genesis: [u8; 32],
|
genesis: [u8; 32],
|
||||||
plans: &[[u8; 32]],
|
plans: &[[u8; 32]],
|
||||||
) -> Vec<u32> {
|
) -> Vec<u32> {
|
||||||
let mut res = Vec::with_capacity(plans.len());
|
let mut res = Vec::with_capacity(plans.len());
|
||||||
for plan in plans {
|
for plan in plans {
|
||||||
let nonce_for = Self::allocate_nonce(txn, genesis);
|
let nonce_for = NextNonceDb::allocate_nonce(txn, genesis);
|
||||||
Self::set_nonce(txn, genesis, PLAN_CODE, plan, nonce_for);
|
ItemNonceDb::set(txn, genesis, PLAN_CODE, plan, &nonce_for);
|
||||||
res.push(nonce_for);
|
res.push(nonce_for);
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
// TODO: Same TODO as selected_for_signing_batch
|
|
||||||
pub fn selected_for_signing_plan(
|
// TODO: The processor won't yield shares for this if the signing protocol aborts. We need to
|
||||||
txn: &mut D::Transaction<'_>,
|
// detect when we're expecting shares for an aborted protocol and insert a dummy transaction
|
||||||
genesis: [u8; 32],
|
// there.
|
||||||
plan: [u8; 32],
|
pub fn selected_for_signing_batch(txn: &mut impl DbTxn, genesis: [u8; 32], batch: [u8; 5]) {
|
||||||
) {
|
let nonce_for = NextNonceDb::allocate_nonce(txn, genesis);
|
||||||
let nonce_for = Self::allocate_nonce(txn, genesis);
|
ItemNonceDb::set(txn, genesis, BATCH_SIGNING_CODE, &batch, &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>> {
|
// 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 {
|
match tx {
|
||||||
Transaction::RemoveParticipant(_) => None,
|
Transaction::RemoveParticipant(_) => None,
|
||||||
|
|
||||||
@@ -105,28 +86,24 @@ impl<D: Db> NonceDecider<D> {
|
|||||||
assert_eq!(*attempt, 0);
|
assert_eq!(*attempt, 0);
|
||||||
Some(Some(2))
|
Some(Some(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
Transaction::Batch(_, _) => None,
|
Transaction::Batch(_, _) => None,
|
||||||
Transaction::SubstrateBlock(_) => None,
|
Transaction::SubstrateBlock(_) => None,
|
||||||
|
|
||||||
Transaction::BatchPreprocess(data) => {
|
Transaction::BatchPreprocess(data) => {
|
||||||
assert_eq!(data.attempt, 0);
|
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) => {
|
Transaction::BatchShare(data) => {
|
||||||
assert_eq!(data.attempt, 0);
|
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) => {
|
Transaction::SignPreprocess(data) => {
|
||||||
assert_eq!(data.attempt, 0);
|
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) => {
|
Transaction::SignShare(data) => {
|
||||||
assert_eq!(data.attempt, 0);
|
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,
|
Transaction::SignCompleted { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user