Skip to content

Commit

Permalink
chore: bump fedimint-dummy to 0.3
Browse files Browse the repository at this point in the history
  • Loading branch information
Kodylow committed Apr 23, 2024
1 parent f0ee5c8 commit cf5fa0a
Show file tree
Hide file tree
Showing 12 changed files with 2,704 additions and 1,400 deletions.
3,774 changes: 2,455 additions & 1,319 deletions Cargo.lock

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,18 @@ license-file = "LICENSE"
keywords = ["bitcoin", "lightning", "chaumian", "e-cash", "federated"]

[workspace.dependencies]
fedimintd = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
fedimint-cli = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
fedimint-core = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
fedimint-client = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
fedimint-logging = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
fedimint-server = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
fedimint-testing = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
devimint = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
aead = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
fedimintd = "0.3.0"
fedimint-cli = "0.3.0"
fedimint-core = "0.3.0"
fedimint-client = "0.3.0"
fedimint-logging = "0.3.0"
fedimint-server = "0.3.0"
fedimint-testing = "0.3.0"
devimint = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0" }
aead = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0" }
threshold_crypto = { git = "https://github.com/fedimint/threshold_crypto" }
tbs = { git = "https://github.com/fedimint/fedimint", tag = "v0.2.1" }
tbs = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0" }
secp256k1 = "0.24.3"

# Comment above lines and uncomment these to work with local fedimint dependencies
# fedimintd = { path = "../fedimint/fedimintd" }
Expand Down
8 changes: 4 additions & 4 deletions fedimint-dummy-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ path = "src/lib.rs"
[dependencies]
async-trait = "0.1.73"
anyhow = "1.0.66"
fedimint-dummy-common ={ path = "../fedimint-dummy-common" }
fedimint-dummy-common = { path = "../fedimint-dummy-common" }
fedimint-client = { workspace = true }
fedimint-core ={ workspace = true }
fedimint-core = { workspace = true }
futures = "0.3"
erased-serde = "0.3"
rand = "0.8.5"
secp256k1 = "0.24.2"
serde = {version = "1.0.149", features = [ "derive" ] }
secp256k1 = { workspace = true }
serde = { version = "1.0.149", features = ["derive"] }
strum = "0.24"
strum_macros = "0.24"
tracing = "0.1.37"
Expand Down
136 changes: 136 additions & 0 deletions fedimint-dummy-client/src/db.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
use fedimint_client::sm::DynState;
use fedimint_core::core::{IntoDynInstance, ModuleInstanceId, OperationId};
use fedimint_core::db::{DatabaseTransaction, DatabaseValue, IDatabaseTransactionOpsCoreTyped};
use fedimint_core::encoding::{Decodable, Encodable};
use fedimint_core::module::registry::ModuleDecoderRegistry;
use fedimint_core::{impl_db_record, Amount};
use strum_macros::EnumIter;
use tracing::warn;

use crate::states::DummyStateMachine;

#[repr(u8)]
#[derive(Clone, Debug, EnumIter)]
pub enum DbKeyPrefix {
ClientFunds = 0x04,
// Used to verify that 0x50 key can be written to, which used to conflict with
// `DatabaseVersionKeyV0`
ClientName = 0x50,
}

impl std::fmt::Display for DbKeyPrefix {
Expand All @@ -19,6 +29,132 @@ pub struct DummyClientFundsKeyV0;

impl_db_record!(
key = DummyClientFundsKeyV0,
value = (),
db_prefix = DbKeyPrefix::ClientFunds,
);

#[derive(Debug, Clone, Encodable, Decodable, Eq, PartialEq, Hash)]
pub struct DummyClientFundsKeyV1;

impl_db_record!(
key = DummyClientFundsKeyV1,
value = Amount,
db_prefix = DbKeyPrefix::ClientFunds,
);

#[derive(Debug, Clone, Encodable, Decodable, Eq, PartialEq, Hash)]
pub struct DummyClientNameKey;

impl_db_record!(
key = DummyClientNameKey,
value = String,
db_prefix = DbKeyPrefix::ClientName,
);

/// Migrates the database from version 0 to version 1 by
/// removing `DummyClientFundsKeyV0` and inserting `DummyClientFundsKeyV1`.
/// The new key/value pair has an `Amount` as the value.
pub async fn migrate_to_v1(
dbtx: &mut DatabaseTransaction<'_>,
) -> anyhow::Result<Option<(Vec<DynState>, Vec<DynState>)>> {
if dbtx.remove_entry(&DummyClientFundsKeyV0).await.is_some() {
// Since this is a dummy migration, we can insert any value for the client
// funds. Real modules should handle the funds properly.

dbtx.insert_new_entry(&DummyClientFundsKeyV1, &Amount::from_sats(1000))
.await;
} else {
warn!("Dummy client did not have client funds, skipping database migration");
}

Ok(None)
}

/// Migrates the database from version 1 to version 2. Maps all `Unreachable`
/// states in the state machine to `InputDone`.
pub async fn migrate_to_v2(
module_instance_id: ModuleInstanceId,
active_states: Vec<(Vec<u8>, OperationId)>,
inactive_states: Vec<(Vec<u8>, OperationId)>,
decoders: ModuleDecoderRegistry,
) -> anyhow::Result<Option<(Vec<DynState>, Vec<DynState>)>> {
let mut new_active_states = Vec::new();
for (active_state, _) in active_states {
// Try to decode the bytes as a `DynState`
let dynstate = DynState::from_bytes(active_state.as_slice(), &decoders)?;
let typed_state = dynstate
.as_any()
.downcast_ref::<DummyStateMachine>()
.expect("Unexpected DynState suppilied to migration function");

match typed_state {
DummyStateMachine::Unreachable(_, _) => {
// Try to parse the bytes as the `Unreachable` struct to simulate a deleted
// state. In a real migration, `DynState::from_bytes` will
// fail since `DummyStateMachine::Unreachable` will not exist.
if let Ok(unreachable) =
Unreachable::consensus_decode_vec(active_state.clone(), &decoders)
{
new_active_states.push(
DummyStateMachine::OutputDone(unreachable.amount, unreachable.operation_id)
.into_dyn(module_instance_id),
);
}
}
state => new_active_states.push(state.clone().into_dyn(module_instance_id)),
}
}

let mut new_inactive_states = Vec::new();
for (inactive_state, _) in inactive_states {
// Try to decode the bytes as a `DynState`
let dynstate = DynState::from_bytes(inactive_state.as_slice(), &decoders)?;
let typed_state = dynstate
.as_any()
.downcast_ref::<DummyStateMachine>()
.expect("Unexpected DynState suppilied to migration function");

match typed_state {
DummyStateMachine::Unreachable(_, _) => {
// Try to parse the bytes as the `Unreachable` struct to simulate a deleted
// state. In a real migration, `DynState::from_bytes` will
// fail since `DummyStateMachine::Unreachable` will not exist.
if let Ok(unreachable) =
Unreachable::consensus_decode_vec(inactive_state.clone(), &decoders)
{
new_inactive_states.push(
DummyStateMachine::OutputDone(unreachable.amount, unreachable.operation_id)
.into_dyn(module_instance_id),
);
}
}
state => new_inactive_states.push(state.clone().into_dyn(module_instance_id)),
}
}

Ok(Some((new_active_states, new_inactive_states)))
}

#[derive(Debug)]
struct Unreachable {
_module_instance_id: ModuleInstanceId,
operation_id: OperationId,
amount: Amount,
}

impl Decodable for Unreachable {
fn consensus_decode<R: std::io::Read>(
reader: &mut R,
modules: &ModuleDecoderRegistry,
) -> Result<Self, fedimint_core::encoding::DecodeError> {
let module_instance_id = ModuleInstanceId::consensus_decode(reader, modules)?;
let operation_id = OperationId::consensus_decode(reader, modules)?;
let amount = Amount::consensus_decode(reader, modules)?;

Ok(Unreachable {
_module_instance_id: module_instance_id,
operation_id,
amount,
})
}
}
56 changes: 42 additions & 14 deletions fedimint-dummy-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ use std::time::Duration;

use anyhow::{anyhow, format_err, Context as _};
use common::broken_fed_key_pair;
use db::DbKeyPrefix;
use db::{migrate_to_v1, migrate_to_v2, DbKeyPrefix, DummyClientFundsKeyV1, DummyClientNameKey};
use fedimint_client::db::ClientMigrationFn;
use fedimint_client::module::init::{ClientModuleInit, ClientModuleInitArgs};
use fedimint_client::module::recovery::NoModuleBackup;
use fedimint_client::module::{ClientContext, ClientModule, IClientModule};
use fedimint_client::sm::{Context, ModuleNotifier};
use fedimint_client::transaction::{ClientInput, ClientOutput, TransactionBuilder};
use fedimint_client::DynGlobalClientContext;
use fedimint_core::api::GlobalFederationApi;
use fedimint_core::core::{Decoder, KeyPair, OperationId};
use fedimint_core::db::{Database, DatabaseTransaction, IDatabaseTransactionOpsCoreTyped};
use fedimint_core::db::{
Database, DatabaseTransaction, DatabaseVersion, IDatabaseTransactionOpsCoreTyped,
};
use fedimint_core::module::{
ApiVersion, CommonModuleInit, ModuleCommon, ModuleInit, MultiApiVersion, TransactionItemAmount,
};
Expand All @@ -25,22 +26,20 @@ use fedimint_dummy_common::{
fed_key_pair, DummyCommonInit, DummyInput, DummyModuleTypes, DummyOutput, DummyOutputOutcome,
KIND,
};
use futures::{pin_mut, StreamExt};
use futures::{pin_mut, FutureExt, StreamExt};
use secp256k1::{PublicKey, Secp256k1};
use states::DummyStateMachine;
use strum::IntoEnumIterator;

use crate::db::DummyClientFundsKeyV0;

pub mod api;
mod db;
pub mod db;
pub mod states;

#[derive(Debug)]
pub struct DummyClientModule {
cfg: DummyClientConfig,
key: KeyPair,
notifier: ModuleNotifier<DynGlobalClientContext, DummyStateMachine>,
notifier: ModuleNotifier<DummyStateMachine>,
client_ctx: ClientContext<Self>,
db: Database,
}
Expand Down Expand Up @@ -88,6 +87,14 @@ impl ClientModule for DummyClientModule {
})
}

// fn input_fee(&self, _input: &<Self::Common as ModuleCommon>::Input) ->
// Option<Amount> { Some(self.cfg.tx_fee)
// }

// fn output_fee(&self, _output: &<Self::Common as ModuleCommon>::Output) ->
// Option<Amount> { Some(self.cfg.tx_fee)
// }

fn supports_being_primary(&self) -> bool {
true
}
Expand All @@ -106,7 +113,7 @@ impl ClientModule for DummyClientModule {
return Err(format_err!("Insufficient funds"));
}
let updated = funds - amount;
dbtx.insert_entry(&DummyClientFundsKeyV0, &updated).await;
dbtx.insert_entry(&DummyClientFundsKeyV1, &updated).await;

// Construct input and state machine to track the tx
Ok(vec![ClientInput {
Expand Down Expand Up @@ -296,7 +303,7 @@ impl DummyClientModule {
return Err(format_err!("Wrong account id"));
}

dbtx.insert_entry(&DummyClientFundsKeyV0, &new_balance)
dbtx.insert_entry(&DummyClientFundsKeyV1, &new_balance)
.await;
dbtx.commit_tx().await;
Ok(())
Expand All @@ -309,17 +316,17 @@ impl DummyClientModule {
}

async fn get_funds(dbtx: &mut DatabaseTransaction<'_>) -> Amount {
let funds = dbtx.get_value(&DummyClientFundsKeyV0).await;
let funds = dbtx.get_value(&DummyClientFundsKeyV1).await;
funds.unwrap_or(Amount::ZERO)
}

#[derive(Debug, Clone)]
pub struct DummyClientInit;

// TODO: Boilerplate-code
#[apply(async_trait_maybe_send!)]
impl ModuleInit for DummyClientInit {
type Common = DummyCommonInit;
const DATABASE_VERSION: DatabaseVersion = DatabaseVersion(2);

async fn dump_database(
&self,
Expand All @@ -334,10 +341,15 @@ impl ModuleInit for DummyClientInit {
for table in filtered_prefixes {
match table {
DbKeyPrefix::ClientFunds => {
if let Some(funds) = dbtx.get_value(&DummyClientFundsKeyV0).await {
if let Some(funds) = dbtx.get_value(&DummyClientFundsKeyV1).await {
items.insert("Dummy Funds".to_string(), Box::new(funds));
}
}
DbKeyPrefix::ClientName => {
if let Some(name) = dbtx.get_value(&DummyClientNameKey).await {
items.insert("Dummy Name".to_string(), Box::new(name));
}
}
}
}

Expand Down Expand Up @@ -367,4 +379,20 @@ impl ClientModuleInit for DummyClientInit {
db: args.db().clone(),
})
}

fn get_database_migrations(&self) -> BTreeMap<DatabaseVersion, ClientMigrationFn> {
let mut migrations: BTreeMap<DatabaseVersion, ClientMigrationFn> = BTreeMap::new();
migrations.insert(DatabaseVersion(0), move |dbtx, _, _, _, _| {
migrate_to_v1(dbtx).boxed()
});

migrations.insert(
DatabaseVersion(1),
move |_, module_instance_id, active_states, inactive_states, decoders| {
migrate_to_v2(module_instance_id, active_states, inactive_states, decoders).boxed()
},
);

migrations
}
}
Loading

0 comments on commit cf5fa0a

Please sign in to comment.