Convert tributary to use create_db macro (#448)

* chore: convert tributary to use create_db macro

* chore: fix fmt

* chore: break long line
This commit is contained in:
David Bell 2023-11-22 13:17:51 +04:00 committed by GitHub
parent 9ab2a2cfe0
commit 9df8c9476e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 142 additions and 294 deletions

View file

@ -38,7 +38,7 @@ use ::tributary::{
mod tributary;
use crate::tributary::{
TributarySpec, SignData, Transaction, TributaryDb, NonceDecider, scanner::RecognizedIdType,
TributarySpec, SignData, Transaction, NonceDecider, scanner::RecognizedIdType, PlanIds,
};
mod db;
@ -256,7 +256,7 @@ async fn handle_processor_message<D: Db, P: P2p>(
.iter()
.filter_map(|plan| Some(plan.id).filter(|_| plan.key == key))
.collect::<Vec<_>>();
TributaryDb::<D>::set_plan_ids(&mut txn, tributary.spec.genesis(), *block, &plans);
PlanIds::set(&mut txn, &tributary.spec.genesis(), *block, &plans);
let tx = Transaction::SubstrateBlock(*block);
log::trace!(
@ -472,7 +472,7 @@ async fn handle_processor_message<D: Db, P: P2p>(
// As for the safety of calling error_generating_key_pair, the processor is presumed
// to only send InvalidShare or GeneratedKeyPair for a given attempt
let mut txs = if let Some(faulty) =
crate::tributary::error_generating_key_pair::<D, _>(&txn, key, spec, id.attempt)
crate::tributary::error_generating_key_pair::<_>(&txn, key, spec, id.attempt)
{
vec![Transaction::RemoveParticipant(faulty)]
} else {

View file

@ -30,7 +30,7 @@ use tokio::{sync::mpsc, time::sleep};
use crate::{
Db,
processors::Processors,
tributary::{TributarySpec, SeraiBlockNumber, TributaryDb},
tributary::{TributarySpec, SeraiBlockNumber, KeyPairDb},
};
mod db;
@ -305,7 +305,7 @@ async fn handle_block<D: Db, Pro: Processors>(
// Immediately ensure this key pair is accessible to the tributary, before we fire any
// events off of it
let mut txn = db.0.txn();
TributaryDb::<D>::set_key_pair(&mut txn, set, &key_pair);
KeyPairDb::set(&mut txn, set, &key_pair);
txn.commit();
handle_key_gen(&mut db.0, processors, serai, &block, set, key_pair).await?;

View file

@ -13,7 +13,7 @@ use sp_runtime::traits::Verify;
use tokio::time::sleep;
use serai_db::{DbTxn, Db, MemDb};
use serai_db::{Db, MemDb, DbTxn};
use processor_messages::{
key_gen::{self, KeyGenId},
@ -23,7 +23,7 @@ use processor_messages::{
use tributary::{TransactionTrait, Tributary};
use crate::{
tributary::{TributaryDb, Transaction, TributarySpec, scanner::handle_new_blocks},
tributary::{Transaction, TributarySpec, scanner::handle_new_blocks},
tests::{
MemProcessors, LocalP2p,
tributary::{new_keys, new_spec, new_tributaries, run_tributaries, wait_for_tx_inclusion},
@ -81,8 +81,8 @@ async fn dkg_test() {
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
spec: &TributarySpec,
tributary: &Tributary<MemDb, Transaction, LocalP2p>,
) -> (TributaryDb<MemDb>, MemProcessors) {
let mut scanner_db = TributaryDb(MemDb::new());
) -> (MemDb, MemProcessors) {
let mut scanner_db = MemDb::new();
let processors = MemProcessors::new();
handle_new_blocks::<_, _, _, _, _, _, LocalP2p>(
&mut scanner_db,
@ -289,7 +289,7 @@ async fn dkg_test() {
if i != 0 {
scanner_db = &mut local_scanner_db;
}
let mut txn = scanner_db.0.txn();
let mut txn = scanner_db.txn();
let share =
crate::tributary::generated_key_pair::<MemDb>(&mut txn, key, &spec, &key_pair, 0).unwrap();
txn.commit();

View file

@ -1,26 +1,20 @@
use core::{marker::PhantomData, ops::Deref};
use std::{io::Read, collections::HashMap};
use scale::{Encode, Decode};
use core::ops::Deref;
use std::collections::HashMap;
use zeroize::Zeroizing;
use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto};
use ciphersuite::{Ciphersuite, Ristretto, group::GroupEncoding};
use frost::Participant;
use serai_client::validator_sets::primitives::{ValidatorSet, KeyPair};
use processor_messages::coordinator::SubstrateSignableId;
use scale::Encode;
pub use serai_db::*;
use crate::tributary::TributarySpec;
create_db! {
NewTributaryDb {
SeraiBlockNumber: (hash: [u8; 32]) -> u64,
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Topic {
Dkg,
@ -58,7 +52,7 @@ pub struct DataSpecification {
}
impl DataSpecification {
fn as_key(&self, genesis: [u8; 32]) -> Vec<u8> {
pub fn as_key(&self, genesis: [u8; 32]) -> Vec<u8> {
let mut res = self.topic.as_key(genesis);
let label_bytes = self.label.bytes();
res.push(u8::try_from(label_bytes.len()).unwrap());
@ -68,226 +62,6 @@ impl DataSpecification {
}
}
#[derive(Debug)]
pub struct TributaryDb<D: Db>(pub D);
impl<D: Db> TributaryDb<D> {
pub fn new(db: D) -> Self {
Self(db)
}
fn tributary_key(dst: &'static [u8], key: impl AsRef<[u8]>) -> Vec<u8> {
D::key(b"coordinator_tributary", dst, key)
}
// Last block scanned
fn last_block_key(genesis: [u8; 32]) -> Vec<u8> {
Self::tributary_key(b"block", genesis)
}
pub fn set_last_block(&mut self, genesis: [u8; 32], block: [u8; 32]) {
let mut txn = self.0.txn();
txn.put(Self::last_block_key(genesis), block);
txn.commit();
}
pub fn last_block(&self, genesis: [u8; 32]) -> [u8; 32] {
self
.0
.get(Self::last_block_key(genesis))
.map(|last| last.try_into().unwrap())
.unwrap_or(genesis)
}
// If a validator has been fatally slashed
fn fatal_slashes_key(genesis: [u8; 32]) -> Vec<u8> {
Self::tributary_key(b"fatal_slashes", genesis)
}
fn fatally_slashed_key(genesis: [u8; 32], account: [u8; 32]) -> Vec<u8> {
Self::tributary_key(b"fatally_slashed", (genesis, account).encode())
}
pub fn is_fatally_slashed<G: Get>(getter: &G, genesis: [u8; 32], account: [u8; 32]) -> bool {
getter.get(Self::fatally_slashed_key(genesis, account)).is_some()
}
pub fn set_fatally_slashed(txn: &mut D::Transaction<'_>, genesis: [u8; 32], account: [u8; 32]) {
txn.put(Self::fatally_slashed_key(genesis, account), []);
let key = Self::fatal_slashes_key(genesis);
let mut existing = txn.get(&key).unwrap_or(vec![]);
// Don't append if we already have it
if existing.chunks(32).any(|existing| existing == account) {
return;
}
existing.extend(account);
txn.put(key, existing);
}
fn share_for_blame_key(genesis: &[u8], from: Participant, to: Participant) -> Vec<u8> {
Self::tributary_key(b"share_for_blame", (genesis, u16::from(from), u16::from(to)).encode())
}
pub fn save_share_for_blame(
txn: &mut D::Transaction<'_>,
genesis: &[u8],
from: Participant,
to: Participant,
share: &[u8],
) {
txn.put(Self::share_for_blame_key(genesis, from, to), share);
}
pub fn share_for_blame<G: Get>(
getter: &G,
genesis: &[u8],
from: Participant,
to: Participant,
) -> Option<Vec<u8>> {
getter.get(Self::share_for_blame_key(genesis, from, to))
}
// The plan IDs associated with a Substrate block
fn plan_ids_key(genesis: &[u8], block: u64) -> Vec<u8> {
Self::tributary_key(b"plan_ids", [genesis, block.to_le_bytes().as_ref()].concat())
}
pub fn set_plan_ids(
txn: &mut D::Transaction<'_>,
genesis: [u8; 32],
block: u64,
plans: &[[u8; 32]],
) {
txn.put(Self::plan_ids_key(&genesis, block), plans.concat());
}
pub fn plan_ids<G: Get>(getter: &G, genesis: [u8; 32], block: u64) -> Option<Vec<[u8; 32]>> {
getter.get(Self::plan_ids_key(&genesis, block)).map(|bytes| {
let mut res = vec![];
let mut bytes_ref: &[u8] = bytes.as_ref();
while !bytes_ref.is_empty() {
let mut id = [0; 32];
bytes_ref.read_exact(&mut id).unwrap();
res.push(id);
}
res
})
}
fn confirmation_nonces_key(genesis: [u8; 32], attempt: u32) -> Vec<u8> {
Self::tributary_key(b"confirmation_nonces", (genesis, attempt).encode())
}
pub fn save_confirmation_nonces(
txn: &mut D::Transaction<'_>,
genesis: [u8; 32],
attempt: u32,
nonces: HashMap<Participant, Vec<u8>>,
) {
let nonces =
nonces.into_iter().map(|(key, value)| (u16::from(key), value)).collect::<HashMap<_, _>>();
txn.put(Self::confirmation_nonces_key(genesis, attempt), bincode::serialize(&nonces).unwrap())
}
pub fn confirmation_nonces<G: Get>(
getter: &G,
genesis: [u8; 32],
attempt: u32,
) -> Option<HashMap<Participant, Vec<u8>>> {
let bytes = getter.get(Self::confirmation_nonces_key(genesis, attempt))?;
let map: HashMap<u16, Vec<u8>> = bincode::deserialize(&bytes).unwrap();
Some(map.into_iter().map(|(key, value)| (Participant::new(key).unwrap(), value)).collect())
}
// The key pair which we're actively working on completing
fn currently_completing_key_pair_key(genesis: [u8; 32]) -> Vec<u8> {
Self::tributary_key(b"currently_completing_key_pair", genesis)
}
pub fn save_currently_completing_key_pair(
txn: &mut D::Transaction<'_>,
genesis: [u8; 32],
key_pair: &KeyPair,
) {
txn.put(Self::currently_completing_key_pair_key(genesis), key_pair.encode())
}
pub fn currently_completing_key_pair<G: Get>(getter: &G, genesis: [u8; 32]) -> Option<KeyPair> {
getter
.get(Self::currently_completing_key_pair_key(genesis))
.map(|bytes| KeyPair::decode(&mut bytes.as_slice()).unwrap())
}
// The key pair confirmed for this Tributary
pub fn key_pair_key(set: ValidatorSet) -> Vec<u8> {
Self::tributary_key(b"key_pair", set.encode())
}
pub fn set_key_pair(txn: &mut D::Transaction<'_>, set: ValidatorSet, key_pair: &KeyPair) {
txn.put(Self::key_pair_key(set), key_pair.encode());
}
pub fn key_pair<G: Get>(getter: &G, set: ValidatorSet) -> Option<KeyPair> {
Some(KeyPair::decode(&mut getter.get(Self::key_pair_key(set))?.as_slice()).unwrap())
}
// The current attempt to resolve a topic
fn attempt_key(genesis: [u8; 32], topic: Topic) -> Vec<u8> {
Self::tributary_key(b"attempt", topic.as_key(genesis))
}
pub fn recognize_topic(txn: &mut D::Transaction<'_>, genesis: [u8; 32], topic: Topic) {
txn.put(Self::attempt_key(genesis, topic), 0u32.to_le_bytes())
}
pub fn attempt<G: Get>(getter: &G, genesis: [u8; 32], topic: Topic) -> Option<u32> {
let attempt_bytes = getter.get(Self::attempt_key(genesis, topic));
// DKGs start when the chain starts
if attempt_bytes.is_none() && (topic == Topic::Dkg) {
return Some(0);
}
Some(u32::from_le_bytes(attempt_bytes?.try_into().unwrap()))
}
// Key for the amount of instances received thus far
fn data_received_key(genesis: [u8; 32], data_spec: &DataSpecification) -> Vec<u8> {
Self::tributary_key(b"data_received", data_spec.as_key(genesis))
}
// Key for an instance of data from a specific validator
fn data_key(
genesis: [u8; 32],
data_spec: &DataSpecification,
signer: <Ristretto as Ciphersuite>::G,
) -> Vec<u8> {
Self::tributary_key(
b"data",
[data_spec.as_key(genesis).as_slice(), signer.to_bytes().as_ref()].concat(),
)
}
pub fn data<G: Get>(
getter: &G,
genesis: [u8; 32],
data_spec: &DataSpecification,
signer: <Ristretto as Ciphersuite>::G,
) -> Option<Vec<u8>> {
getter.get(Self::data_key(genesis, data_spec, signer))
}
fn set_data(
txn: &mut D::Transaction<'_>,
genesis: [u8; 32],
data_spec: &DataSpecification,
signer: <Ristretto as Ciphersuite>::G,
signer_shares: u16,
data: &[u8],
) -> (u16, u16) {
let received_key = Self::data_received_key(genesis, data_spec);
let prior_received =
u16::from_le_bytes(txn.get(&received_key).unwrap_or(vec![0; 2]).try_into().unwrap());
let received = prior_received + signer_shares;
txn.put(received_key, received.to_le_bytes());
txn.put(Self::data_key(genesis, data_spec, signer), data);
(prior_received, received)
}
fn event_key(id: &[u8], index: u32) -> Vec<u8> {
Self::tributary_key(b"event", [id, index.to_le_bytes().as_ref()].concat())
}
pub fn handled_event<G: Get>(getter: &G, id: [u8; 32], index: u32) -> bool {
getter.get(Self::event_key(&id, index)).is_some()
}
pub fn handle_event(txn: &mut D::Transaction<'_>, id: [u8; 32], index: u32) {
assert!(!Self::handled_event(txn, id, index));
txn.put(Self::event_key(&id, index), []);
}
}
pub enum DataSet {
Participating(HashMap<Participant, Vec<u8>>),
NotParticipating,
@ -298,17 +72,81 @@ pub enum Accumulation {
NotReady,
}
pub struct TributaryState<D: Db>(PhantomData<D>);
impl<D: Db> TributaryState<D> {
create_db!(
NewTributary {
SeraiBlockNumber: (hash: [u8; 32]) -> u64,
LastBlock: (genesis: [u8; 32]) -> [u8; 32],
FatalSlashes: (genesis: [u8; 32]) -> Vec<u8>,
FatallySlashed: (genesis: [u8; 32], account: [u8; 32]) -> (),
ShareBlame: (genesis: [u8; 32], from: u16, to: u16) -> Vec<u8>,
PlanIds: (genesis: &[u8], block: u64) -> Vec<[u8; 32]>,
ConfirmationNonces: (genesis: [u8; 32], attempt: u32) -> HashMap<Participant, Vec<u8>>,
CurrentlyCompletingKeyPair: (genesis: [u8; 32]) -> KeyPair,
KeyPairDb: (set: ValidatorSet) -> KeyPair,
AttemptDb: (genesis: [u8; 32], topic_key: &Vec<u8>) -> u32,
DataReceived: (genesis: [u8; 32], data_spec_key: &Vec<u8>) -> u16,
DataDb: (genesis: [u8; 32], data_spec_key: &Vec<u8>, signer_bytes: &[u8; 32]) -> Vec<u8>,
EventDb: (id: [u8; 32], index: u32) -> (),
}
);
impl FatallySlashed {
pub fn set_fatally_slashed(txn: &mut impl DbTxn, genesis: [u8; 32], account: [u8; 32]) {
Self::set(txn, genesis, account, &());
let mut existing = FatalSlashes::get(txn, genesis).unwrap_or_default();
// Don't append if we already have it
if existing.chunks(32).any(|existing| existing == account) {
return;
}
existing.extend(account);
FatalSlashes::set(txn, genesis, &existing);
}
}
impl AttemptDb {
pub fn recognize_topic(txn: &mut impl DbTxn, genesis: [u8; 32], topic: Topic) {
Self::set(txn, genesis, &topic.as_key(genesis), &0u32);
}
pub fn attempt(getter: &impl Get, genesis: [u8; 32], topic: Topic) -> Option<u32> {
let attempt = Self::get(getter, genesis, &topic.as_key(genesis));
if attempt.is_none() && topic == Topic::Dkg {
return Some(0);
}
attempt
}
}
impl DataDb {
pub fn set_data(
txn: &mut impl DbTxn,
genesis: [u8; 32],
data_spec: &DataSpecification,
signer: <Ristretto as Ciphersuite>::G,
signer_shares: u16,
data: &Vec<u8>,
) -> (u16, u16) {
let data_spec = data_spec.as_key(genesis);
let prior_received = DataReceived::get(txn, genesis, &data_spec).unwrap_or_default();
let received = prior_received + signer_shares;
DataReceived::set(txn, genesis, &data_spec, &received);
DataDb::set(txn, genesis, &data_spec, &signer.to_bytes(), data);
(prior_received, received)
}
pub fn accumulate(
txn: &mut D::Transaction<'_>,
txn: &mut impl DbTxn,
our_key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
spec: &TributarySpec,
data_spec: &DataSpecification,
signer: <Ristretto as Ciphersuite>::G,
data: &[u8],
data: &Vec<u8>,
) -> Accumulation {
if TributaryDb::<D>::data(txn, spec.genesis(), data_spec, signer).is_some() {
let genesis = spec.genesis();
let data_spec_key = data_spec.as_key(genesis);
if Self::get(txn, genesis, &data_spec_key, &signer.to_bytes()).is_some() {
panic!("accumulating data for a participant multiple times");
}
let signer_shares = {
@ -317,7 +155,7 @@ impl<D: Db> TributaryState<D> {
u16::from(signer_i.end) - u16::from(signer_i.start)
};
let (prior_received, now_received) =
TributaryDb::<D>::set_data(txn, spec.genesis(), data_spec, signer, signer_shares, data);
Self::set_data(txn, spec.genesis(), data_spec, signer, signer_shares, data);
// If we have all the needed commitments/preprocesses/shares, tell the processor
let needed = if data_spec.topic == Topic::Dkg { spec.n() } else { spec.t() };
@ -327,13 +165,14 @@ impl<D: Db> TributaryState<D> {
for validator in spec.validators().iter().map(|validator| validator.0) {
data.insert(
spec.i(validator).unwrap().start,
if let Some(data) = TributaryDb::<D>::data(txn, spec.genesis(), data_spec, validator) {
if let Some(data) = Self::get(txn, genesis, &data_spec_key, &validator.to_bytes()) {
data
} else {
continue;
},
);
}
assert_eq!(data.len(), usize::from(needed));
// Remove our own piece of data, if we were involved
@ -355,3 +194,10 @@ impl<D: Db> TributaryState<D> {
Accumulation::NotReady
}
}
impl EventDb {
pub fn handle_event(txn: &mut impl DbTxn, id: [u8; 32], index: u32) {
assert!(Self::get(txn, id, index).is_none());
Self::set(txn, id, index, &());
}
}

View file

@ -27,14 +27,16 @@ use serai_db::{Get, Db};
use crate::{
processors::Processors,
tributary::{
Transaction, TributarySpec, SeraiBlockNumber, Topic, DataSpecification, TributaryDb, DataSet,
Accumulation, TributaryState,
Transaction, TributarySpec, SeraiBlockNumber, Topic, DataSpecification, DataSet, Accumulation,
nonce_decider::NonceDecider,
dkg_confirmer::DkgConfirmer,
scanner::{RecognizedIdType, RIDTrait},
FatallySlashed, ShareBlame, PlanIds, ConfirmationNonces, KeyPairDb, AttemptDb, DataDb,
},
};
use super::CurrentlyCompletingKeyPair;
const DKG_COMMITMENTS: &str = "commitments";
const DKG_SHARES: &str = "shares";
const DKG_CONFIRMATION_NONCES: &str = "confirmation_nonces";
@ -61,14 +63,13 @@ pub fn dkg_confirmation_nonces(
//
// The caller must ensure only error_generating_key_pair or generated_key_pair is called for a
// given attempt.
pub fn error_generating_key_pair<D: Db, G: Get>(
pub fn error_generating_key_pair<G: Get>(
getter: &G,
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
spec: &TributarySpec,
attempt: u32,
) -> Option<Participant> {
let preprocesses =
TributaryDb::<D>::confirmation_nonces(getter, spec.genesis(), attempt).unwrap();
let preprocesses = ConfirmationNonces::get(getter, spec.genesis(), attempt).unwrap();
// Sign a key pair which can't be valid
// (0xff used as 0 would be the Ristretto identity point, 0-length for the network key)
@ -90,8 +91,8 @@ pub fn generated_key_pair<D: Db>(
key_pair: &KeyPair,
attempt: u32,
) -> Result<[u8; 32], Participant> {
TributaryDb::<D>::save_currently_completing_key_pair(txn, spec.genesis(), key_pair);
let preprocesses = TributaryDb::<D>::confirmation_nonces(txn, spec.genesis(), attempt).unwrap();
CurrentlyCompletingKeyPair::set(txn, spec.genesis(), key_pair);
let preprocesses = ConfirmationNonces::get(txn, spec.genesis(), attempt).unwrap();
DkgConfirmer::share(spec, key, attempt, preprocesses, key_pair)
}
@ -102,7 +103,7 @@ pub(super) fn fatal_slash<D: Db>(
reason: &str,
) {
log::warn!("fatally slashing {}. reason: {}", hex::encode(account), reason);
TributaryDb::<D>::set_fatally_slashed(txn, genesis, account);
FatallySlashed::set_fatally_slashed(txn, genesis, account);
// TODO: disconnect the node from network/ban from further participation in all Tributaries
// TODO: If during DKG, trigger a re-attempt
@ -155,7 +156,7 @@ pub(crate) async fn handle_application_tx<
// TODO: Because fatally slashed participants can still publish onto the blockchain, they have
// a notable DoS ability
if let TransactionKind::Signed(signed) = tx.kind() {
if TributaryDb::<D>::is_fatally_slashed(txn, genesis, signed.signer.to_bytes()) {
if FatallySlashed::get(txn, genesis, signed.signer.to_bytes()).is_some() {
return;
}
}
@ -164,7 +165,7 @@ pub(crate) async fn handle_application_tx<
data_spec: &DataSpecification,
bytes: Vec<u8>,
signed: &Signed| {
let Some(curr_attempt) = TributaryDb::<D>::attempt(txn, genesis, data_spec.topic) else {
let Some(curr_attempt) = AttemptDb::attempt(txn, genesis, data_spec.topic) else {
// Premature publication of a valid ID/publication of an invalid ID
fatal_slash::<D>(
txn,
@ -176,7 +177,7 @@ pub(crate) async fn handle_application_tx<
};
// If they've already published a TX for this attempt, slash
if TributaryDb::<D>::data(txn, genesis, data_spec, signed.signer).is_some() {
if DataDb::get(txn, genesis, &data_spec.as_key(genesis), &signed.signer.to_bytes()).is_some() {
fatal_slash::<D>(txn, genesis, signed.signer.to_bytes(), "published data multiple times");
return Accumulation::NotReady;
}
@ -203,7 +204,7 @@ pub(crate) async fn handle_application_tx<
// TODO: If this is shares, we need to check they are part of the selected signing set
// Accumulate this data
TributaryState::<D>::accumulate(txn, key, spec, data_spec, signed.signer, &bytes)
DataDb::accumulate(txn, key, spec, data_spec, signed.signer, &bytes)
};
fn check_sign_data_len<D: Db>(
@ -312,7 +313,7 @@ pub(crate) async fn handle_application_tx<
}
let to = Participant::new(to).unwrap();
TributaryDb::<D>::save_share_for_blame(txn, &genesis, from, to, share);
ShareBlame::set(txn, genesis, from.into(), to.into(), &share);
}
}
}
@ -367,7 +368,7 @@ pub(crate) async fn handle_application_tx<
else {
panic!("got all DKG shares yet confirmation nonces aren't Ready(Participating(_))");
};
TributaryDb::<D>::save_confirmation_nonces(txn, genesis, attempt, confirmation_nonces);
ConfirmationNonces::set(txn, genesis, attempt, &confirmation_nonces);
// shares is a HashMap<Participant, Vec<Vec<Vec<u8>>>>, with the values representing:
// - Each of the sender's shares
@ -438,7 +439,7 @@ pub(crate) async fn handle_application_tx<
return;
}
let share = TributaryDb::<D>::share_for_blame(txn, &genesis, accuser, faulty).unwrap();
let share = ShareBlame::get(txn, genesis, accuser.into(), faulty.into()).unwrap();
processors
.send(
spec.set().network,
@ -463,16 +464,13 @@ pub(crate) async fn handle_application_tx<
Accumulation::Ready(DataSet::Participating(shares)) => {
log::info!("got all DkgConfirmed for {}", hex::encode(genesis));
let preprocesses = TributaryDb::<D>::confirmation_nonces(txn, genesis, attempt).unwrap();
let preprocesses = ConfirmationNonces::get(txn, genesis, attempt).unwrap();
// TODO: This can technically happen under very very very specific timing as the txn put
// happens before DkgConfirmed, yet the txn commit isn't guaranteed to
let key_pair = TributaryDb::<D>::currently_completing_key_pair(txn, genesis)
.unwrap_or_else(|| {
panic!(
"in DkgConfirmed handling, which happens after everyone {}",
"(including us) fires DkgConfirmed, yet no confirming key pair"
)
});
let key_pair = CurrentlyCompletingKeyPair::get(txn, genesis).expect(
"in DkgConfirmed handling, which happens after everyone \
(including us) fires DkgConfirmed, yet no confirming key pair",
);
let sig =
match DkgConfirmer::complete(spec, key, attempt, preprocesses, &key_pair, shares) {
Ok(sig) => sig,
@ -496,7 +494,7 @@ pub(crate) async fn handle_application_tx<
}
Transaction::CosignSubstrateBlock(hash) => {
TributaryDb::<D>::recognize_topic(
AttemptDb::recognize_topic(
txn,
genesis,
Topic::SubstrateSign(SubstrateSignableId::CosigningSubstrateBlock(hash)),
@ -508,7 +506,7 @@ pub(crate) async fn handle_application_tx<
);
let key = loop {
let Some(key_pair) = TributaryDb::<D>::key_pair(txn, spec.set()) else {
let Some(key_pair) = KeyPairDb::get(txn, spec.set()) else {
// This can happen based on a timing condition
log::warn!("CosignSubstrateBlock yet keys weren't set yet");
tokio::time::sleep(core::time::Duration::from_secs(1)).await;
@ -535,7 +533,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(
AttemptDb::recognize_topic(
txn,
genesis,
Topic::SubstrateSign(SubstrateSignableId::Batch(batch)),
@ -546,14 +544,14 @@ pub(crate) async fn handle_application_tx<
}
Transaction::SubstrateBlock(block) => {
let plan_ids = TributaryDb::<D>::plan_ids(txn, genesis, block).expect(
let plan_ids = PlanIds::get(txn, &genesis, block).expect(
"synced a tributary block finalizing a substrate block in a provided transaction \
despite us not providing that transaction",
);
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));
AttemptDb::recognize_topic(txn, genesis, Topic::Sign(id));
recognized_id(spec.set(), genesis, RecognizedIdType::Plan, id.to_vec(), nonce).await;
}
}
@ -575,7 +573,7 @@ pub(crate) async fn handle_application_tx<
Accumulation::Ready(DataSet::Participating(mut preprocesses)) => {
unflatten(spec, &mut preprocesses);
NonceDecider::selected_for_signing_substrate(txn, genesis, data.plan);
let key = TributaryDb::<D>::key_pair(txn, spec.set()).unwrap().0 .0;
let key = KeyPairDb::get(txn, spec.set()).unwrap().0 .0;
processors
.send(
spec.set().network,
@ -606,7 +604,7 @@ 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;
let key = KeyPairDb::get(txn, spec.set()).unwrap().0 .0;
processors
.send(
spec.set().network,
@ -629,7 +627,7 @@ pub(crate) async fn handle_application_tx<
let Ok(_) = check_sign_data_len::<D>(txn, spec, data.signed.signer, data.data.len()) else {
return;
};
let key_pair = TributaryDb::<D>::key_pair(txn, spec.set());
let key_pair = KeyPairDb::get(txn, spec.set());
match handle(
txn,
&DataSpecification {
@ -668,7 +666,7 @@ pub(crate) async fn handle_application_tx<
let Ok(_) = check_sign_data_len::<D>(txn, spec, data.signed.signer, data.data.len()) else {
return;
};
let key_pair = TributaryDb::<D>::key_pair(txn, spec.set());
let key_pair = KeyPairDb::get(txn, spec.set());
match handle(
txn,
&DataSpecification {
@ -709,7 +707,7 @@ pub(crate) async fn handle_application_tx<
hex::encode(plan)
);
if TributaryDb::<D>::attempt(txn, genesis, Topic::Sign(plan)).is_none() {
if AttemptDb::attempt(txn, genesis, Topic::Sign(plan)).is_none() {
fatal_slash::<D>(
txn,
genesis,
@ -720,7 +718,7 @@ pub(crate) async fn handle_application_tx<
};
// TODO: Confirm this signer hasn't prior published a completion
let Some(key_pair) = TributaryDb::<D>::key_pair(txn, spec.set()) else {
let Some(key_pair) = KeyPairDb::get(txn, spec.set()) else {
panic!("SignCompleted for recognized plan ID despite not having a key pair for this set")
};
processors

View file

@ -18,16 +18,18 @@ use tributary::{
},
};
use serai_db::DbTxn;
use crate::{
Db,
tributary::handle::{fatal_slash, handle_application_tx},
processors::Processors,
tributary::{TributaryDb, TributarySpec, Transaction},
tributary::{TributarySpec, Transaction, EventDb},
P2p,
};
use super::LastBlock;
use serai_db::DbTxn;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Encode, Decode)]
pub enum RecognizedIdType {
Batch,
@ -53,7 +55,7 @@ async fn handle_block<
RID: RIDTrait<FRid>,
P: P2p,
>(
db: &mut TributaryDb<D>,
db: &mut D,
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
recognized_id: RID,
processors: &Pro,
@ -69,12 +71,12 @@ async fn handle_block<
let mut event_id = 0;
#[allow(clippy::explicit_counter_loop)] // event_id isn't TX index. It just currently lines up
for tx in block.transactions {
if TributaryDb::<D>::handled_event(&db.0, hash, event_id) {
if EventDb::get(db, hash, event_id).is_some() {
event_id += 1;
continue;
}
let mut txn = db.0.txn();
let mut txn = db.txn();
match tx {
TributaryTransaction::Tendermint(TendermintTx::SlashEvidence(ev)) => {
@ -121,7 +123,7 @@ async fn handle_block<
}
}
TributaryDb::<D>::handle_event(&mut txn, hash, event_id);
EventDb::handle_event(&mut txn, hash, event_id);
txn.commit();
event_id += 1;
@ -139,7 +141,7 @@ pub(crate) async fn handle_new_blocks<
RID: RIDTrait<FRid>,
P: P2p,
>(
db: &mut TributaryDb<D>,
db: &mut D,
key: &Zeroizing<<Ristretto as Ciphersuite>::F>,
recognized_id: RID,
processors: &Pro,
@ -148,7 +150,7 @@ pub(crate) async fn handle_new_blocks<
tributary: &TributaryReader<D, Transaction>,
) {
let genesis = tributary.genesis();
let mut last_block = db.last_block(genesis);
let mut last_block = LastBlock::get(db, genesis).unwrap_or(genesis);
while let Some(next) = tributary.block_after(&last_block) {
let block = tributary.block(&next).unwrap();
@ -176,7 +178,9 @@ pub(crate) async fn handle_new_blocks<
)
.await;
last_block = next;
db.set_last_block(genesis, next);
let mut txn = db.txn();
LastBlock::set(&mut txn, genesis, &next);
txn.commit();
}
}
@ -209,7 +213,7 @@ pub(crate) async fn scan_tributaries_task<
async move {
let spec = &spec;
let reader = tributary.reader();
let mut tributary_db = TributaryDb::new(raw_db.clone());
let mut tributary_db = raw_db.clone();
loop {
// Check if the set was retired, and if so, don't further operate
if crate::MainDb::<D>::is_tributary_retired(&raw_db, spec.set()) {