#![warn(clippy::pedantic, clippy::nursery)]
#![allow(clippy::cast_possible_truncation)]
#![allow(clippy::cast_possible_wrap)]
#![allow(clippy::cast_precision_loss)]
#![allow(clippy::cast_sign_loss)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::default_trait_access)]
#![allow(clippy::doc_markdown)]
#![allow(clippy::future_not_send)]
#![allow(clippy::missing_const_for_fn)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::redundant_pub_crate)]
#![allow(clippy::return_self_not_must_use)]
#![allow(clippy::significant_drop_tightening)]
#![allow(clippy::similar_names)]
#![allow(clippy::transmute_ptr_to_ptr)]
#![allow(clippy::unsafe_derive_deserialize)]
#![allow(clippy::use_self)]
#![allow(where_clauses_object_safety)] extern crate self as fedimint_core;
use std::fmt::Debug;
use std::io::Error;
use std::str::FromStr;
pub use amount::*;
pub use anyhow;
use bitcoin_hashes::hash_newtype;
use bitcoin_hashes::sha256::Hash as Sha256;
pub use bitcoin_hashes::Hash as BitcoinHash;
pub use macro_rules_attribute::apply;
pub use module::ServerModule;
pub use peer_id::*;
use serde::{Deserialize, Serialize};
use thiserror::Error;
pub use tiered::Tiered;
pub use tiered_multi::*;
pub use {hex, secp256k1};
pub use crate::core::server;
use crate::encoding::{Decodable, DecodeError, Encodable};
use crate::module::registry::ModuleDecoderRegistry;
pub mod admin_client;
mod amount;
pub mod backup;
pub mod bitcoin_migration;
pub mod bls12_381_serde;
pub mod config;
pub mod core;
pub mod db;
pub mod encoding;
pub mod endpoint_constants;
pub mod envs;
pub mod epoch;
pub mod fmt_utils;
pub mod invite_code;
#[macro_use]
pub mod macros;
pub mod module;
pub mod net;
mod peer_id;
pub mod runtime;
pub mod task;
pub mod tiered;
pub mod tiered_multi;
pub mod time;
pub mod timing;
pub mod transaction;
pub mod txoproof;
pub mod util;
pub mod session_outcome;
hash_newtype!(
pub struct TransactionId(Sha256);
);
#[derive(Debug, Eq, PartialEq, Copy, Hash, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BitcoinAmountOrAll {
All,
#[serde(untagged)]
Amount(#[serde(with = "bitcoin::amount::serde::as_sat")] bitcoin::Amount),
}
impl FromStr for BitcoinAmountOrAll {
type Err = anyhow::Error;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
if s == "all" {
Ok(BitcoinAmountOrAll::All)
} else {
let amount = Amount::from_str(s)?;
Ok(BitcoinAmountOrAll::Amount(amount.try_into()?))
}
}
}
#[derive(
Debug,
Clone,
Copy,
Eq,
PartialEq,
PartialOrd,
Ord,
Hash,
Deserialize,
Serialize,
Encodable,
Decodable,
)]
pub struct OutPoint {
pub txid: TransactionId,
pub out_idx: u64,
}
impl std::fmt::Display for OutPoint {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.txid, self.out_idx)
}
}
impl Encodable for TransactionId {
fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, Error> {
let bytes = &self[..];
writer.write_all(bytes)?;
Ok(bytes.len())
}
}
impl Decodable for TransactionId {
fn consensus_decode<D: std::io::Read>(
d: &mut D,
_modules: &ModuleDecoderRegistry,
) -> Result<Self, DecodeError> {
let mut bytes = [0u8; 32];
d.read_exact(&mut bytes).map_err(DecodeError::from_err)?;
Ok(TransactionId::from_byte_array(bytes))
}
}
#[derive(
Copy,
Clone,
Debug,
PartialEq,
Ord,
PartialOrd,
Eq,
Hash,
Serialize,
Deserialize,
Encodable,
Decodable,
)]
pub struct Feerate {
pub sats_per_kvb: u64,
}
impl Feerate {
pub fn calculate_fee(&self, weight: u64) -> bitcoin::Amount {
let sats = weight_to_vbytes(weight) * self.sats_per_kvb / 1000;
bitcoin::Amount::from_sat(sats)
}
}
const WITNESS_SCALE_FACTOR: u64 = bitcoin::constants::WITNESS_SCALE_FACTOR as u64;
pub fn weight_to_vbytes(weight: u64) -> u64 {
(weight + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR
}
#[derive(Debug, Error)]
pub enum CoreError {
#[error("Mismatching outcome variant: expected {0}, got {1}")]
MismatchingVariant(&'static str, &'static str),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn converts_weight_to_vbytes() {
assert_eq!(1, weight_to_vbytes(4));
assert_eq!(2, weight_to_vbytes(5));
}
#[test]
fn calculate_fee() {
let feerate = Feerate { sats_per_kvb: 1000 };
assert_eq!(bitcoin::Amount::from_sat(25), feerate.calculate_fee(100));
assert_eq!(bitcoin::Amount::from_sat(26), feerate.calculate_fee(101));
}
#[test]
fn test_deserialize_amount_or_all() {
let all: BitcoinAmountOrAll = serde_json::from_str("\"all\"").unwrap();
assert_eq!(all, BitcoinAmountOrAll::All);
let all: BitcoinAmountOrAll = serde_json::from_str("12345").unwrap();
assert_eq!(
all,
BitcoinAmountOrAll::Amount(bitcoin::Amount::from_sat(12345))
);
}
}