fedimint_client::module

Trait ClientModule

source
pub trait ClientModule:
    Debug
    + MaybeSend
    + MaybeSync
    + 'static {
    type Init: ClientModuleInit;
    type Common: ModuleCommon;
    type Backup: ModuleBackup;
    type ModuleStateMachineContext: Context;
    type States: State<ModuleContext = Self::ModuleStateMachineContext> + IntoDynInstance<DynType = DynState>;

Show 16 methods // Required methods fn context(&self) -> Self::ModuleStateMachineContext; fn input_fee( &self, amount: Amount, input: &<Self::Common as ModuleCommon>::Input, ) -> Option<Amount>; fn output_fee( &self, output: &<Self::Common as ModuleCommon>::Output, ) -> Option<Amount>; // Provided methods fn decoder() -> Decoder { ... } fn kind() -> ModuleKind { ... } fn start<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait { ... } fn handle_cli_command<'life0, 'life1, 'async_trait>( &'life0 self, _args: &'life1 [OsString], ) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait { ... } fn handle_rpc<'life0, 'async_trait>( &'life0 self, _method: String, _request: Value, ) -> Pin<Box<dyn Future<Output = BoxStream<'_, Result<Value>>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait { ... } fn supports_backup(&self) -> bool { ... } fn backup<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Self::Backup>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait { ... } fn supports_being_primary(&self) -> bool { ... } fn create_final_inputs_and_outputs<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _dbtx: &'life1 mut DatabaseTransaction<'life2>, _operation_id: OperationId, _input_amount: Amount, _output_amount: Amount, ) -> Pin<Box<dyn Future<Output = Result<(Vec<ClientInput<<Self::Common as ModuleCommon>::Input, Self::States>>, Vec<ClientOutput<<Self::Common as ModuleCommon>::Output, Self::States>>)>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn await_primary_module_output<'life0, 'async_trait>( &'life0 self, _operation_id: OperationId, _out_point: OutPoint, ) -> Pin<Box<dyn Future<Output = Result<Amount>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait { ... } fn get_balance<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _dbtx: &'life1 mut DatabaseTransaction<'life2>, ) -> Pin<Box<dyn Future<Output = Amount> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... } fn subscribe_balance_changes<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = BoxStream<'static, ()>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait { ... } fn leave<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _dbtx: &'life1 mut DatabaseTransaction<'life2>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait { ... }
}
Expand description

Fedimint module client

Required Associated Types§

source

type Init: ClientModuleInit

source

type Common: ModuleCommon

Common module types shared between client and server

source

type Backup: ModuleBackup

Data stored in regular backups so that restoring doesn’t have to start from epoch 0

source

type ModuleStateMachineContext: Context

Data and API clients available to state machine transitions of this module

source

type States: State<ModuleContext = Self::ModuleStateMachineContext> + IntoDynInstance<DynType = DynState>

All possible states this client can submit to the executor

Required Methods§

source

fn context(&self) -> Self::ModuleStateMachineContext

source

fn input_fee( &self, amount: Amount, input: &<Self::Common as ModuleCommon>::Input, ) -> Option<Amount>

Returns the fee the processing of this input requires.

If the semantics of a given input aren’t known this function returns None, this only happens if a future version of Fedimint introduces a new input variant. For clients this should only be the case when processing transactions created by other users, so the result of this function can be unwrapped whenever dealing with inputs generated by ourselves.

source

fn output_fee( &self, output: &<Self::Common as ModuleCommon>::Output, ) -> Option<Amount>

Returns the fee the processing of this output requires.

If the semantics of a given output aren’t known this function returns None, this only happens if a future version of Fedimint introduces a new output variant. For clients this should only be the case when processing transactions created by other users, so the result of this function can be unwrapped whenever dealing with inputs generated by ourselves.

Provided Methods§

source

fn decoder() -> Decoder

source

fn kind() -> ModuleKind

source

fn start<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait,

Initialize client.

Called by the core client code on start, after ClientContext is fully initialized, so unlike during ClientModuleInit::init, access to global client is allowed.

source

fn handle_cli_command<'life0, 'life1, 'async_trait>( &'life0 self, _args: &'life1 [OsString], ) -> Pin<Box<dyn Future<Output = Result<Value>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

source

fn handle_rpc<'life0, 'async_trait>( &'life0 self, _method: String, _request: Value, ) -> Pin<Box<dyn Future<Output = BoxStream<'_, Result<Value>>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait,

source

fn supports_backup(&self) -> bool

source

fn backup<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<Self::Backup>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait,

source

fn supports_being_primary(&self) -> bool

Does this module support being a primary module

If it does it must implement:

source

fn create_final_inputs_and_outputs<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _dbtx: &'life1 mut DatabaseTransaction<'life2>, _operation_id: OperationId, _input_amount: Amount, _output_amount: Amount, ) -> Pin<Box<dyn Future<Output = Result<(Vec<ClientInput<<Self::Common as ModuleCommon>::Input, Self::States>>, Vec<ClientOutput<<Self::Common as ModuleCommon>::Output, Self::States>>)>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Creates all inputs and outputs necessary to balance the transaction. The function returns an error if and only if the client’s funds are not sufficient to create the inputs necessary to fully fund the transaction.

A returned input also contains:

  • A set of private keys belonging to the input for signing the transaction
  • A closure that generates states belonging to the input. This closure takes the transaction id of the transaction in which the input was used and the input index as input since these cannot be known at time of calling create_funding_input and have to be injected later.

A returned output also contains:

  • A closure that generates states belonging to the output. This closure takes the transaction id of the transaction in which the output was used and the output index as input since these cannot be known at time of calling create_change_output and have to be injected later.
source

fn await_primary_module_output<'life0, 'async_trait>( &'life0 self, _operation_id: OperationId, _out_point: OutPoint, ) -> Pin<Box<dyn Future<Output = Result<Amount>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait,

Waits for the funds from an output created by Self::create_final_inputs_and_outputs to become available. This function returning typically implies a change in the output of Self::get_balance.

source

fn get_balance<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _dbtx: &'life1 mut DatabaseTransaction<'life2>, ) -> Pin<Box<dyn Future<Output = Amount> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Returns the balance held by this module and available for funding transactions.

source

fn subscribe_balance_changes<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = BoxStream<'static, ()>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait,

Returns a stream that will output the updated module balance each time it changes.

source

fn leave<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _dbtx: &'life1 mut DatabaseTransaction<'life2>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: Sync + 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Leave the federation

While technically there’s nothing stopping the client from just abandoning Federation at any point by deleting all the related local data, it is useful to make sure it’s safe beforehand.

This call indicates the desire of the caller client code to orderly and safely leave the Federation by this module instance. The goal of the implementations is to fulfil that wish, giving prompt and informative feedback if it’s not yet possible.

The client module implementation should handle the request and return as fast as possible avoiding blocking for longer than necessary. This would usually involve some combination of:

  • recording the state of being in process of leaving the Federation to prevent initiating new conditions that could delay its completion;
  • performing any fast to complete cleanup/exit logic;
  • initiating any time-consuming logic (e.g. canceling outstanding contracts), as background jobs, tasks machines, etc.
  • checking for any conditions indicating it might not be safe to leave at the moment.

This function should return Ok only if from the perspective of this module instance, it is safe to delete client data and stop using it, with no further actions (like background jobs) required to complete.

This function should return an error if it’s not currently possible to safely (e.g. without loosing funds) leave the Federation. It should avoid running indefinitely trying to complete any cleanup actions necessary to reach a clean state, preferring spawning new state machines and returning an informative error about cleanup still in progress.

If any internal task needs to complete, any user action is required, or even external condition needs to be met this function should return a Err.

Notably modules should not disable interaction that might be necessary for the user (possibly through other modules) to leave the Federation. In particular a Mint module should retain ability to create new notes, and LN module should retain ability to send funds out.

Calling code must NOT assume that a module that once returned Ok, will not return Err at later point. E.g. a Mint module might have no outstanding balance at first, but other modules winding down might “cash-out” to Ecash.

Before leaving the Federation and deleting any state the calling code must collect a full round of Ok from all the modules.

Calling code should allow the user to override and ignore any outstanding errors, after sufficient amount of warnings. Ideally, this should be done on per-module basis, to avoid mistakes.

Object Safety§

This trait is not object safe.

Implementors§