use alloc::collections::VecDeque;
use core::borrow::Borrow;
use core::convert::TryFrom;
use core::convert::TryInto;
use core::fmt::{self, Debug, Formatter};
use core::iter::FromIterator;
use core::str::FromStr;
use core::time::Duration;
use bitcoin;
use bitcoin::bech32::{u5, FromBase32};
use bitcoin::hashes::hex::ToHex;
use bitcoin::hashes::sha256::Hash as Sha256Hash;
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
use bitcoin::hashes::Hash;
use bitcoin::secp256k1::ecdh::SharedSecret;
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
use bitcoin::secp256k1::{schnorr, All, Message, PublicKey, Secp256k1, SecretKey};
use bitcoin::util::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey};
use bitcoin::util::sighash::SighashCache;
use bitcoin::{secp256k1, Address, PrivateKey, Transaction, TxOut};
use bitcoin::{EcdsaSighashType, Network, OutPoint, Script};
use lightning::chain;
use lightning::chain::keysinterface::{
ChannelSigner, EntropySource, KeyMaterial, NodeSigner, Recipient, SignerProvider,
SpendableOutputDescriptor,
};
use lightning::ln::chan_utils::{
ChannelPublicKeys, ChannelTransactionParameters, CounterpartyChannelTransactionParameters,
};
use lightning::ln::msgs::UnsignedGossipMessage;
use lightning::ln::script::ShutdownScript;
use lightning::ln::{PaymentHash, PaymentPreimage};
use lightning::util::invoice::construct_invoice_preimage;
use lightning::util::logger::Logger;
use lightning::util::ser::Writeable;
use lightning_invoice::{RawDataPart, RawHrp, RawInvoice, SignedRawInvoice};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
#[allow(unused_imports)]
use log::{debug, info, trace, warn};
use serde_bolt::to_vec;
use crate::chain::tracker::ChainTracker;
use crate::chain::tracker::Headers;
use crate::channel::{
Channel, ChannelBalance, ChannelBase, ChannelId, ChannelSetup, ChannelSlot, ChannelStub,
};
use crate::invoice::{Invoice, InvoiceAttributes};
use crate::monitor::ChainMonitor;
use crate::persist::model::NodeEntry;
use crate::persist::{Persist, SeedPersist};
use crate::policy::error::{policy_error, ValidationError};
use crate::policy::validator::{BalanceDelta, ValidatorFactory};
use crate::policy::validator::{EnforcementState, Validator};
use crate::policy::Policy;
use crate::policy_err;
use crate::prelude::*;
use crate::signer::derive::KeyDerivationStyle;
use crate::signer::my_keys_manager::MyKeysManager;
use crate::signer::StartingTimeFactory;
use crate::sync::{Arc, Weak};
use crate::tx::tx::PreimageMap;
use crate::txoo::get_latest_checkpoint;
use crate::util::clock::Clock;
use crate::util::crypto_utils::{sighash_from_heartbeat, signature_to_bitcoin_vec};
use crate::util::debug_utils::{DebugBytes, DebugMapPaymentState, DebugMapRoutedPayment};
use crate::util::ser_util::DurationHandler;
use crate::util::status::{failed_precondition, internal_error, invalid_argument, Status};
use crate::util::velocity::VelocityControl;
use crate::wallet::Wallet;
const INVOICE_PRUNE_TIME: Duration = Duration::from_secs(60 * 60 * 24);
#[derive(Copy, Clone, Debug)]
pub struct NodeConfig {
pub network: Network,
pub key_derivation_style: KeyDerivationStyle,
pub use_checkpoints: bool,
}
impl NodeConfig {
pub fn new(network: Network) -> NodeConfig {
NodeConfig {
network,
key_derivation_style: KeyDerivationStyle::Native,
use_checkpoints: true,
}
}
}
#[serde_as]
#[derive(Clone, Serialize, Deserialize)]
pub struct PaymentState {
pub invoice_hash: [u8; 32],
pub amount_msat: u64,
pub payee: PublicKey,
#[serde_as(as = "DurationHandler")]
pub duration_since_epoch: Duration,
#[serde_as(as = "DurationHandler")]
pub expiry_duration: Duration,
pub is_fulfilled: bool,
pub payment_type: PaymentType,
}
impl Debug for PaymentState {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("PaymentState")
.field("invoice_hash", &DebugBytes(&self.invoice_hash))
.field("amount_msat", &self.amount_msat)
.field("payee", &self.payee)
.field("duration_since_epoch", &self.duration_since_epoch)
.field("expiry_duration", &self.expiry_duration)
.field("is_fulfilled", &self.is_fulfilled)
.field("payment_type", &self.payment_type)
.finish()
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum PaymentType {
Invoice,
Keysend,
}
#[derive(Clone, Debug)]
pub struct RoutedPayment {
pub incoming: OrderedMap<ChannelId, u64>,
pub outgoing: OrderedMap<ChannelId, u64>,
pub preimage: Option<PaymentPreimage>,
}
impl RoutedPayment {
pub fn new() -> RoutedPayment {
RoutedPayment { incoming: OrderedMap::new(), outgoing: OrderedMap::new(), preimage: None }
}
pub fn is_fulfilled(&self) -> bool {
self.preimage.is_some()
}
pub fn is_no_outgoing(&self) -> bool {
self.outgoing.values().into_iter().sum::<u64>() == 0
}
pub fn updated_incoming_outgoing(
&self,
channel_id: &ChannelId,
incoming_amount_sat: u64,
outgoing_amount_sat: u64,
) -> (u64, u64) {
let mut incoming = self.incoming.clone();
incoming.insert(channel_id.clone(), incoming_amount_sat);
let mut outgoing = self.outgoing.clone();
outgoing.insert(channel_id.clone(), outgoing_amount_sat);
(incoming.values().into_iter().sum::<u64>(), outgoing.values().into_iter().sum::<u64>())
}
pub fn incoming_outgoing(&self) -> (u64, u64) {
(
self.incoming.values().into_iter().sum::<u64>(),
self.outgoing.values().into_iter().sum::<u64>(),
)
}
pub fn apply(
&mut self,
channel_id: &ChannelId,
incoming_amount_sat: u64,
outgoing_amount_sat: u64,
) {
self.incoming.insert(channel_id.clone(), incoming_amount_sat);
self.outgoing.insert(channel_id.clone(), outgoing_amount_sat);
}
}
pub struct NodeState {
pub invoices: Map<PaymentHash, PaymentState>,
pub issued_invoices: Map<PaymentHash, PaymentState>,
pub payments: Map<PaymentHash, RoutedPayment>,
pub excess_amount: u64,
pub log_prefix: String,
pub velocity_control: VelocityControl,
pub fee_velocity_control: VelocityControl,
}
impl Debug for NodeState {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("NodeState")
.field("invoices", &DebugMapPaymentState(&self.invoices))
.field("issued_invoices", &DebugMapPaymentState(&self.issued_invoices))
.field("payments", &DebugMapRoutedPayment(&self.payments))
.field("excess_amount", &self.excess_amount)
.field("log_prefix", &self.log_prefix)
.field("velocity_control", &self.velocity_control)
.finish()
}
}
impl PreimageMap for NodeState {
fn has_preimage(&self, hash: &PaymentHash) -> bool {
self.payments.get(hash).map(|p| p.preimage.is_some()).unwrap_or(false)
}
}
impl NodeState {
pub fn new(velocity_control: VelocityControl, fee_velocity_control: VelocityControl) -> Self {
NodeState {
invoices: Map::new(),
issued_invoices: Map::new(),
payments: Map::new(),
excess_amount: 0,
log_prefix: String::new(),
velocity_control,
fee_velocity_control,
}
}
fn with_log_prefix(
self,
velocity_control: VelocityControl,
fee_velocity_control: VelocityControl,
log_prefix: String,
) -> Self {
NodeState {
invoices: self.invoices,
issued_invoices: self.issued_invoices,
payments: self.payments,
excess_amount: self.excess_amount,
log_prefix,
velocity_control,
fee_velocity_control,
}
}
#[cfg(test)]
pub(crate) fn validate_and_apply_payments(
&mut self,
channel_id: &ChannelId,
incoming_payment_summary: &Map<PaymentHash, u64>,
outgoing_payment_summary: &Map<PaymentHash, u64>,
balance_delta: &BalanceDelta,
validator: Arc<dyn Validator>,
) -> Result<(), ValidationError> {
self.validate_payments(
channel_id,
incoming_payment_summary,
outgoing_payment_summary,
balance_delta,
validator.clone(),
)?;
self.apply_payments(
channel_id,
incoming_payment_summary,
outgoing_payment_summary,
balance_delta,
validator.clone(),
);
Ok(())
}
pub fn validate_payments(
&self,
channel_id: &ChannelId,
incoming_payment_summary: &Map<PaymentHash, u64>,
outgoing_payment_summary: &Map<PaymentHash, u64>,
balance_delta: &BalanceDelta,
validator: Arc<dyn Validator>,
) -> Result<(), ValidationError> {
debug!(
"validating payments on channel {} - in {:?} out {:?}",
channel_id, incoming_payment_summary, outgoing_payment_summary
);
let mut hashes: UnorderedSet<&PaymentHash> = UnorderedSet::new();
hashes.extend(incoming_payment_summary.keys());
hashes.extend(outgoing_payment_summary.keys());
let mut unbalanced = Vec::new();
for hash_r in hashes.iter() {
let incoming_for_chan_sat =
incoming_payment_summary.get(hash_r).map(|a| *a).unwrap_or(0);
let outgoing_for_chan_sat =
outgoing_payment_summary.get(hash_r).map(|a| *a).unwrap_or(0);
let hash = **hash_r;
let payment = self.payments.get(&hash);
let (incoming_sat, outgoing_sat) = if let Some(p) = payment {
p.updated_incoming_outgoing(
channel_id,
incoming_for_chan_sat,
outgoing_for_chan_sat,
)
} else {
(incoming_for_chan_sat, outgoing_for_chan_sat)
};
let invoiced_amount = self.invoices.get(&hash).map(|i| i.amount_msat);
if validator
.validate_payment_balance(incoming_sat * 1000, outgoing_sat * 1000, invoiced_amount)
.is_err()
{
unbalanced.push(hash);
}
}
if !unbalanced.is_empty() {
policy_err!(
validator,
"policy-commitment-htlc-routing-balance",
"unbalanced payments on channel {}: {:?}",
channel_id,
unbalanced.into_iter().map(|h| h.0.to_hex()).collect::<Vec<_>>()
);
}
if validator.enforce_balance() {
info!(
"{} validate payments adjust excess {} +{} -{}",
self.log_prefix, self.excess_amount, balance_delta.1, balance_delta.0
);
self.excess_amount
.checked_add(balance_delta.1)
.expect("overflow")
.checked_sub(balance_delta.0)
.ok_or_else(|| {
policy_error(format!(
"shortfall {} + {} - {}",
self.excess_amount, balance_delta.1, balance_delta.0
))
})?;
}
Ok(())
}
pub fn apply_payments(
&mut self,
channel_id: &ChannelId,
incoming_payment_summary: &Map<PaymentHash, u64>,
outgoing_payment_summary: &Map<PaymentHash, u64>,
balance_delta: &BalanceDelta,
validator: Arc<dyn Validator>,
) {
debug!("applying payments on channel {}", channel_id);
let mut hashes: UnorderedSet<&PaymentHash> = UnorderedSet::new();
hashes.extend(incoming_payment_summary.keys());
hashes.extend(outgoing_payment_summary.keys());
let mut fulfilled_issued_invoices = Vec::new();
for hash_r in hashes.iter() {
let hash = **hash_r;
let payment = self.payments.entry(hash).or_insert_with(|| RoutedPayment::new());
if let Some(issued) = self.issued_invoices.get(&hash) {
if !payment.is_fulfilled() {
let incoming_for_chan_sat =
incoming_payment_summary.get(hash_r).map(|a| *a).unwrap_or(0);
let outgoing_for_chan_sat =
outgoing_payment_summary.get(hash_r).map(|a| *a).unwrap_or(0);
let (incoming_sat, outgoing_sat) = payment.updated_incoming_outgoing(
channel_id,
incoming_for_chan_sat,
outgoing_for_chan_sat,
);
if incoming_sat >= outgoing_sat + issued.amount_msat / 1000 {
fulfilled_issued_invoices.push(hash);
}
}
}
}
if validator.enforce_balance() {
info!(
"{} apply payments adjust excess {} +{} -{}",
self.log_prefix, self.excess_amount, balance_delta.1, balance_delta.0
);
let excess_amount = self
.excess_amount
.checked_add(balance_delta.1)
.expect("overflow")
.checked_sub(balance_delta.0)
.expect("validation didn't catch underflow");
for hash in fulfilled_issued_invoices.iter() {
debug!("mark issued invoice {} as fulfilled", hash.0.to_hex());
let payment = self.payments.get_mut(&hash).expect("already checked");
payment.preimage = Some(PaymentPreimage([0; 32]));
}
self.excess_amount = excess_amount;
}
debug!(
"applying incoming payments from channel {} - {:?}",
channel_id, incoming_payment_summary
);
for hash in hashes.iter() {
let incoming_sat = incoming_payment_summary.get(hash).map(|a| *a).unwrap_or(0);
let outgoing_sat = outgoing_payment_summary.get(hash).map(|a| *a).unwrap_or(0);
let payment = self.payments.get_mut(hash).expect("created above");
payment.apply(channel_id, incoming_sat, outgoing_sat);
}
}
pub fn htlc_fulfilled(
&mut self,
channel_id: &ChannelId,
preimage: PaymentPreimage,
validator: Arc<dyn Validator>,
) {
let payment_hash = PaymentHash(Sha256Hash::hash(&preimage.0).into_inner());
if let Some(payment) = self.payments.get_mut(&payment_hash) {
if payment.preimage.is_some() {
info!(
"{} duplicate preimage {} on channel {}",
self.log_prefix,
payment_hash.0.to_hex(),
channel_id
);
} else {
let (incoming, outgoing) = payment.incoming_outgoing();
if self.invoices.contains_key(&payment_hash) {
if incoming > 0 {
info!(
"{} preimage invoice+routing {} +{} -{} msat",
self.log_prefix,
payment_hash.0.to_hex(),
incoming,
outgoing
)
} else {
info!(
"{} preimage invoice {} -{} msat",
self.log_prefix,
payment_hash.0.to_hex(),
outgoing
)
}
} else {
info!(
"{} preimage routing {} adjust excess {} +{} -{} msat",
self.log_prefix,
payment_hash.0.to_hex(),
self.excess_amount,
incoming,
outgoing
);
if validator.enforce_balance() {
self.excess_amount =
self.excess_amount.checked_add(incoming).expect("overflow");
self.excess_amount =
self.excess_amount.checked_sub(outgoing).expect("underflow");
}
}
payment.preimage = Some(preimage);
}
}
}
fn prune_issued_invoices(&mut self, now: Duration) {
self.issued_invoices.retain(|_, issued| {
issued.duration_since_epoch + issued.expiry_duration + INVOICE_PRUNE_TIME > now
});
}
fn prune_invoices(&mut self, now: Duration) {
let invoices = &mut self.invoices;
let payments = &mut self.payments;
let prune: UnorderedSet<_> = invoices
.iter_mut()
.filter_map(|(hash, payment_state)| {
let payments = payments.get(hash).expect("missing payments struct for invoice");
if Self::is_invoice_prunable(now, hash, payment_state, payments) {
Some(*hash)
} else {
None
}
})
.collect();
invoices.retain(|hash, _| !prune.contains(hash));
payments.retain(|hash, _| !prune.contains(hash));
}
fn is_invoice_prunable(
now: Duration,
hash: &PaymentHash,
state: &PaymentState,
payment: &RoutedPayment,
) -> bool {
let is_payment_complete = payment.is_fulfilled() || payment.is_no_outgoing();
let is_past_prune_time =
now > state.duration_since_epoch + state.expiry_duration + INVOICE_PRUNE_TIME;
if is_past_prune_time && !is_payment_complete {
warn!(
"invoice {:?} is past prune time but there are still pending outgoing payments",
hash
);
}
is_past_prune_time && is_payment_complete
}
}
#[derive(Eq, PartialEq, Hash, Clone)]
pub enum Allowable {
Script(Script),
XPub(ExtendedPubKey),
Payee(PublicKey),
}
pub trait ToStringForNetwork {
fn to_string(&self, network: Network) -> String;
}
impl ToStringForNetwork for Allowable {
fn to_string(&self, network: Network) -> String {
match self {
Allowable::Script(script) => {
let addr_res = Address::from_script(&script, network);
addr_res
.map(|a| format!("address:{}", a.to_string()))
.unwrap_or_else(|_| format!("invalid_script:{}", script.to_hex()))
}
Allowable::Payee(pubkey) => format!("payee:{}", pubkey.to_hex()),
Allowable::XPub(xpub) => {
format!("xpub:{}", xpub.to_string())
}
}
}
}
impl Allowable {
pub fn from_str(s: &str, network: Network) -> Result<Allowable, String> {
let mut splits = s.splitn(2, ":");
let prefix = splits.next().expect("failed to parse Allowable");
if let Some(body) = splits.next() {
if prefix == "address" {
let address = Address::from_str(body).map_err(|_| s.to_string())?;
if address.network != network {
return Err(format!("{}: expected network {}", s, network));
}
Ok(Allowable::Script(address.script_pubkey()))
} else if prefix == "payee" {
let pubkey = PublicKey::from_str(body).map_err(|_| s.to_string())?;
Ok(Allowable::Payee(pubkey))
} else if prefix == "xpub" {
let xpub = ExtendedPubKey::from_str(body).map_err(|_| s.to_string())?;
if xpub.network != network {
return Err(format!("{}: expected network {}", s, network));
}
Ok(Allowable::XPub(xpub))
} else {
Err(s.to_string())
}
} else {
let address = Address::from_str(prefix).map_err(|_| s.to_string())?;
if address.network != network {
return Err(format!("{}: expected network {}", s, network));
}
Ok(Allowable::Script(address.script_pubkey()))
}
}
pub fn to_script(self) -> Result<Script, ()> {
match self {
Allowable::Script(script) => Ok(script),
_ => Err(()),
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Heartbeat {
pub chain_tip: bitcoin::BlockHash,
pub chain_height: u32,
pub chain_timestamp: u32,
pub current_timestamp: u32,
}
impl Heartbeat {
pub fn encode(&self) -> Vec<u8> {
to_vec(&self).expect("serialize Heartbeat")
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SignedHeartbeat {
pub signature: Vec<u8>,
pub heartbeat: Heartbeat,
}
impl SignedHeartbeat {
pub fn sighash(&self) -> Message {
sighash_from_heartbeat(&self.heartbeat.encode())
}
pub fn verify(&self, pubkey: &PublicKey, secp: &Secp256k1<All>) -> bool {
let signature = schnorr::Signature::from_slice(&self.signature).unwrap();
let xpubkey = bitcoin::XOnlyPublicKey::from(pubkey.clone());
secp.verify_schnorr(&signature, &self.sighash(), &xpubkey).is_ok()
}
}
pub struct Node {
pub(crate) node_config: NodeConfig,
pub(crate) keys_manager: MyKeysManager,
channels: Mutex<OrderedMap<ChannelId, Arc<Mutex<ChannelSlot>>>>,
pub(crate) validator_factory: Mutex<Arc<dyn ValidatorFactory>>,
pub(crate) persister: Arc<dyn Persist>,
pub(crate) clock: Arc<dyn Clock>,
allowlist: Mutex<UnorderedSet<Allowable>>,
tracker: Mutex<ChainTracker<ChainMonitor>>,
pub(crate) state: Mutex<NodeState>,
node_id: PublicKey,
}
#[derive(Clone)]
pub struct NodeServices {
pub validator_factory: Arc<dyn ValidatorFactory>,
pub starting_time_factory: Arc<dyn StartingTimeFactory>,
pub persister: Arc<dyn Persist>,
pub clock: Arc<dyn Clock>,
}
impl Wallet for Node {
fn can_spend(&self, child_path: &[u32], script_pubkey: &Script) -> Result<bool, Status> {
if child_path.len() == 0 {
return Ok(false);
}
let secp_ctx = Secp256k1::signing_only();
let pubkey = self.get_wallet_pubkey(&secp_ctx, child_path)?;
let native_addr = Address::p2wpkh(&pubkey, self.network()).expect("p2wpkh failed");
let wrapped_addr = Address::p2shwpkh(&pubkey, self.network()).expect("p2shwpkh failed");
Ok(*script_pubkey == native_addr.script_pubkey()
|| *script_pubkey == wrapped_addr.script_pubkey())
}
fn get_native_address(&self, child_path: &[u32]) -> Result<Address, Status> {
if child_path.len() == 0 {
return Err(invalid_argument("empty child path"));
}
let secp_ctx = Secp256k1::signing_only();
let pubkey = self.get_wallet_pubkey(&secp_ctx, child_path)?;
Ok(Address::p2wpkh(&pubkey, self.network()).expect("p2wpkh failed"))
}
fn get_wrapped_address(&self, child_path: &[u32]) -> Result<Address, Status> {
if child_path.len() == 0 {
return Err(invalid_argument("empty child path"));
}
let secp_ctx = Secp256k1::signing_only();
let pubkey = self.get_wallet_pubkey(&secp_ctx, child_path)?;
Ok(Address::p2shwpkh(&pubkey, self.network()).expect("p2shwpkh failed"))
}
fn allowlist_contains_payee(&self, payee: PublicKey) -> bool {
self.allowlist.lock().unwrap().contains(&Allowable::Payee(payee.clone()))
}
fn allowlist_contains(&self, script_pubkey: &Script, path: &[u32]) -> bool {
if self.allowlist.lock().unwrap().contains(&Allowable::Script(script_pubkey.clone())) {
return true;
}
if path.len() == 0 {
return false;
}
let child_path: Vec<_> =
path.iter().map(|i| ChildNumber::from_normal_idx(*i).unwrap()).collect();
for a in self.allowlist.lock().unwrap().iter() {
if let Allowable::XPub(xp) = a {
let pubkey = bitcoin::PublicKey::new(
xp.derive_pub(&Secp256k1::new(), &child_path).unwrap().public_key,
);
if *script_pubkey
== Address::p2wpkh(&pubkey, self.network()).unwrap().script_pubkey()
{
return true;
}
if *script_pubkey == Address::p2pkh(&pubkey, self.network()).script_pubkey() {
return true;
}
}
}
return false;
}
fn network(&self) -> Network {
self.node_config.network
}
}
impl Node {
pub fn new(
node_config: NodeConfig,
seed: &[u8],
allowlist: Vec<Allowable>,
services: NodeServices,
) -> Node {
let policy = services.validator_factory.policy(node_config.network);
let global_velocity_control = Self::make_velocity_control(&policy);
let fee_velocity_control = Self::make_fee_velocity_control(&policy);
let state = NodeState::new(global_velocity_control, fee_velocity_control);
let (keys_manager, node_id) = Self::make_keys_manager(node_config, seed, &services);
let tracker = if node_config.use_checkpoints {
ChainTracker::for_network(
node_config.network,
node_id.clone(),
services.validator_factory.clone(),
)
} else {
ChainTracker::from_genesis(
node_config.network,
node_id.clone(),
services.validator_factory.clone(),
)
};
Self::new_full(node_config, allowlist, services, state, keys_manager, node_id, tracker)
}
pub(crate) fn get_node_secret(&self) -> SecretKey {
self.keys_manager.get_node_secret()
}
pub fn get_entropy_source(&self) -> &dyn EntropySource {
&self.keys_manager
}
pub fn new_from_persistence(
node_config: NodeConfig,
seed: &[u8],
allowlist: Vec<Allowable>,
services: NodeServices,
state: NodeState,
) -> Node {
let (keys_manager, node_id) = Self::make_keys_manager(node_config, seed, &services);
let tracker = services
.persister
.get_tracker(node_id.clone(), services.validator_factory.clone())
.expect("get tracker from persister");
Self::new_full(node_config, allowlist, services, state, keys_manager, node_id, tracker)
}
fn new_full(
node_config: NodeConfig,
allowlist: Vec<Allowable>,
services: NodeServices,
state: NodeState,
keys_manager: MyKeysManager,
node_id: PublicKey,
tracker: ChainTracker<ChainMonitor>,
) -> Node {
let log_prefix = &node_id.to_hex()[0..4];
let persister = services.persister;
let clock = services.clock;
let validator_factory = services.validator_factory;
let policy = validator_factory.policy(node_config.network);
let global_velocity_control = Self::make_velocity_control(&policy);
let fee_velocity_control = Self::make_fee_velocity_control(&policy);
let state = Mutex::new(state.with_log_prefix(
global_velocity_control,
fee_velocity_control,
log_prefix.to_string(),
));
Node {
keys_manager,
node_config,
channels: Mutex::new(OrderedMap::new()),
validator_factory: Mutex::new(validator_factory),
persister,
clock,
allowlist: Mutex::new(UnorderedSet::from_iter(allowlist)),
tracker: Mutex::new(tracker),
state,
node_id,
}
}
pub fn make_keys_manager(
node_config: NodeConfig,
seed: &[u8],
services: &NodeServices,
) -> (MyKeysManager, PublicKey) {
let keys_manager = MyKeysManager::new(
node_config.key_derivation_style,
seed,
node_config.network,
services.starting_time_factory.borrow(),
);
let node_id = keys_manager.get_node_id(Recipient::Node).unwrap();
(keys_manager, node_id)
}
pub fn get_persister(&self) -> Arc<dyn Persist> {
Arc::clone(&self.persister)
}
pub fn get_onion_reply_secret(&self) -> [u8; 32] {
self.keys_manager.get_onion_reply_secret()
}
pub fn get_bolt12_pubkey(&self) -> PublicKey {
self.keys_manager.get_bolt12_pubkey()
}
pub fn get_persistence_pubkey(&self) -> PublicKey {
self.keys_manager.get_persistence_pubkey()
}
pub fn get_persistence_shared_secret(&self, server_pubkey: &PublicKey) -> [u8; 32] {
self.keys_manager.get_persistence_shared_secret(server_pubkey)
}
pub fn get_persistence_auth_token(&self, server_pubkey: &PublicKey) -> [u8; 32] {
self.keys_manager.get_persistence_auth_token(server_pubkey)
}
pub fn sign_bolt12(
&self,
messagename: &[u8],
fieldname: &[u8],
merkleroot: &[u8; 32],
publictweak_opt: Option<&[u8]>,
) -> Result<schnorr::Signature, Status> {
self.keys_manager
.sign_bolt12(messagename, fieldname, merkleroot, publictweak_opt)
.map_err(|_| internal_error("signature operation failed"))
}
pub fn derive_secret(&self, info: &[u8]) -> SecretKey {
self.keys_manager.derive_secret(info)
}
pub fn set_validator_factory(&self, validator_factory: Arc<dyn ValidatorFactory>) {
let mut vfac = self.validator_factory.lock().unwrap();
*vfac = validator_factory;
}
pub fn get_id(&self) -> PublicKey {
self.node_id
}
pub fn log_prefix(&self) -> String {
self.get_id().to_hex()[0..4].to_string()
}
pub fn get_state(&self) -> MutexGuard<NodeState> {
self.state.lock().unwrap()
}
#[allow(dead_code)]
pub(crate) fn get_secure_random_bytes(&self) -> [u8; 32] {
self.keys_manager.get_secure_random_bytes()
}
pub fn get_inbound_payment_key_material(&self) -> KeyMaterial {
self.keys_manager.get_inbound_payment_key_material()
}
pub fn get_channel(&self, channel_id: &ChannelId) -> Result<Arc<Mutex<ChannelSlot>>, Status> {
let mut guard = self.channels();
let elem = guard.get_mut(channel_id);
let slot_arc =
elem.ok_or_else(|| invalid_argument(format!("no such channel: {}", &channel_id)))?;
Ok(Arc::clone(slot_arc))
}
pub fn with_channel_base<F: Sized, T>(&self, channel_id: &ChannelId, f: F) -> Result<T, Status>
where
F: Fn(&mut ChannelBase) -> Result<T, Status>,
{
let slot_arc = self.get_channel(channel_id)?;
let mut slot = slot_arc.lock().unwrap();
let base = match &mut *slot {
ChannelSlot::Stub(stub) => stub as &mut ChannelBase,
ChannelSlot::Ready(chan) => chan as &mut ChannelBase,
};
f(base)
}
pub fn with_ready_channel<F: Sized, T>(&self, channel_id: &ChannelId, f: F) -> Result<T, Status>
where
F: Fn(&mut Channel) -> Result<T, Status>,
{
let slot_arc = self.get_channel(channel_id)?;
let mut slot = slot_arc.lock().unwrap();
match &mut *slot {
ChannelSlot::Stub(_) =>
Err(invalid_argument(format!("channel not ready: {}", &channel_id))),
ChannelSlot::Ready(chan) => f(chan),
}
}
pub fn find_channel_with_funding_outpoint(
&self,
outpoint: &OutPoint,
) -> Option<Arc<Mutex<ChannelSlot>>> {
let channels_lock = self.channels.lock().unwrap();
find_channel_with_funding_outpoint(&channels_lock, outpoint)
}
pub fn new_channel(
&self,
opt_channel_id: Option<ChannelId>,
arc_self: &Arc<Node>,
) -> Result<(ChannelId, Option<ChannelSlot>), Status> {
let channel_id = opt_channel_id.unwrap_or_else(|| self.keys_manager.get_channel_id());
let mut channels = self.channels.lock().unwrap();
let policy = self.policy();
if channels.len() >= policy.max_channels() {
return Err(failed_precondition(format!(
"too many channels ({} >= {})",
channels.len(),
policy.max_channels()
)));
}
let maybe_slot = channels.get(&channel_id);
if let Some(slot) = maybe_slot {
let slot = slot.lock().unwrap().clone();
return Ok((channel_id, Some(slot)));
}
let channel_value_sat = 0; let keys =
self.keys_manager.get_channel_keys_with_id(channel_id.clone(), channel_value_sat);
let stub = ChannelStub {
node: Arc::downgrade(arc_self),
secp_ctx: Secp256k1::new(),
keys,
id0: channel_id.clone(),
};
channels.insert(channel_id.clone(), Arc::new(Mutex::new(ChannelSlot::Stub(stub.clone()))));
self.persister
.new_channel(&self.get_id(), &stub)
.expect("channel was in storage but not in memory");
Ok((channel_id.clone(), Some(ChannelSlot::Stub(stub))))
}
pub(crate) fn restore_channel(
&self,
channel_id0: ChannelId,
channel_id: Option<ChannelId>,
channel_value_sat: u64,
channel_setup: Option<ChannelSetup>,
enforcement_state: EnforcementState,
arc_self: &Arc<Node>,
) -> Result<Arc<Mutex<ChannelSlot>>, ()> {
let mut channels = self.channels.lock().unwrap();
assert!(!channels.contains_key(&channel_id0));
let mut keys =
self.keys_manager.get_channel_keys_with_id(channel_id0.clone(), channel_value_sat);
let slot = match channel_setup {
None => {
let stub = ChannelStub {
node: Arc::downgrade(arc_self),
secp_ctx: Secp256k1::new(),
keys,
id0: channel_id0.clone(),
};
let slot = Arc::new(Mutex::new(ChannelSlot::Stub(stub.clone())));
channels.insert(channel_id0, Arc::clone(&slot));
channel_id.map(|id| channels.insert(id, Arc::clone(&slot)));
slot
}
Some(setup) => {
let channel_transaction_parameters =
Node::channel_setup_to_channel_transaction_parameters(&setup, keys.pubkeys());
keys.provide_channel_parameters(&channel_transaction_parameters);
let funding_outpoint = setup.funding_outpoint;
let monitor = arc_self
.get_tracker()
.listeners
.get_key_value(&ChainMonitor::new(funding_outpoint, 0))
.expect("monitor key")
.0
.clone();
let channel = Channel {
node: Arc::downgrade(arc_self),
secp_ctx: Secp256k1::new(),
keys,
enforcement_state,
setup,
id0: channel_id0.clone(),
id: channel_id.clone(),
monitor,
};
let slot = Arc::new(Mutex::new(ChannelSlot::Ready(channel.clone())));
channels.insert(channel_id0, Arc::clone(&slot));
channel_id.map(|id| channels.insert(id, Arc::clone(&slot)));
slot
}
};
self.keys_manager.increment_channel_id_child_index();
Ok(slot)
}
pub fn restore_node(
node_id: &PublicKey,
node_entry: NodeEntry,
seed: &[u8],
services: NodeServices,
) -> Arc<Node> {
let network = Network::from_str(node_entry.network.as_str()).expect("bad network");
let config = NodeConfig {
network,
key_derivation_style: KeyDerivationStyle::try_from(node_entry.key_derivation_style)
.unwrap(),
use_checkpoints: true,
};
let persister = services.persister.clone();
let allowlist = persister
.get_node_allowlist(node_id)
.expect("node allowlist")
.iter()
.map(|e| Allowable::from_str(e, network))
.collect::<Result<_, _>>()
.expect("allowable parse error");
let policy = services.validator_factory.policy(network);
let global_velocity_control = Self::make_velocity_control(&policy);
let fee_velocity_control = Self::make_fee_velocity_control(&policy);
let state = NodeState::new(global_velocity_control, fee_velocity_control);
let node = Arc::new(Node::new_from_persistence(config, seed, allowlist, services, state));
assert_eq!(&node.get_id(), node_id);
info!("Restore node {} on {}", node_id, config.network);
for (channel_id0, channel_entry) in
persister.get_node_channels(node_id).expect("node channels")
{
info!(" Restore channel {}", channel_id0);
node.restore_channel(
channel_id0,
channel_entry.id,
channel_entry.channel_value_satoshis,
channel_entry.channel_setup,
channel_entry.enforcement_state,
&node,
)
.expect("restore channel");
}
if let Some((height, _hash, filter_header, header)) = get_latest_checkpoint(network) {
let mut tracker = node.get_tracker();
if tracker.height() == 0 {
tracker.headers = VecDeque::new();
tracker.tip = Headers(header, filter_header);
tracker.height = height;
}
}
node
}
pub fn restore_nodes(
services: NodeServices,
seed_persister: Arc<dyn SeedPersist>,
) -> Map<PublicKey, Arc<Node>> {
let mut nodes = Map::new();
let persister = services.persister.clone();
let mut seeds = OrderedSet::from_iter(seed_persister.list().into_iter());
for (node_id, node_entry) in persister.get_nodes().expect("nodes") {
let seed = seed_persister
.get(&node_id.serialize().to_hex())
.expect(format!("no seed for node {:?}", node_id).as_str());
let node = Node::restore_node(&node_id, node_entry, &seed, services.clone());
nodes.insert(node_id, node);
seeds.remove(&node_id.serialize().to_hex());
}
if !seeds.is_empty() {
warn!("some seeds had no persisted node state: {:?}", seeds);
}
nodes
}
pub fn ready_channel(
&self,
channel_id0: ChannelId,
opt_channel_id: Option<ChannelId>,
setup: ChannelSetup,
holder_shutdown_key_path: &[u32],
) -> Result<Channel, Status> {
let mut tracker = self.tracker.lock().unwrap();
let validator = self.validator_factory.lock().unwrap().make_validator(
self.network(),
self.get_id(),
Some(channel_id0.clone()),
);
let chan = {
let channels = self.channels.lock().unwrap();
let arcobj = channels.get(&channel_id0).ok_or_else(|| {
invalid_argument(format!("channel does not exist: {}", channel_id0))
})?;
let slot = arcobj.lock().unwrap();
let stub: &ChannelStub = match &*slot {
ChannelSlot::Stub(stub) => stub,
ChannelSlot::Ready(c) => {
if c.setup != setup {
return Err(invalid_argument(format!(
"channel already ready with different setup: {}",
channel_id0
)));
}
return Ok(c.clone());
}
};
let mut keys = stub.channel_keys_with_channel_value(setup.channel_value_sat);
let holder_pubkeys = keys.pubkeys();
let channel_transaction_parameters =
Node::channel_setup_to_channel_transaction_parameters(&setup, holder_pubkeys);
keys.provide_channel_parameters(&channel_transaction_parameters);
let funding_outpoint = setup.funding_outpoint;
let monitor = ChainMonitor::new(funding_outpoint, tracker.height());
monitor.add_funding_outpoint(&funding_outpoint);
let to_holder_msat = if setup.is_outbound {
(setup.channel_value_sat * 1000).checked_sub(setup.push_value_msat).ok_or_else(
|| {
policy_error(format!(
"beneficial channel value underflow: {} - {}",
setup.channel_value_sat * 1000,
setup.push_value_msat
))
},
)?
} else {
setup.push_value_msat
};
let initial_holder_value_sat = validator.minimum_initial_balance(to_holder_msat);
let enforcement_state = EnforcementState::new(initial_holder_value_sat);
Channel {
node: Weak::clone(&stub.node),
secp_ctx: stub.secp_ctx.clone(),
keys,
enforcement_state,
setup: setup.clone(),
id0: channel_id0.clone(),
id: opt_channel_id.clone(),
monitor,
}
};
validator.validate_ready_channel(self, &setup, holder_shutdown_key_path)?;
let mut channels = self.channels.lock().unwrap();
let chan_arc = Arc::new(Mutex::new(ChannelSlot::Ready(chan.clone())));
let chan_id = opt_channel_id.unwrap_or(channel_id0.clone());
channels.insert(chan_id.clone(), chan_arc.clone());
if channel_id0 != chan_id {
channels.insert(channel_id0, chan_arc.clone());
}
tracker.add_listener(
chan.monitor.clone(),
OrderedSet::from_iter(vec![setup.funding_outpoint.txid]),
);
debug_vals!(&chan.setup);
trace_enforcement_state!(&chan);
self.persister
.update_tracker(&self.get_id(), &tracker)
.map_err(|_| internal_error("tracker persist failed"))?;
self.persister
.update_channel(&self.get_id(), &chan)
.map_err(|_| internal_error("persist failed"))?;
Ok(chan)
}
pub fn get_heartbeat(&self) -> SignedHeartbeat {
let mut state = self.get_state();
let now = self.clock.now();
state.prune_invoices(now);
state.prune_issued_invoices(now);
drop(state); let tracker = self.tracker.lock().unwrap();
let tip = tracker.tip();
let current_timestamp = self.clock.now().as_secs() as u32;
let heartbeat = Heartbeat {
chain_tip: tip.0.block_hash(),
chain_height: tracker.height(),
chain_timestamp: tip.0.time,
current_timestamp,
};
let ser_heartbeat = heartbeat.encode();
let sig = self.keys_manager.sign_heartbeat(&ser_heartbeat);
SignedHeartbeat { signature: sig[..].to_vec(), heartbeat }
}
#[cfg(any(test, feature = "test_utils"))]
pub(crate) fn check_and_sign_onchain_tx(
&self,
tx: &Transaction,
input_txs: &[&Transaction],
ipaths: &[Vec<u32>],
values_sat: &[u64],
spendtypes: &[SpendType],
uniclosekeys: Vec<Option<(SecretKey, Vec<Vec<u8>>)>>,
opaths: &[Vec<u32>],
) -> Result<Vec<Vec<Vec<u8>>>, Status> {
self.check_onchain_tx(tx, input_txs, values_sat, spendtypes, &uniclosekeys, opaths)?;
self.unchecked_sign_onchain_tx(tx, ipaths, values_sat, spendtypes, uniclosekeys)
}
pub fn unchecked_sign_onchain_tx(
&self,
tx: &Transaction,
ipaths: &[Vec<u32>],
values_sat: &[u64],
spendtypes: &[SpendType],
uniclosekeys: Vec<Option<(SecretKey, Vec<Vec<u8>>)>>,
) -> Result<Vec<Vec<Vec<u8>>>, Status> {
let channels_lock = self.channels.lock().unwrap();
let secp_ctx = Secp256k1::signing_only();
let txid = tx.txid();
debug!("{}: txid: {}", short_function!(), txid);
let channels: Vec<Option<Arc<Mutex<ChannelSlot>>>> = (0..tx.output.len())
.map(|ndx| {
let outpoint = OutPoint { txid, vout: ndx as u32 };
find_channel_with_funding_outpoint(&channels_lock, &outpoint)
})
.collect();
let mut witvec: Vec<Vec<Vec<u8>>> = Vec::new();
for (idx, uck) in uniclosekeys.into_iter().enumerate() {
if spendtypes[idx] == SpendType::Invalid {
witvec.push(vec![]);
} else {
let value_sat = values_sat[idx];
let (privkey, mut witness) = match uck {
Some((key, stack)) =>
(bitcoin::PrivateKey::new(key.clone(), Network::Testnet), stack),
None => {
let key = self.get_wallet_privkey(&secp_ctx, &ipaths[idx])?;
let redeemscript =
PublicKey::from_secret_key(&secp_ctx, &key.inner).serialize().to_vec();
(key, vec![redeemscript])
}
};
let pubkey = privkey.public_key(&secp_ctx);
let script_code = Address::p2pkh(&pubkey, privkey.network).script_pubkey();
let sighash = match spendtypes[idx] {
SpendType::P2pkh => {
let sighash = tx.signature_hash(0, &script_code, 0x01);
Ok(sighash)
}
SpendType::P2wpkh | SpendType::P2shP2wpkh => {
let sighash = SighashCache::new(tx)
.segwit_signature_hash(
idx,
&script_code,
value_sat,
EcdsaSighashType::All,
)
.unwrap();
Ok(sighash)
}
SpendType::P2wsh => {
let sighash = SighashCache::new(tx)
.segwit_signature_hash(
idx,
&Script::from(witness[witness.len() - 1].clone()),
value_sat,
EcdsaSighashType::All,
)
.unwrap();
Ok(sighash)
}
st => Err(invalid_argument(format!("unsupported spend_type={:?}", st))),
}?;
let message = Message::from_slice(&sighash).map_err(|err| {
internal_error(format!("sighash {:?} failed: {}", spendtypes[idx], err))
})?;
let sig = secp_ctx.sign_ecdsa(&message, &privkey.inner);
let sigvec = signature_to_bitcoin_vec(sig);
witness.insert(0, sigvec);
witvec.push(witness);
}
}
let mut tracker = self.tracker.lock().unwrap();
for (vout, slot_opt) in channels.iter().enumerate() {
if let Some(slot_mutex) = slot_opt {
let slot = slot_mutex.lock().unwrap();
match &*slot {
ChannelSlot::Stub(_) => panic!("this can't happen"),
ChannelSlot::Ready(chan) => {
let inputs =
OrderedSet::from_iter(tx.input.iter().map(|i| i.previous_output));
tracker.add_listener_watches(chan.monitor.clone(), inputs);
chan.funding_signed(tx, vout as u32)
}
}
}
}
self.persister
.update_tracker(&self.get_id(), &tracker)
.map_err(|_| internal_error("tracker persist failed"))?;
Ok(witvec)
}
pub fn check_onchain_tx(
&self,
tx: &Transaction,
input_txs: &[&Transaction],
values_sat: &[u64],
spendtypes: &[SpendType],
uniclosekeys: &[Option<(SecretKey, Vec<Vec<u8>>)>],
opaths: &[Vec<u32>],
) -> Result<(), ValidationError> {
let channels_lock = self.channels.lock().unwrap();
let txid = tx.txid();
debug!("{}: txid: {}", short_function!(), txid);
let channels: Vec<Option<Arc<Mutex<ChannelSlot>>>> = (0..tx.output.len())
.map(|ndx| {
let outpoint = OutPoint { txid, vout: ndx as u32 };
find_channel_with_funding_outpoint(&channels_lock, &outpoint)
})
.collect();
let validator = self.validator();
let mut weight_lower_bound = tx.weight();
for (idx, uck) in uniclosekeys.iter().enumerate() {
if spendtypes[idx] == SpendType::Invalid {
weight_lower_bound += 0;
} else {
let wit_len = match uck {
Some((_key, stack)) => stack.iter().map(|v| 1 + v.len()).sum(),
None => 33,
};
weight_lower_bound += 2 + 1 + 1 + 72 + 1 + wit_len;
}
}
debug!("weight_lower_bound: {}", weight_lower_bound);
let non_beneficial_sat = validator.validate_onchain_tx(
self,
channels,
tx,
input_txs,
values_sat,
opaths,
weight_lower_bound,
)?;
drop(channels_lock);
let validator = self.validator();
let mut state = self.state.lock().unwrap();
let now = self.clock.now().as_secs();
if !state.fee_velocity_control.insert(now, non_beneficial_sat * 1000) {
policy_err!(
validator,
"policy-onchain-fee-range",
"fee velocity would be exceeded {} + {} > {}",
state.fee_velocity_control.velocity(),
non_beneficial_sat * 1000,
state.fee_velocity_control.limit
);
}
Ok(())
}
fn validator(&self) -> Arc<dyn Validator> {
self.validator_factory.lock().unwrap().make_validator(self.network(), self.get_id(), None)
}
fn channel_setup_to_channel_transaction_parameters(
setup: &ChannelSetup,
holder_pubkeys: &ChannelPublicKeys,
) -> ChannelTransactionParameters {
let funding_outpoint = Some(chain::transaction::OutPoint {
txid: setup.funding_outpoint.txid,
index: setup.funding_outpoint.vout as u16,
});
let opt_non_zero_fee_anchors = if setup.is_zero_fee_htlc() { Some(()) } else { None };
let channel_transaction_parameters = ChannelTransactionParameters {
holder_pubkeys: holder_pubkeys.clone(),
holder_selected_contest_delay: setup.holder_selected_contest_delay,
is_outbound_from_holder: setup.is_outbound,
counterparty_parameters: Some(CounterpartyChannelTransactionParameters {
pubkeys: setup.counterparty_points.clone(),
selected_contest_delay: setup.counterparty_selected_contest_delay,
}),
funding_outpoint,
opt_anchors: if setup.is_anchors() { Some(()) } else { None },
opt_non_zero_fee_anchors,
};
channel_transaction_parameters
}
pub(crate) fn get_wallet_privkey(
&self,
secp_ctx: &Secp256k1<secp256k1::SignOnly>,
child_path: &[u32],
) -> Result<PrivateKey, Status> {
if child_path.len() != self.node_config.key_derivation_style.get_key_path_len() {
return Err(invalid_argument(format!(
"get_wallet_key: bad child_path len : {}",
child_path.len()
)));
}
let mut xkey = self.get_account_extended_key().clone();
for elem in child_path {
xkey = xkey
.ckd_priv(&secp_ctx, ChildNumber::from_normal_idx(*elem).unwrap())
.map_err(|err| internal_error(format!("derive child_path failed: {}", err)))?;
}
Ok(PrivateKey::new(xkey.private_key, self.network()))
}
pub(crate) fn get_wallet_pubkey(
&self,
secp_ctx: &Secp256k1<secp256k1::SignOnly>,
child_path: &[u32],
) -> Result<bitcoin::PublicKey, Status> {
Ok(self.get_wallet_privkey(secp_ctx, child_path)?.public_key(secp_ctx))
}
pub fn check_wallet_pubkey(
&self,
child_path: &[u32],
pubkey: bitcoin::PublicKey,
) -> Result<bool, Status> {
let secp_ctx = Secp256k1::signing_only();
Ok(self.get_wallet_pubkey(&secp_ctx, child_path)? == pubkey)
}
pub fn get_ldk_shutdown_scriptpubkey(&self) -> ShutdownScript {
self.keys_manager.get_shutdown_scriptpubkey()
}
pub fn get_account_extended_key(&self) -> &ExtendedPrivKey {
self.keys_manager.get_account_extended_key()
}
pub fn get_account_extended_pubkey(&self) -> ExtendedPubKey {
let secp_ctx = Secp256k1::signing_only();
ExtendedPubKey::from_priv(&secp_ctx, &self.get_account_extended_key())
}
pub fn sign_node_announcement(&self, na: &[u8]) -> Result<Signature, Status> {
self.do_sign_gossip_message(na)
}
pub fn sign_channel_update(&self, cu: &[u8]) -> Result<Signature, Status> {
self.do_sign_gossip_message(cu)
}
pub fn sign_gossip_message(&self, msg: &UnsignedGossipMessage) -> Result<Signature, Status> {
let encoded = &msg.encode()[..];
self.do_sign_gossip_message(encoded)
}
fn do_sign_gossip_message(&self, encoded: &[u8]) -> Result<Signature, Status> {
let secp_ctx = Secp256k1::signing_only();
let msg_hash = Sha256dHash::hash(encoded);
let encmsg = Message::from_slice(&msg_hash[..])
.map_err(|err| internal_error(format!("encmsg failed: {}", err)))?;
let sig = secp_ctx.sign_ecdsa(&encmsg, &self.get_node_secret());
Ok(sig)
}
pub fn sign_invoice(
&self,
hrp_bytes: &[u8],
invoice_data: &[u5],
) -> Result<RecoverableSignature, Status> {
let signed_raw_invoice = self.do_sign_invoice(hrp_bytes, invoice_data)?;
let sig = signed_raw_invoice.signature().0;
let (hash, payment_state, invoice_hash) = Self::payment_state_from_invoice(
&signed_raw_invoice.try_into().map_err(|e: Status| invalid_argument(e.to_string()))?,
)?;
info!(
"{} signing an invoice {} -> {}",
self.log_prefix(),
hash.0.to_hex(),
payment_state.amount_msat
);
let mut state = self.get_state();
let policy = self.policy();
if state.issued_invoices.len() >= policy.max_invoices() {
return Err(failed_precondition(format!(
"too many invoices {} (max {})",
state.issued_invoices.len(),
policy.max_invoices()
)));
}
if let Some(payment_state) = state.issued_invoices.get(&hash) {
return if payment_state.invoice_hash == invoice_hash {
Ok(sig)
} else {
Err(failed_precondition(
"already have a different invoice for same secret".to_string(),
))
};
}
state.issued_invoices.insert(hash, payment_state);
Ok(sig)
}
fn policy(&self) -> Box<dyn Policy> {
self.validator_factory.lock().unwrap().policy(self.network())
}
pub(crate) fn do_sign_invoice(
&self,
hrp_bytes: &[u8],
invoice_data: &[u5],
) -> Result<SignedRawInvoice, Status> {
let hrp: RawHrp = String::from_utf8(hrp_bytes.to_vec())
.map_err(|_| invalid_argument("invoice hrp not utf-8"))?
.parse()
.map_err(|e| invalid_argument(format!("parse error: {}", e)))?;
let data = RawDataPart::from_base32(invoice_data)
.map_err(|e| invalid_argument(format!("parse error: {}", e)))?;
let raw_invoice = RawInvoice { hrp, data };
let invoice_preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data);
let secp_ctx = Secp256k1::signing_only();
let hash = Sha256Hash::hash(&invoice_preimage);
let message = secp256k1::Message::from_slice(&hash).unwrap();
let sig = secp_ctx.sign_ecdsa_recoverable(&message, &self.get_node_secret());
raw_invoice
.sign::<_, ()>(|_| Ok(sig))
.map_err(|()| internal_error("failed to sign invoice"))
}
pub fn sign_message(&self, message: &[u8]) -> Result<Vec<u8>, Status> {
let mut buffer = String::from("Lightning Signed Message:").into_bytes();
buffer.extend(message);
let secp_ctx = Secp256k1::signing_only();
let hash = Sha256dHash::hash(&buffer);
let encmsg = secp256k1::Message::from_slice(&hash[..])
.map_err(|err| internal_error(format!("encmsg failed: {}", err)))?;
let sig = secp_ctx.sign_ecdsa_recoverable(&encmsg, &self.get_node_secret());
let (rid, sig) = sig.serialize_compact();
let mut res = sig.to_vec();
res.push(rid.to_i32() as u8);
Ok(res)
}
pub fn channels(&self) -> MutexGuard<OrderedMap<ChannelId, Arc<Mutex<ChannelSlot>>>> {
self.channels.lock().unwrap()
}
pub fn ecdh(&self, other_key: &PublicKey) -> Vec<u8> {
let our_key = self.keys_manager.get_node_secret();
let ss = SharedSecret::new(&other_key, &our_key);
ss.as_ref().to_vec()
}
pub fn spend_spendable_outputs(
&self,
descriptors: &[&SpendableOutputDescriptor],
outputs: Vec<TxOut>,
change_destination_script: Script,
feerate_sat_per_1000_weight: u32,
secp_ctx: &Secp256k1<All>,
) -> Result<Transaction, ()> {
self.keys_manager.spend_spendable_outputs(
descriptors,
outputs,
change_destination_script,
feerate_sat_per_1000_weight,
secp_ctx,
)
}
pub fn allowlist(&self) -> Result<Vec<String>, Status> {
let alset = self.allowlist.lock().unwrap();
(*alset)
.iter()
.map(|allowable| Ok(allowable.to_string(self.network())))
.collect::<Result<Vec<String>, Status>>()
}
pub fn allowables(&self) -> Vec<Allowable> {
self.allowlist.lock().unwrap().iter().cloned().collect()
}
pub fn add_allowlist(&self, addlist: &[String]) -> Result<(), Status> {
let allowables = addlist
.iter()
.map(|addrstr| Allowable::from_str(addrstr, self.network()))
.collect::<Result<Vec<Allowable>, String>>()
.map_err(|s| invalid_argument(format!("could not parse {}", s)))?;
let mut alset = self.allowlist.lock().unwrap();
for a in allowables {
alset.insert(a);
}
self.update_allowlist(&alset)?;
Ok(())
}
pub fn set_allowlist(&self, allowlist: &[String]) -> Result<(), Status> {
let allowables = allowlist
.iter()
.map(|addrstr| Allowable::from_str(addrstr, self.network()))
.collect::<Result<Vec<Allowable>, String>>()
.map_err(|s| invalid_argument(format!("could not parse {}", s)))?;
let mut alset = self.allowlist.lock().unwrap();
alset.clear();
for a in allowables {
alset.insert(a);
}
self.update_allowlist(&alset)?;
Ok(())
}
fn update_allowlist(&self, alset: &MutexGuard<UnorderedSet<Allowable>>) -> Result<(), Status> {
let wlvec = (*alset).iter().map(|a| a.to_string(self.network())).collect();
self.persister
.update_node_allowlist(&self.get_id(), wlvec)
.map_err(|_| internal_error("persist failed"))
}
pub fn remove_allowlist(&self, rmlist: &[String]) -> Result<(), Status> {
let allowables = rmlist
.iter()
.map(|addrstr| Allowable::from_str(addrstr, self.network()))
.collect::<Result<Vec<Allowable>, String>>()
.map_err(|s| invalid_argument(format!("could not parse {}", s)))?;
let mut alset = self.allowlist.lock().unwrap();
for a in allowables {
alset.remove(&a);
}
self.update_allowlist(&alset)?;
Ok(())
}
pub fn get_tracker(&self) -> MutexGuard<'_, ChainTracker<ChainMonitor>> {
self.tracker.lock().unwrap()
}
pub fn get_chain_height(&self) -> u32 {
self.tracker.lock().unwrap().height()
}
pub(crate) fn htlcs_fulfilled(
&self,
channel_id: &ChannelId,
preimages: Vec<PaymentPreimage>,
validator: Arc<dyn Validator>,
) {
let mut state = self.get_state();
for preimage in preimages.into_iter() {
state.htlc_fulfilled(channel_id, preimage, Arc::clone(&validator));
}
}
pub fn add_invoice(&self, invoice: Invoice) -> Result<bool, Status> {
let validator = self.validator();
let now = self.clock.now();
validator.validate_invoice(&invoice, now)?;
let (hash, payment_state, invoice_hash) = Self::payment_state_from_invoice(&invoice)?;
info!(
"{} adding invoice {} -> {}",
self.log_prefix(),
hash.0.to_hex(),
payment_state.amount_msat
);
let mut state = self.get_state();
let policy = self.policy();
if state.invoices.len() >= policy.max_invoices() {
return Err(failed_precondition(format!(
"too many invoices ({} >= {})",
state.invoices.len(),
policy.max_invoices()
)));
}
if let Some(payment_state) = state.invoices.get(&hash) {
return if payment_state.invoice_hash == invoice_hash {
Ok(true)
} else {
Err(failed_precondition("already have a different invoice for same secret"))
};
}
if !state.velocity_control.insert(now.as_secs(), payment_state.amount_msat) {
warn!(
"policy-commitment-payment-velocity velocity would be exceeded - += {} = {} > {}",
payment_state.amount_msat,
state.velocity_control.velocity(),
state.velocity_control.limit
);
return Ok(false);
}
state.invoices.insert(hash, payment_state);
state.payments.insert(hash, RoutedPayment::new());
self.persister.update_node(&self.get_id(), &*state).expect("node persistence failure");
Ok(true)
}
pub fn add_keysend(
&self,
payee: PublicKey,
payment_hash: PaymentHash,
amount_msat: u64,
) -> Result<bool, Status> {
let (payment_state, invoice_hash) =
Node::payment_state_from_keysend(payee, payment_hash, amount_msat)?;
info!(
"{} adding payment {} -> {}",
self.log_prefix(),
payment_hash.0.to_hex(),
payment_state.amount_msat
);
let mut state = self.get_state();
let policy = self.policy();
if state.invoices.len() >= policy.max_invoices() {
return Err(failed_precondition(format!(
"too many invoices ({} >= {})",
state.invoices.len(),
policy.max_invoices()
)));
}
if let Some(payment_state) = state.invoices.get(&payment_hash) {
return if payment_state.invoice_hash == invoice_hash {
Ok(true)
} else {
Err(failed_precondition("already have a different payment for same secret"))
};
}
let now = self.clock.now().as_secs();
if !state.velocity_control.insert(now, payment_state.amount_msat) {
warn!(
"policy-commitment-payment-velocity velocity would be exceeded - += {} = {} > {}",
payment_state.amount_msat,
state.velocity_control.velocity(),
state.velocity_control.limit
);
return Ok(false);
}
state.invoices.insert(payment_hash, payment_state);
state.payments.insert(payment_hash, RoutedPayment::new());
self.persister.update_node(&self.get_id(), &*state).expect("node persistence failure");
Ok(true)
}
pub fn has_payment(&self, hash: &PaymentHash, invoice_hash: &[u8; 32]) -> Result<bool, Status> {
let state = self.get_state();
let retval = if let Some(payment_state) = state.invoices.get(&hash) {
if payment_state.invoice_hash == *invoice_hash {
Ok(true)
} else {
Err(failed_precondition("already have a different invoice for same secret"))
}
} else {
Ok(false) };
debug!("{} has_payment {} {:?}", self.log_prefix(), hash.0.to_hex(), retval,);
retval
}
pub fn payment_state_from_invoice(
invoice: &Invoice,
) -> Result<(PaymentHash, PaymentState, [u8; 32]), Status> {
let payment_hash = invoice.payment_hash();
let invoice_hash = invoice.invoice_hash();
let payment_state = PaymentState {
invoice_hash: invoice_hash.clone(),
amount_msat: invoice.amount_milli_satoshis(),
payee: invoice.payee_pub_key(),
duration_since_epoch: invoice.duration_since_epoch(),
expiry_duration: invoice.expiry_duration(),
is_fulfilled: false,
payment_type: PaymentType::Invoice,
};
Ok((payment_hash, payment_state, invoice_hash))
}
pub fn payment_state_from_keysend(
payee: PublicKey,
payment_hash: PaymentHash,
amount_msat: u64,
) -> Result<(PaymentState, [u8; 32]), Status> {
let invoice_hash = payment_hash.0;
let payment_state = PaymentState {
invoice_hash,
amount_msat,
payee,
duration_since_epoch: Duration::ZERO,
expiry_duration: Duration::ZERO,
is_fulfilled: false,
payment_type: PaymentType::Keysend,
};
Ok((payment_state, invoice_hash))
}
fn make_velocity_control(policy: &Box<dyn Policy>) -> VelocityControl {
let velocity_control_spec = policy.global_velocity_control();
VelocityControl::new(velocity_control_spec)
}
fn make_fee_velocity_control(policy: &Box<dyn Policy>) -> VelocityControl {
let velocity_control_spec = policy.fee_velocity_control();
VelocityControl::new(velocity_control_spec)
}
}
pub trait NodeMonitor {
fn channel_balance(&self) -> ChannelBalance;
}
impl NodeMonitor for Node {
fn channel_balance(&self) -> ChannelBalance {
let mut sum = ChannelBalance::zero();
let channels_lock = self.channels.lock().unwrap();
for (_, slot_arc) in channels_lock.iter() {
let slot = slot_arc.lock().unwrap();
match &*slot {
ChannelSlot::Ready(chan) => sum.accumulate(&chan.balance()),
ChannelSlot::Stub(_stub) => {
}
}
}
sum
}
}
fn find_channel_with_funding_outpoint(
channels_lock: &MutexGuard<OrderedMap<ChannelId, Arc<Mutex<ChannelSlot>>>>,
outpoint: &OutPoint,
) -> Option<Arc<Mutex<ChannelSlot>>> {
for (_, slot_arc) in channels_lock.iter() {
let slot = slot_arc.lock().unwrap();
match &*slot {
ChannelSlot::Ready(chan) =>
if chan.setup.funding_outpoint == *outpoint {
return Some(Arc::clone(slot_arc));
},
ChannelSlot::Stub(_stub) => {
}
}
}
None
}
impl Debug for Node {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str("node")
}
}
#[derive(PartialEq, Clone, Copy, Debug)]
#[repr(i32)]
pub enum SpendType {
Invalid = 0,
P2pkh = 1,
P2wpkh = 3,
P2shP2wpkh = 4,
P2wsh = 5,
}
impl TryFrom<i32> for SpendType {
type Error = ();
fn try_from(i: i32) -> Result<Self, Self::Error> {
let res = match i {
x if x == SpendType::Invalid as i32 => SpendType::Invalid,
x if x == SpendType::P2pkh as i32 => SpendType::P2pkh,
x if x == SpendType::P2wpkh as i32 => SpendType::P2wpkh,
x if x == SpendType::P2shP2wpkh as i32 => SpendType::P2shP2wpkh,
x if x == SpendType::P2wsh as i32 => SpendType::P2wsh,
_ => return Err(()),
};
Ok(res)
}
}
pub trait SyncLogger: Logger + SendSync {}
#[cfg(test)]
mod tests {
use bitcoin;
use bitcoin::bech32::{CheckBase32, ToBase32};
use bitcoin::consensus::deserialize;
use bitcoin::hashes::sha256d::Hash as Sha256dHash;
use bitcoin::hashes::Hash;
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
use bitcoin::secp256k1::SecretKey;
use bitcoin::util::sighash::SighashCache;
use bitcoin::{secp256k1, BlockHash};
use bitcoin::{Address, EcdsaSighashType, OutPoint};
use lightning::ln::chan_utils::derive_private_key;
use lightning::ln::{chan_utils, PaymentSecret};
use lightning_invoice::{Currency, InvoiceBuilder};
use std::time::{SystemTime, UNIX_EPOCH};
use test_log::test;
use crate::channel::ChannelBase;
use crate::policy::simple_validator::{make_simple_policy, SimpleValidatorFactory};
use crate::util::status::{internal_error, invalid_argument, Code, Status};
use crate::util::test_utils::invoice::make_test_bolt12_invoice;
use crate::util::test_utils::*;
use super::*;
#[test]
fn channel_debug_test() {
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let _status: Result<(), Status> = node.with_ready_channel(&channel_id, |chan| {
assert_eq!(format!("{:?}", chan), "channel");
Ok(())
});
}
#[test]
fn node_debug_test() {
let (node, _channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
assert_eq!(format!("{:?}", node), "node");
}
#[test]
fn node_invalid_argument_test() {
let err = invalid_argument("testing invalid_argument");
assert_eq!(err.code(), Code::InvalidArgument);
assert_eq!(err.message(), "testing invalid_argument");
}
#[test]
fn node_internal_error_test() {
let err = internal_error("testing internal_error");
assert_eq!(err.code(), Code::Internal);
assert_eq!(err.message(), "testing internal_error");
}
#[test]
fn new_channel_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let (channel_id, _) = node.new_channel(None, &node).unwrap();
assert!(node.get_channel(&channel_id).is_ok());
}
#[test]
fn bad_channel_lookup_test() -> Result<(), ()> {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let channel_id = ChannelId::new(&hex_decode(TEST_CHANNEL_ID[0]).unwrap());
assert!(node.get_channel(&channel_id).is_err());
Ok(())
}
#[test]
fn keysend_test() {
let payee_node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let payee_node_id = payee_node.node_id.clone();
let (node, _channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let hash = PaymentHash([2; 32]);
assert!(node.add_keysend(payee_node_id.clone(), hash, 1234).unwrap());
assert!(node.add_keysend(payee_node.node_id.clone(), hash, 1234).unwrap());
let (_, invoice_hash) =
Node::payment_state_from_keysend(payee_node_id, hash, 1234).unwrap();
assert!(node.has_payment(&hash, &invoice_hash).unwrap());
assert!(!node.has_payment(&PaymentHash([5; 32]), &invoice_hash).unwrap());
}
#[test]
fn invoice_test() {
let payee_node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let hash = PaymentHash([2; 32]);
let invoice1 = make_test_invoice(&payee_node, "invoice1", hash);
let invoice2 = make_test_invoice(&payee_node, "invoice2", hash);
assert_eq!(node.add_invoice(invoice1.clone()).expect("add invoice"), true);
assert_eq!(node.add_invoice(invoice1.clone()).expect("add invoice"), true);
node.add_invoice(invoice2.clone())
.expect_err("add a different invoice with same payment hash");
let mut state = node.get_state();
let hash1 = PaymentHash([1; 32]);
let channel_id2 = ChannelId::new(&hex_decode(TEST_CHANNEL_ID[1]).unwrap());
let mut policy = make_simple_policy(Network::Testnet);
policy.require_invoices = true;
let invoice_validator = SimpleValidatorFactory::new_with_policy(policy).make_validator(
Network::Testnet,
node.get_id(),
None,
);
let lenient_validator =
SimpleValidatorFactory::new().make_validator(Network::Testnet, node.get_id(), None);
state
.validate_and_apply_payments(
&channel_id2,
&Map::new(),
&vec![(hash, 99)].into_iter().collect(),
&Default::default(),
invoice_validator.clone(),
)
.expect("channel1");
let result = state.validate_and_apply_payments(
&channel_id,
&Map::new(),
&vec![(hash, 12)].into_iter().collect(),
&Default::default(),
invoice_validator.clone(),
);
assert_eq!(result, Err(policy_error("validate_payments: unbalanced payments on channel 0100000000000000000000000000000000000000000000000000000000000000: [\"0202020202020202020202020202020202020202020202020202020202020202\"]")));
let result = state.validate_and_apply_payments(
&channel_id,
&Map::new(),
&vec![(hash, 11)].into_iter().collect(),
&Default::default(),
invoice_validator.clone(),
);
assert!(result.is_ok());
let result = state.validate_and_apply_payments(
&channel_id,
&Map::new(),
&vec![(hash1, 5)].into_iter().collect(),
&Default::default(),
lenient_validator.clone(),
);
assert!(result.is_ok());
let result = state.validate_and_apply_payments(
&channel_id,
&Map::new(),
&vec![(hash1, 5)].into_iter().collect(),
&Default::default(),
invoice_validator.clone(),
);
assert!(result.is_err());
}
fn make_test_invoice(
payee_node: &Node,
description: &str,
payment_hash: PaymentHash,
) -> Invoice {
sign_invoice(payee_node, build_test_invoice(description, &payment_hash))
}
fn sign_invoice(payee_node: &Node, data: (Vec<u8>, Vec<u5>)) -> Invoice {
payee_node.do_sign_invoice(&data.0, &data.1).unwrap().try_into().unwrap()
}
fn build_test_invoice(description: &str, payment_hash: &PaymentHash) -> (Vec<u8>, Vec<u5>) {
let now = SystemTime::now().duration_since(UNIX_EPOCH).expect("time");
build_test_invoice_with_time(description, payment_hash, now)
}
fn build_test_invoice_with_time(
description: &str,
payment_hash: &PaymentHash,
now: Duration,
) -> (Vec<u8>, Vec<u5>) {
let raw_invoice = InvoiceBuilder::new(Currency::Bitcoin)
.duration_since_epoch(now)
.amount_milli_satoshis(100_000)
.payment_hash(Sha256Hash::from_slice(&payment_hash.0).unwrap())
.payment_secret(PaymentSecret([0; 32]))
.description(description.to_string())
.build_raw()
.expect("build");
let hrp_str = raw_invoice.hrp.to_string();
let hrp_bytes = hrp_str.as_bytes().to_vec();
let invoice_data = raw_invoice.data.to_base32();
(hrp_bytes, invoice_data)
}
#[test]
fn with_channel_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let channel_id = ChannelId::new(&hex_decode(TEST_CHANNEL_ID[0]).unwrap());
node.new_channel(Some(channel_id.clone()), &node).expect("new_channel");
assert!(node
.with_ready_channel(&channel_id, |_channel| {
panic!("should not be called");
#[allow(unreachable_code)]
Ok(())
})
.is_err());
assert!(node.with_channel_base(&channel_id, |_channel| { Ok(()) }).is_ok());
}
#[test]
fn double_new_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let channel_id = ChannelId::new(&hex_decode(TEST_CHANNEL_ID[0]).unwrap());
node.new_channel(Some(channel_id.clone()), &node).expect("new_channel");
let (id, slot) = node.new_channel(Some(channel_id.clone()), &node).unwrap();
assert_eq!(id, channel_id);
assert!(slot.is_some());
}
#[test]
fn too_many_channels_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
for _ in 0..node.policy().max_channels() {
node.new_channel(None, &node).expect("new_channel");
}
assert!(node.new_channel(None, &node).is_err());
}
#[test]
fn too_many_invoices_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let payee_node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
for i in 0..node.policy().max_invoices() {
let mut hash = [1u8; 32];
hash[0..8].copy_from_slice(&i.to_be_bytes());
let invoice =
make_test_invoice(&payee_node, &format!("invoice {}", i), PaymentHash(hash));
assert_eq!(node.add_invoice(invoice).expect("add invoice"), true);
}
let invoice = make_test_invoice(&payee_node, "invoice", PaymentHash([2u8; 32]));
node.add_invoice(invoice).expect_err("expected too many invoices");
}
#[test]
fn prune_invoice_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let invoice = make_test_invoice(&node, "invoice", PaymentHash([0; 32]));
node.add_invoice(invoice.clone()).unwrap();
let mut state = node.get_state();
assert_eq!(state.invoices.len(), 1);
assert_eq!(state.payments.len(), 1);
println!("now: {:?}", node.clock.now());
println!("invoice time: {:?}", invoice.duration_since_epoch());
state.prune_invoices(node.clock.now());
assert_eq!(state.invoices.len(), 1);
assert_eq!(state.payments.len(), 1);
state.prune_invoices(node.clock.now() + Duration::from_secs(3600 * 23));
assert_eq!(state.invoices.len(), 1);
assert_eq!(state.payments.len(), 1);
state.prune_invoices(node.clock.now() + Duration::from_secs(3600 * 25));
assert_eq!(state.invoices.len(), 0);
assert_eq!(state.payments.len(), 0);
}
#[test]
fn prune_invoice_incomplete_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let invoice = make_test_invoice(&node, "invoice", PaymentHash([0; 32]));
node.add_invoice(invoice.clone()).unwrap();
let mut state = node.get_state();
assert_eq!(state.invoices.len(), 1);
assert_eq!(state.payments.len(), 1);
let chan_id = ChannelId::new(&[0; 32]);
state.payments.get_mut(&PaymentHash([0; 32])).unwrap().outgoing.insert(chan_id, 100);
state.prune_invoices(node.clock.now());
assert_eq!(state.invoices.len(), 1);
assert_eq!(state.payments.len(), 1);
state.prune_invoices(node.clock.now() + Duration::from_secs(3600 * 25));
assert_eq!(state.invoices.len(), 1);
assert_eq!(state.payments.len(), 1);
state.payments.get_mut(&PaymentHash([0; 32])).unwrap().preimage =
Some(PaymentPreimage([0; 32]));
state.prune_invoices(node.clock.now() + Duration::from_secs(3600 * 25));
assert_eq!(state.invoices.len(), 0);
assert_eq!(state.payments.len(), 0);
}
#[test]
fn prune_issued_invoice_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let (hrp, data) = build_test_invoice("invoice", &PaymentHash([0; 32]));
node.sign_invoice(&hrp, &data).unwrap();
let mut state = node.get_state();
assert_eq!(state.issued_invoices.len(), 1);
state.prune_issued_invoices(node.clock.now());
assert_eq!(state.issued_invoices.len(), 1);
state.prune_issued_invoices(node.clock.now() + Duration::from_secs(3600 * 23));
assert_eq!(state.issued_invoices.len(), 1);
state.prune_issued_invoices(node.clock.now() + Duration::from_secs(3600 * 25));
assert_eq!(state.issued_invoices.len(), 0);
}
#[test]
fn add_expired_invoice_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let future =
SystemTime::now().duration_since(UNIX_EPOCH).expect("time") + Duration::from_secs(3600);
let invoice = sign_invoice(
&*node,
build_test_invoice_with_time("invoice", &PaymentHash([0; 32]), future),
);
assert!(node
.add_invoice(invoice)
.unwrap_err()
.message()
.starts_with("policy failure: validate_invoice: invoice is not yet valid"));
let past =
SystemTime::now().duration_since(UNIX_EPOCH).expect("time") - Duration::from_secs(7200);
let invoice = sign_invoice(
&*node,
build_test_invoice_with_time("invoice", &PaymentHash([0; 32]), past),
);
assert!(node
.add_invoice(invoice)
.unwrap_err()
.message()
.starts_with("policy failure: validate_invoice: invoice is expired"));
}
#[test]
fn too_many_issued_invoices_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
for i in 0..node.policy().max_invoices() {
let mut hash = [1u8; 32];
hash[0..8].copy_from_slice(&i.to_be_bytes());
let (hrp, data) = build_test_invoice("invoice", &PaymentHash(hash));
node.sign_invoice(&hrp, &data).unwrap();
}
let (hrp, data) = build_test_invoice("invoice", &PaymentHash([2u8; 32]));
node.sign_invoice(&hrp, &data).expect_err("expected too many issued invoics");
}
#[test]
fn fulfill_test() {
let payee_node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let preimage = PaymentPreimage([0; 32]);
let hash = PaymentHash(Sha256Hash::hash(&preimage.0).into_inner());
let invoice = make_test_invoice(&payee_node, "invoice", hash);
assert_eq!(node.add_invoice(invoice).expect("add invoice"), true);
let mut policy = make_simple_policy(Network::Testnet);
policy.require_invoices = true;
policy.enforce_balance = true;
let factory = SimpleValidatorFactory::new_with_policy(policy);
let invoice_validator = factory.make_validator(Network::Testnet, node.get_id(), None);
node.set_validator_factory(Arc::new(factory));
{
let mut state = node.get_state();
assert_status_ok!(state.validate_and_apply_payments(
&channel_id,
&Map::new(),
&vec![(hash, 110)].into_iter().collect(),
&Default::default(),
invoice_validator.clone()
));
}
node.with_ready_channel(&channel_id, |chan| {
chan.htlcs_fulfilled(vec![preimage]);
Ok(())
})
.unwrap();
}
#[test]
fn fulfill_bolt12_test() {
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let preimage = PaymentPreimage([0; 32]);
let hash = PaymentHash(Sha256Hash::hash(&preimage.0).into_inner());
let invoice = make_test_bolt12_invoice("This is the invoice description", hash);
assert_eq!(invoice.description(), "This is the invoice description".to_string());
assert_eq!(node.add_invoice(invoice).expect("add invoice"), true);
let mut policy = make_simple_policy(Network::Testnet);
policy.require_invoices = true;
policy.enforce_balance = true;
let factory = SimpleValidatorFactory::new_with_policy(policy);
let invoice_validator = factory.make_validator(Network::Testnet, node.get_id(), None);
node.set_validator_factory(Arc::new(factory));
{
let mut state = node.get_state();
assert_status_ok!(state.validate_and_apply_payments(
&channel_id,
&Map::new(),
&vec![(hash, 110)].into_iter().collect(),
&Default::default(),
invoice_validator.clone()
));
}
node.with_ready_channel(&channel_id, |chan| {
chan.htlcs_fulfilled(vec![preimage]);
Ok(())
})
.unwrap();
}
#[test]
fn overpay_test() {
let payee_node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let preimage = PaymentPreimage([0; 32]);
let hash = PaymentHash(Sha256Hash::hash(&preimage.0).into_inner());
let invoice = make_test_invoice(&payee_node, "invoice", hash);
assert_eq!(node.add_invoice(invoice).expect("add invoice"), true);
let mut policy = make_simple_policy(Network::Testnet);
policy.require_invoices = true;
policy.enforce_balance = true;
let factory = SimpleValidatorFactory::new_with_policy(policy);
let invoice_validator = factory.make_validator(Network::Testnet, node.get_id(), None);
node.set_validator_factory(Arc::new(factory));
{
let mut state = node.get_state();
assert_eq!(
state.validate_and_apply_payments(
&channel_id,
&Map::new(),
&vec![(hash, 111)].into_iter().collect(),
&Default::default(),
invoice_validator.clone()
),
Err(policy_error("validate_payments: unbalanced payments on channel 0100000000000000000000000000000000000000000000000000000000000000: [\"66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925\"]"))
);
}
}
#[test]
fn shortfall_test() {
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let mut policy = make_simple_policy(Network::Testnet);
policy.require_invoices = true;
policy.enforce_balance = true;
let factory = SimpleValidatorFactory::new_with_policy(policy);
let invoice_validator = factory.make_validator(Network::Testnet, node.get_id(), None);
node.set_validator_factory(Arc::new(factory));
{
let mut state = node.get_state();
assert_eq!(
state.validate_and_apply_payments(
&channel_id,
&Map::new(),
&Map::new(),
&BalanceDelta(0, 0),
invoice_validator.clone()
),
Ok(())
);
assert_eq!(
state.validate_and_apply_payments(
&channel_id,
&Map::new(),
&Map::new(),
&BalanceDelta(1, 0),
invoice_validator.clone()
),
Err(policy_error("shortfall 0 + 0 - 1"))
);
}
}
#[test]
fn sign_invoice_no_amount_test() {
let (node, _channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let preimage = PaymentPreimage([0; 32]);
let hash = PaymentHash(Sha256Hash::hash(&preimage.0).into_inner());
let raw_invoice = InvoiceBuilder::new(Currency::Bitcoin)
.duration_since_epoch(Duration::from_secs(123456789))
.payment_hash(Sha256Hash::from_slice(&hash.0).unwrap())
.payment_secret(PaymentSecret([0; 32]))
.description("".to_string())
.build_raw()
.expect("build");
let hrp_str = raw_invoice.hrp.to_string();
let hrp = hrp_str.as_bytes().to_vec();
let data = raw_invoice.data.to_base32();
node.sign_invoice(&hrp, &data).unwrap();
}
#[test]
fn incoming_payment_test() {
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let preimage = PaymentPreimage([0; 32]);
let hash = PaymentHash(Sha256Hash::hash(&preimage.0).into_inner());
let (hrp, data) = build_test_invoice("invoice", &hash);
node.sign_invoice(&hrp, &data).unwrap();
let mut policy = make_simple_policy(Network::Testnet);
policy.require_invoices = true;
policy.enforce_balance = true;
let factory = SimpleValidatorFactory::new_with_policy(policy);
let invoice_validator = factory.make_validator(Network::Testnet, node.get_id(), None);
{
let mut state = node.get_state();
state
.validate_and_apply_payments(
&channel_id,
&vec![(hash, 99)].into_iter().collect(),
&Map::new(),
&Default::default(),
invoice_validator.clone(),
)
.expect("ok");
assert!(!state.payments.get(&hash).unwrap().is_fulfilled());
state
.validate_and_apply_payments(
&channel_id,
&vec![(hash, 100)].into_iter().collect(),
&Map::new(),
&Default::default(),
invoice_validator.clone(),
)
.expect("ok");
assert!(state.payments.get(&hash).unwrap().is_fulfilled());
state
.validate_and_apply_payments(
&channel_id,
&vec![(hash, 100)].into_iter().collect(),
&Map::new(),
&Default::default(),
invoice_validator.clone(),
)
.expect("ok");
assert!(state.payments.get(&hash).unwrap().is_fulfilled());
}
}
#[test]
fn get_per_commitment_point_and_secret_test() {
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let commit_num = 23;
let (point, secret) = node
.with_ready_channel(&channel_id, |chan| {
chan.enforcement_state.set_next_holder_commit_num_for_testing(commit_num + 2);
let point = chan.get_per_commitment_point(commit_num)?;
let secret = chan.get_per_commitment_secret(commit_num)?;
Ok((point, secret))
})
.expect("point");
let derived_point = PublicKey::from_secret_key(&Secp256k1::new(), &secret);
assert_eq!(point, derived_point);
}
#[test]
fn get_check_future_secret_test() {
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let n: u64 = 10;
let suggested = SecretKey::from_slice(
hex_decode("2f87fef68f2bafdb3c6425921894af44da9a984075c70c7ba31ccd551b3585db")
.unwrap()
.as_slice(),
)
.unwrap();
let correct = node
.with_channel_base(&channel_id, |base| base.check_future_secret(n, &suggested))
.unwrap();
assert_eq!(correct, true);
let notcorrect = node
.with_channel_base(&channel_id, |base| base.check_future_secret(n + 1, &suggested))
.unwrap();
assert_eq!(notcorrect, false);
}
#[test]
fn sign_channel_announcement_with_funding_key_test() {
let (node, channel_id) =
init_node_and_channel(TEST_NODE_CONFIG, TEST_SEED[1], make_test_channel_setup());
let ann = hex_decode("0123456789abcdef").unwrap();
let bsig = node
.with_ready_channel(&channel_id, |chan| {
Ok(chan.sign_channel_announcement_with_funding_key(&ann))
})
.unwrap();
let ca_hash = Sha256dHash::hash(&ann);
let encmsg = secp256k1::Message::from_slice(&ca_hash[..]).expect("encmsg");
let secp_ctx = Secp256k1::new();
node.with_ready_channel(&channel_id, |chan| {
let funding_pubkey = PublicKey::from_secret_key(&secp_ctx, &chan.keys.funding_key);
Ok(secp_ctx.verify_ecdsa(&encmsg, &bsig, &funding_pubkey).expect("verify bsig"))
})
.unwrap();
}
#[test]
fn sign_node_announcement_test() -> Result<(), ()> {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let ann = hex_decode("000302aaa25e445fef0265b6ab5ec860cd257865d61ef0bbf5b3339c36cbda8b26b74e7f1dca490b65180265b64c4f554450484f544f2d2e302d3139392d67613237336639642d6d6f646465640000").unwrap();
let sigvec = node.sign_node_announcement(&ann).unwrap().serialize_der().to_vec();
assert_eq!(sigvec, hex_decode("30450221008ef1109b95f127a7deec63b190b72180f0c2692984eaf501c44b6bfc5c4e915502207a6fa2f250c5327694967be95ff42a94a9c3d00b7fa0fbf7daa854ceb872e439").unwrap());
Ok(())
}
#[test]
fn sign_channel_update_test() -> Result<(), ()> {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let cu = hex_decode("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f00006700000100015e42ddc6010000060000000000000000000000010000000a000000003b023380").unwrap();
let sigvec = node.sign_channel_update(&cu).unwrap().serialize_der().to_vec();
assert_eq!(sigvec, hex_decode("3045022100be9840696c868b161aaa997f9fa91a899e921ea06c8083b2e1ea32b8b511948d0220352eec7a74554f97c2aed26950b8538ca7d7d7568b42fd8c6f195bd749763fa5").unwrap());
Ok(())
}
#[test]
fn sign_invoice_test() -> Result<(), ()> {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let human_readable_part = String::from("lnbcrt1230n");
let data_part = hex_decode("010f0418090a010101141917110f01040e050f06100003021e1b0e13161c150301011415060204130c0018190d07070a18070a1c1101111e111f130306000d00120c11121706181b120d051807081a0b0f0d18060004120e140018000105100114000b130b01110c001a05041a181716020007130c091d11170d10100d0b1a1b00030e05190208171e16080d00121a00110719021005000405001000").unwrap().check_base32().unwrap();
let (rid, rsig) = node
.sign_invoice(human_readable_part.as_bytes(), &data_part)
.unwrap()
.serialize_compact();
assert_eq!(rsig.to_vec(), hex_decode("739ffb91aa7c0b3d3c92de1600f7a9afccedc5597977095228232ee4458685531516451b84deb35efad27a311ea99175d10c6cdb458cd27ce2ed104eb6cf8064").unwrap());
assert_eq!(rid.to_i32(), 0);
Ok(())
}
#[test]
fn sign_invoice_with_overhang_test() -> Result<(), ()> {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let human_readable_part = String::from("lnbcrt2m");
let data_part = hex_decode("010f0a001d051e0101140c0c000006140009160c09051a0d1a190708020d17141106171f0f07131616111f1910070b0d0e150c0c0c0d010d1a01181c15100d010009181a06101a0a0309181b040a111a0a06111705100c0b18091909030e151b14060004120e14001800010510011419080f1307000a0a0517021c171410101a1e101605050a08180d0d110e13150409051d02091d181502020f050e1a1f161a09130005000405001000").unwrap().check_base32().unwrap();
let (rid, rsig) = node
.sign_invoice(human_readable_part.as_bytes(), &data_part)
.unwrap()
.serialize_compact();
assert_eq!(rsig.to_vec(), hex_decode("f278cdba3fd4a37abf982cee5a66f52e142090631ef57763226f1232eead78b43da7962fcfe29ffae9bd918c588df71d6d7b92a4787de72801594b22f0e7e62a").unwrap());
assert_eq!(rid.to_i32(), 0);
Ok(())
}
#[test]
fn sign_bad_invoice_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let human_readable_part = String::from("lnbcrt1230n");
let data_part = hex_decode("010f0418090a").unwrap().check_base32().unwrap();
assert_invalid_argument_err!(
node.sign_invoice(human_readable_part.as_bytes(), &data_part),
"parse error: data part too short (should be at least 111 bech32 chars long)"
);
}
#[test]
fn ecdh_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let pointvec =
hex_decode("0330febba06ba074378dec994669cf5ebf6b15e24a04ec190fb93a9482e841a0ca")
.unwrap();
let other_key = PublicKey::from_slice(pointvec.as_slice()).unwrap();
let ssvec = node.ecdh(&other_key);
assert_eq!(
ssvec,
hex_decode("48db1582f4b42a0068b5727fd37090a65fbf1f9bd842f4393afc2e794719ae47").unwrap()
);
}
#[test]
fn get_unilateral_close_key_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[0]);
let (channel_id, chan) = node.new_channel(None, &node).unwrap();
node.ready_channel(channel_id.clone(), None, make_test_channel_setup(), &vec![])
.expect("ready channel");
let uck = node
.with_ready_channel(&channel_id, |chan| chan.get_unilateral_close_key(&None, &None))
.unwrap();
let keys = &chan.as_ref().unwrap().unwrap_stub().keys;
let key = keys.pubkeys().payment_point;
assert_eq!(
uck,
(
SecretKey::from_slice(
&hex_decode("e6eb522940c9d1dcffc82f4eaff5b81ad318bdaa952061fa73fd6f717f73e160")
.unwrap()[..]
)
.unwrap(),
vec![key.serialize().to_vec()]
)
);
let secp_ctx = Secp256k1::new();
let revocation_secret = SecretKey::from_slice(
hex_decode("0101010101010101010101010101010101010101010101010101010101010101")
.unwrap()
.as_slice(),
)
.unwrap();
let revocation_point = PublicKey::from_secret_key(&secp_ctx, &revocation_secret);
let commitment_secret = SecretKey::from_slice(
hex_decode("0101010101010101010101010101010101010101010101010101010101010102")
.unwrap()
.as_slice(),
)
.unwrap();
let commitment_point = PublicKey::from_secret_key(&secp_ctx, &commitment_secret);
let uck = node
.with_ready_channel(&channel_id, |chan| {
chan.get_unilateral_close_key(&Some(commitment_point), &Some(revocation_point))
})
.unwrap();
let seckey =
derive_private_key(&secp_ctx, &commitment_point, &keys.delayed_payment_base_key);
let pubkey = PublicKey::from_secret_key(&secp_ctx, &seckey);
let redeem_script = chan_utils::get_revokeable_redeemscript(&revocation_point, 7, &pubkey);
assert_eq!(
uck,
(
SecretKey::from_slice(
&hex_decode("fd5f03ea7b42be9a045097dfa1ef007a430f576302c76e6e6265812f1d1ce18f")
.unwrap()[..]
)
.unwrap(),
vec![vec![], redeem_script.to_bytes()]
)
);
}
#[test]
fn get_account_ext_pub_key_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let xpub = node.get_account_extended_pubkey();
assert_eq!(format!("{}", xpub), "tpubDAu312RD7nE6R9qyB4xJk9QAMyi3ppq3UJ4MMUGpB9frr6eNDd8FJVPw27zTVvWAfYFVUtJamgfh5ZLwT23EcymYgLx7MHsU8zZxc9L3GKk");
}
#[test]
fn check_wallet_pubkey_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
assert_eq!(
node.check_wallet_pubkey(
&vec![1],
bitcoin::PublicKey::from_slice(
hex_decode(
"0330febba06ba074378dec994669cf5ebf6b15e24a04ec190fb93a9482e841a0ca"
)
.unwrap()
.as_slice()
)
.unwrap()
)
.unwrap(),
false,
);
assert_eq!(
node.check_wallet_pubkey(
&vec![1],
bitcoin::PublicKey::from_slice(
hex_decode(
"0207ec2b35534712d86ae030dd9bfaec08e2ddea1ec1cecffb9725ed7acb12ab66"
)
.unwrap()
.as_slice()
)
.unwrap()
)
.unwrap(),
true,
);
}
#[test]
fn sign_bolt12_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
node.sign_bolt12("name".as_bytes(), "field".as_bytes(), &[0; 32], None).unwrap();
}
#[test]
fn sign_message_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let message = String::from("Testing 1 2 3").into_bytes();
let mut rsigvec = node.sign_message(&message).unwrap();
let rid = rsigvec.pop().unwrap() as i32;
let rsig =
RecoverableSignature::from_compact(&rsigvec[..], RecoveryId::from_i32(rid).unwrap())
.unwrap();
let secp_ctx = secp256k1::Secp256k1::new();
let mut buffer = String::from("Lightning Signed Message:").into_bytes();
buffer.extend(message);
let hash = Sha256dHash::hash(&buffer);
let encmsg = secp256k1::Message::from_slice(&hash[..]).unwrap();
let sig = Signature::from_compact(&rsig.to_standard().serialize_compact()).unwrap();
let pubkey = secp_ctx.recover_ecdsa(&encmsg, &rsig).unwrap();
assert!(secp_ctx.verify_ecdsa(&encmsg, &sig, &pubkey).is_ok());
assert_eq!(pubkey.serialize().to_vec(), node.get_id().serialize().to_vec());
}
#[test]
fn transaction_verify_test() {
let spending: Transaction = deserialize(hex_decode("020000000001031cfbc8f54fbfa4a33a30068841371f80dbfe166211242213188428f437445c91000000006a47304402206fbcec8d2d2e740d824d3d36cc345b37d9f65d665a99f5bd5c9e8d42270a03a8022013959632492332200c2908459547bf8dbf97c65ab1a28dec377d6f1d41d3d63e012103d7279dfb90ce17fe139ba60a7c41ddf605b25e1c07a4ddcb9dfef4e7d6710f48feffffff476222484f5e35b3f0e43f65fc76e21d8be7818dd6a989c160b1e5039b7835fc00000000171600140914414d3c94af70ac7e25407b0689e0baa10c77feffffffa83d954a62568bbc99cc644c62eb7383d7c2a2563041a0aeb891a6a4055895570000000017160014795d04cc2d4f31480d9a3710993fbd80d04301dffeffffff06fef72f000000000017a91476fd7035cd26f1a32a5ab979e056713aac25796887a5000f00000000001976a914b8332d502a529571c6af4be66399cd33379071c588ac3fda0500000000001976a914fc1d692f8de10ae33295f090bea5fe49527d975c88ac522e1b00000000001976a914808406b54d1044c429ac54c0e189b0d8061667e088ac6eb68501000000001976a914dfab6085f3a8fb3e6710206a5a959313c5618f4d88acbba20000000000001976a914eb3026552d7e3f3073457d0bee5d4757de48160d88ac0002483045022100bee24b63212939d33d513e767bc79300051f7a0d433c3fcf1e0e3bf03b9eb1d70220588dc45a9ce3a939103b4459ce47500b64e23ab118dfc03c9caa7d6bfc32b9c601210354fd80328da0f9ae6eef2b3a81f74f9a6f66761fadf96f1d1d22b1fd6845876402483045022100e29c7e3a5efc10da6269e5fc20b6a1cb8beb92130cc52c67e46ef40aaa5cac5f0220644dd1b049727d991aece98a105563416e10a5ac4221abac7d16931842d5c322012103960b87412d6e169f30e12106bdf70122aabb9eb61f455518322a18b920a4dfa887d30700")
.unwrap().as_slice()).unwrap();
let spent1: Transaction = deserialize(hex_decode("020000000001040aacd2c49f5f3c0968cfa8caf9d5761436d95385252e3abb4de8f5dcf8a582f20000000017160014bcadb2baea98af0d9a902e53a7e9adff43b191e9feffffff96cd3c93cac3db114aafe753122bd7d1afa5aa4155ae04b3256344ecca69d72001000000171600141d9984579ceb5c67ebfbfb47124f056662fe7adbfeffffffc878dd74d3a44072eae6178bb94b9253177db1a5aaa6d068eb0e4db7631762e20000000017160014df2a48cdc53dae1aba7aa71cb1f9de089d75aac3feffffffe49f99275bc8363f5f593f4eec371c51f62c34ff11cc6d8d778787d340d6896c0100000017160014229b3b297a0587e03375ab4174ef56eeb0968735feffffff03360d0f00000000001976a9149f44b06f6ee92ddbc4686f71afe528c09727a5c788ac24281b00000000001976a9140277b4f68ff20307a2a9f9b4487a38b501eb955888ac227c0000000000001976a9148020cd422f55eef8747a9d418f5441030f7c9c7788ac0247304402204aa3bd9682f9a8e101505f6358aacd1749ecf53a62b8370b97d59243b3d6984f02200384ad449870b0e6e89c92505880411285ecd41cf11e7439b973f13bad97e53901210205b392ffcb83124b1c7ce6dd594688198ef600d34500a7f3552d67947bbe392802473044022033dfd8d190a4ae36b9f60999b217c775b96eb10dee3a1ff50fb6a75325719106022005872e4e36d194e49ced2ebcf8bb9d843d842e7b7e0eb042f4028396088d292f012103c9d7cbf369410b090480de2aa15c6c73d91b9ffa7d88b90724614b70be41e98e0247304402207d952de9e59e4684efed069797e3e2d993e9f98ec8a9ccd599de43005fe3f713022076d190cc93d9513fc061b1ba565afac574e02027c9efbfa1d7b71ab8dbb21e0501210313ad44bc030cc6cb111798c2bf3d2139418d751c1e79ec4e837ce360cc03b97a024730440220029e75edb5e9413eb98d684d62a077b17fa5b7cc19349c1e8cc6c4733b7b7452022048d4b9cae594f03741029ff841e35996ef233701c1ea9aa55c301362ea2e2f68012103590657108a72feb8dc1dec022cf6a230bb23dc7aaa52f4032384853b9f8388baf9d20700")
.unwrap().as_slice()).unwrap();
let spent2: Transaction = deserialize(hex_decode("0200000000010166c3d39490dc827a2594c7b17b7d37445e1f4b372179649cd2ce4475e3641bbb0100000017160014e69aa750e9bff1aca1e32e57328b641b611fc817fdffffff01e87c5d010000000017a914f3890da1b99e44cd3d52f7bcea6a1351658ea7be87024830450221009eb97597953dc288de30060ba02d4e91b2bde1af2ecf679c7f5ab5989549aa8002202a98f8c3bd1a5a31c0d72950dd6e2e3870c6c5819a6c3db740e91ebbbc5ef4800121023f3d3b8e74b807e32217dea2c75c8d0bd46b8665b3a2d9b3cb310959de52a09bc9d20700")
.unwrap().as_slice()).unwrap();
let spent3: Transaction = deserialize(hex_decode("01000000027a1120a30cef95422638e8dab9dedf720ec614b1b21e451a4957a5969afb869d000000006a47304402200ecc318a829a6cad4aa9db152adbf09b0cd2de36f47b53f5dade3bc7ef086ca702205722cda7404edd6012eedd79b2d6f24c0a0c657df1a442d0a2166614fb164a4701210372f4b97b34e9c408741cd1fc97bcc7ffdda6941213ccfde1cb4075c0f17aab06ffffffffc23b43e5a18e5a66087c0d5e64d58e8e21fcf83ce3f5e4f7ecb902b0e80a7fb6010000006b483045022100f10076a0ea4b4cf8816ed27a1065883efca230933bf2ff81d5db6258691ff75202206b001ef87624e76244377f57f0c84bc5127d0dd3f6e0ef28b276f176badb223a01210309a3a61776afd39de4ed29b622cd399d99ecd942909c36a8696cfd22fc5b5a1affffffff0200127a000000000017a914f895e1dd9b29cb228e9b06a15204e3b57feaf7cc8769311d09000000001976a9144d00da12aaa51849d2583ae64525d4a06cd70fde88ac00000000")
.unwrap().as_slice()).unwrap();
println!("{:?}", &spending.txid());
println!("{:?}", &spent1.txid());
println!("{:?}", &spent2.txid());
println!("{:?}", &spent3.txid());
println!("{:?}", &spent1.output[0].script_pubkey);
println!("{:?}", &spent2.output[0].script_pubkey);
println!("{:?}", &spent3.output[0].script_pubkey);
let mut spent = Map::new();
spent.insert(spent1.txid(), spent1);
spent.insert(spent2.txid(), spent2);
spent.insert(spent3.txid(), spent3);
spending
.verify(|point: &OutPoint| {
if let Some(tx) = spent.remove(&point.txid) {
return tx.output.get(point.vout as usize).cloned();
}
None
})
.unwrap();
}
#[test]
fn bip143_p2wpkh_test() {
let tx: Transaction = deserialize(hex_decode("0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f0000000000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a0100000000ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000")
.unwrap().as_slice()).unwrap();
let secp_ctx = Secp256k1::signing_only();
let priv2 = SecretKey::from_slice(
hex_decode("619c335025c7f4012e556c2a58b2506e30b8511b53ade95ea316fd8c3286feb9")
.unwrap()
.as_slice(),
)
.unwrap();
let pub2 = bitcoin::PublicKey::from_slice(
&PublicKey::from_secret_key(&secp_ctx, &priv2).serialize(),
)
.unwrap();
let script_code = Address::p2pkh(&pub2, Network::Testnet).script_pubkey();
assert_eq!(
hex_encode(script_code.as_bytes()),
"76a9141d0f172a0ecb48aee1be1f2687d2963ae33f71a188ac"
);
let value = 600_000_000;
let sighash = &SighashCache::new(&tx)
.segwit_signature_hash(1, &script_code, value, EcdsaSighashType::All)
.unwrap()[..];
assert_eq!(
hex_encode(sighash),
"c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670"
);
}
fn vecs_match<T: PartialEq + std::cmp::Ord>(mut a: Vec<T>, mut b: Vec<T>) -> bool {
a.sort();
b.sort();
let matching = a.iter().zip(b.iter()).filter(|&(a, b)| a == b).count();
matching == a.len() && matching == b.len()
}
#[test]
fn allowlist_test() {
assert!(Allowable::from_str(
"address:mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB",
Network::Regtest
)
.is_err());
assert!(Allowable::from_str("xpub:tpubDEQBfiy13hMZzGT4NWqNnaSWwVqYQ58kuu2pDYjkrf8F6DLKAprm8c65Pyh7PrzodXHtJuEXFu5yf6JbvYaL8rz7v28zapwbuzZzr7z4UvR", Network::Regtest).is_err());
assert!(Allowable::from_str("xxx:mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB", Network::Regtest)
.is_err());
let a = Allowable::from_str("address:mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB", Network::Testnet)
.unwrap();
assert_eq!(a.to_script().unwrap().to_string(), "Script(OP_DUP OP_HASH160 OP_PUSHBYTES_20 9f9a7abd600c0caa03983a77c8c3df8e062cb2fa OP_EQUALVERIFY OP_CHECKSIG)");
let x = Allowable::from_str("xpub:tpubDEQBfiy13hMZzGT4NWqNnaSWwVqYQ58kuu2pDYjkrf8F6DLKAprm8c65Pyh7PrzodXHtJuEXFu5yf6JbvYaL8rz7v28zapwbuzZzr7z4UvR", Network::Testnet).unwrap();
assert!(x.to_script().is_err());
}
#[test]
fn node_wallet_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let a = node.get_native_address(&[0]).unwrap();
assert_eq!(a.to_string(), "tb1qr8j660jqglj0x2axua26u0qcyuxhanycx4sr49");
assert!(node.can_spend(&[0], &a.script_pubkey()).unwrap());
assert!(!node.can_spend(&[1], &a.script_pubkey()).unwrap());
let a = node.get_wrapped_address(&[0]).unwrap();
assert_eq!(a.to_string(), "2NBaG2jeH1ahh6cMcYBF1RAcZRZsTPqLNLZ");
}
#[test]
fn node_allowlist_contains_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let payee_sec = SecretKey::from_slice(&[42; 32]).unwrap();
let payee_pub = PublicKey::from_secret_key(&Secp256k1::new(), &payee_sec);
let xpub_str = "tpubDEQBfiy13hMZzGT4NWqNnaSWwVqYQ58kuu2pDYjkrf8F6DLKAprm8c65Pyh7PrzodXHtJuEXFu5yf6JbvYaL8rz7v28zapwbuzZzr7z4UvR";
node.add_allowlist(&[
"address:mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB".to_string(),
format!("xpub:{}", xpub_str),
format!("payee:{}", payee_pub.to_string()),
])
.unwrap();
let script2 =
Address::from_str("mnTkxhNkgx7TsZrEdRcPti564yQTzynGJp").unwrap().script_pubkey();
assert!(node.allowlist_contains(&script2, &[2]));
let script2 =
Address::from_str("mpW3iVi2Td1vqDK8Nfie29ddZXf9spmZkX").unwrap().script_pubkey();
assert!(!node.allowlist_contains(&script2, &[2]));
let p2wpkh_script = Address::from_str("tb1qfshzhu5qdyz94r4kylyrnlerq6mnhw3sjz7w8p")
.unwrap()
.script_pubkey();
assert!(node.allowlist_contains(&p2wpkh_script, &[2]));
}
#[test]
fn node_allowlist_test() {
fn prefix(a: &String) -> String {
format!("address:{}", a)
}
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
assert!(node.allowlist().expect("allowlist").len() == 0);
let adds0: Vec<String> = vec![
"mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB",
"2N6i2gfgTonx88yvYm32PRhnHxqxtEfocbt",
"tb1qhetd7l0rv6kca6wvmt25ax5ej05eaat9q29z7z",
"tb1qycu764qwuvhn7u0enpg0x8gwumyuw565f3mspnn58rsgar5hkjmqtjegrh",
]
.iter()
.map(|s| s.to_string())
.collect();
let prefixed_adds: Vec<String> = adds0.iter().cloned().map(|s| prefix(&s)).collect();
assert_status_ok!(node.add_allowlist(&adds0));
assert!(vecs_match(node.allowlist().expect("allowlist").clone(), prefixed_adds.clone()));
assert_status_ok!(node.add_allowlist(&adds0));
assert!(vecs_match(node.allowlist().expect("allowlist").clone(), prefixed_adds.clone()));
let removes0 = vec![adds0[0].clone(), adds0[3].clone()];
assert_status_ok!(node.remove_allowlist(&removes0));
assert!(vecs_match(
node.allowlist().expect("allowlist").clone(),
vec![prefix(&adds0[1]), prefix(&adds0[2])]
));
assert_status_ok!(node.set_allowlist(&removes0));
assert!(vecs_match(
node.allowlist().expect("allowlist").clone(),
removes0.iter().map(|e| prefix(e)).collect()
));
assert_invalid_argument_err!(
node.add_allowlist(&vec!["1234567890".to_string()]),
"could not parse 1234567890"
);
assert_invalid_argument_err!(
node.add_allowlist(&vec!["1287uUybCYgf7Tb76qnfPf8E1ohCgSZATp".to_string()]),
"could not parse 1287uUybCYgf7Tb76qnfPf8E1ohCgSZATp: expected network testnet"
);
assert_invalid_argument_err!(
node.remove_allowlist(&vec!["1287uUybCYgf7Tb76qnfPf8E1ohCgSZATp".to_string()]),
"could not parse 1287uUybCYgf7Tb76qnfPf8E1ohCgSZATp: expected network testnet"
);
}
#[test]
fn node_heartbeat_test() {
let node = init_node(TEST_NODE_CONFIG, TEST_SEED[1]);
let heartbeat = node.get_heartbeat();
let secp = Secp256k1::new();
assert!(heartbeat.verify(&node.get_account_extended_pubkey().public_key, &secp));
}
#[test]
fn cln_node_param_compatibility() {
let node = init_node(
NodeConfig::new(Network::Regtest),
"6c696768746e696e672d31000000000000000000000000000000000000000000",
);
assert_eq!(
node.get_id().serialize().to_hex(),
"0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518"
);
assert_eq!(
node.get_account_extended_pubkey().to_string(),
"tpubDBrTnjDZwRM6jznHEmo1sYqJWU9so1HRsGEWWjMKLRhVLtuCKYKaHPE3NzqFY3ZdTd64t65T8YrXZZ8Ugwkb7oNzQVBtokaAvtC8Km6EM2G");
assert_eq!(
node.get_bolt12_pubkey().serialize().to_hex(),
"02e25c37f1af7cb00984e594eae0f4d1d03537ffe202b7a6b2ebc1e5fcf1dfd9f4"
);
assert_eq!(
node.get_onion_reply_secret().to_hex(),
"cfd1fb341180bf3fa2f624ed7d4a809aedf388e3ba363c589faf341018cb83e1"
);
}
#[test]
fn serialize_heartbeat_test() {
let hb = SignedHeartbeat {
signature: vec![1, 2, 3, 4],
heartbeat: Heartbeat {
chain_tip: BlockHash::all_zeros(),
chain_height: 0,
chain_timestamp: 0,
current_timestamp: 0,
},
};
let mut ser_hb = to_vec(&hb).expect("heartbeat");
let de_hb: SignedHeartbeat = serde_bolt::from_vec(&mut ser_hb).expect("bad heartbeat");
assert_eq!(format!("{:?}", hb), format!("{:?}", de_hb));
}
}