[[package]]
name = "lightning"
-version = "0.0.115"
+version = "0.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e009e1c0c21f66378b491bb40f548682138c63e09db6f3a05af59f8804bb9f4a"
+checksum = "90a0f2155316f1570446a0447c993480673f840748c8ed25bbc59dfc442ac770"
dependencies = [
"bitcoin",
]
[[package]]
name = "lightning-background-processor"
-version = "0.0.115"
+version = "0.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "721b05b9848a09d5b943915449b5ffb31e24708007763640cf9d79b124a17e19"
+checksum = "398b68a96cceb3c1227504bd5faeb74f26c3233447bc10cc1cb2c67e01b51556"
dependencies = [
"bitcoin",
"lightning",
[[package]]
name = "lightning-block-sync"
-version = "0.0.115"
+version = "0.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c60cf241b3c219ee865aad91eab85a879b23c1756a335a5a311790ad6c1c3d2"
+checksum = "d94c276dbe2a777d58ed6ececca96006247a4717c00ac4cdfff62d76852be783"
dependencies = [
"bitcoin",
"chunked_transfer",
[[package]]
name = "lightning-invoice"
-version = "0.23.0"
+version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4e44b0e2822c8811470137d2339fdfe67a699b3248bb1606d1d02eb6a1e9f0a"
+checksum = "1788c0158526ec27a502043c2911ea6ea58fdc656bdf8749484942c07b790d23"
dependencies = [
"bech32 0.9.1",
"bitcoin",
[[package]]
name = "lightning-net-tokio"
-version = "0.0.115"
+version = "0.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4561ec5d4df2dd410a8b80955791fcfb007ef9210395db6e914b9527397b868c"
+checksum = "366c0ae225736cbc03555bd5fb4b44b2e8fe2ca3c868ec53a4b325c38b2ab2bd"
dependencies = [
"bitcoin",
"lightning",
[[package]]
name = "lightning-persister"
-version = "0.0.115"
+version = "0.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c52ed57ec33fb945f464b7e91b5df49f49fec649e1b44909f3ce517e96b0449a"
+checksum = "93caaafeb42115b70119619c2420e362cce776670427fc4ced3e6df77b41c0b6"
dependencies = [
"bitcoin",
"libc",
[[package]]
name = "lightning-rapid-gossip-sync"
-version = "0.0.115"
+version = "0.0.116"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd84d74a9b3892db22a60ac11dfc12e76b257b3174db6743e818ecc24834f3be"
+checksum = "8a07af5814234924e623bca499e003fca1864024d5bd984e752230f73a131584"
dependencies = [
"bitcoin",
"lightning",
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-lightning = { version = "0.0.115", features = ["max_level_trace"] }
-lightning-block-sync = { version = "0.0.115", features = [ "rpc-client" ] }
-lightning-invoice = { version = "0.23" }
-lightning-net-tokio = { version = "0.0.115" }
-lightning-persister = { version = "0.0.115" }
-lightning-background-processor = { version = "0.0.115", features = [ "futures" ] }
-lightning-rapid-gossip-sync = { version = "0.0.115" }
+lightning = { version = "0.0.116", features = ["max_level_trace"] }
+lightning-block-sync = { version = "0.0.116", features = [ "rpc-client" ] }
+lightning-invoice = { version = "0.24.0" }
+lightning-net-tokio = { version = "0.0.116" }
+lightning-persister = { version = "0.0.116" }
+lightning-background-processor = { version = "0.0.116", features = [ "futures" ] }
+lightning-rapid-gossip-sync = { version = "0.0.116" }
base64 = "0.13.0"
bitcoin = "0.29.0"
-use crate::convert::{BlockchainInfo, FeeResponse, FundedTx, NewAddress, RawTx, SignedTx};
+use crate::convert::{
+ BlockchainInfo, FeeResponse, FundedTx, MempoolMinFeeResponse, NewAddress, RawTx, SignedTx,
+};
use crate::disk::FilesystemLogger;
use base64;
use bitcoin::blockdata::transaction::Transaction;
#[derive(Clone, Eq, Hash, PartialEq)]
pub enum Target {
+ MempoolMinimum,
Background,
Normal,
HighPriority,
"Failed to make initial call to bitcoind - please check your RPC user/password and access settings")
})?;
let mut fees: HashMap<Target, AtomicU32> = HashMap::new();
+ fees.insert(Target::MempoolMinimum, AtomicU32::new(MIN_FEERATE));
fees.insert(Target::Background, AtomicU32::new(MIN_FEERATE));
fees.insert(Target::Normal, AtomicU32::new(2000));
fees.insert(Target::HighPriority, AtomicU32::new(5000));
) {
handle.spawn(async move {
loop {
+ let mempoolmin_estimate = {
+ let resp = rpc_client
+ .call_method::<MempoolMinFeeResponse>("getmempoolinfo", &vec![])
+ .await
+ .unwrap();
+ match resp.feerate_sat_per_kw {
+ Some(feerate) => std::cmp::max(feerate, MIN_FEERATE),
+ None => MIN_FEERATE,
+ }
+ };
let background_estimate = {
let background_conf_target = serde_json::json!(144);
let background_estimate_mode = serde_json::json!("ECONOMICAL");
}
};
+ fees.get(&Target::MempoolMinimum)
+ .unwrap()
+ .store(mempoolmin_estimate, Ordering::Release);
fees.get(&Target::Background)
.unwrap()
.store(background_estimate, Ordering::Release);
impl FeeEstimator for BitcoindClient {
fn get_est_sat_per_1000_weight(&self, confirmation_target: ConfirmationTarget) -> u32 {
match confirmation_target {
+ ConfirmationTarget::MempoolMinimum => {
+ self.fees.get(&Target::MempoolMinimum).unwrap().load(Ordering::Acquire)
+ }
ConfirmationTarget::Background => {
self.fees.get(&Target::Background).unwrap().load(Ordering::Acquire)
}
}
impl BroadcasterInterface for BitcoindClient {
- fn broadcast_transaction(&self, tx: &Transaction) {
- let bitcoind_rpc_client = self.bitcoind_rpc_client.clone();
- let tx_serialized = encode::serialize_hex(tx);
- let tx_json = serde_json::json!(tx_serialized);
- let logger = Arc::clone(&self.logger);
- self.handle.spawn(async move {
- // This may error due to RL calling `broadcast_transaction` with the same transaction
- // multiple times, but the error is safe to ignore.
- match bitcoind_rpc_client
- .call_method::<Txid>("sendrawtransaction", &vec![tx_json])
- .await
- {
- Ok(_) => {}
- Err(e) => {
- let err_str = e.get_ref().unwrap().to_string();
- log_error!(logger,
- "Warning, failed to broadcast a transaction, this is likely okay but may indicate an error: {}\nTransaction: {}",
- err_str,
- tx_serialized);
- print!("Warning, failed to broadcast a transaction, this is likely okay but may indicate an error: {}\n> ", err_str);
- }
- }
- });
+ fn broadcast_transactions(&self, txs: &[&Transaction]) {
+ // TODO: Rather than calling `sendrawtransaction` in a a loop, we should probably use
+ // `submitpackage` once it becomes available.
+ for tx in txs {
+ let bitcoind_rpc_client = Arc::clone(&self.bitcoind_rpc_client);
+ let tx_serialized = encode::serialize_hex(tx);
+ let tx_json = serde_json::json!(tx_serialized);
+ let logger = Arc::clone(&self.logger);
+ self.handle.spawn(async move {
+ // This may error due to RL calling `broadcast_transactions` with the same transaction
+ // multiple times, but the error is safe to ignore.
+ match bitcoind_rpc_client
+ .call_method::<Txid>("sendrawtransaction", &vec![tx_json])
+ .await
+ {
+ Ok(_) => {}
+ Err(e) => {
+ let err_str = e.get_ref().unwrap().to_string();
+ log_error!(logger,
+ "Warning, failed to broadcast a transaction, this is likely okay but may indicate an error: {}\nTransaction: {}",
+ err_str,
+ tx_serialized);
+ print!("Warning, failed to broadcast a transaction, this is likely okay but may indicate an error: {}\n> ", err_str);
+ }
+ }
+ });
+ }
}
}
use bitcoin::hashes::Hash;
use bitcoin::network::constants::Network;
use bitcoin::secp256k1::PublicKey;
-use lightning::chain::keysinterface::{EntropySource, KeysManager};
use lightning::ln::channelmanager::{PaymentId, RecipientOnionFields, Retry};
use lightning::ln::msgs::NetAddress;
use lightning::ln::{PaymentHash, PaymentPreimage};
+use lightning::onion_message::OnionMessagePath;
use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMessageContents};
use lightning::routing::gossip::NodeId;
use lightning::routing::router::{PaymentParameters, RouteParameters};
+use lightning::sign::{EntropySource, KeysManager};
use lightning::util::config::{ChannelHandshakeConfig, ChannelHandshakeLimits, UserConfig};
use lightning::util::persist::KVStorePersister;
use lightning::util::ser::{Writeable, Writer};
use lightning_invoice::payment::pay_invoice;
-use lightning_invoice::{utils, Currency, Invoice};
+use lightning_invoice::{utils, Bolt11Invoice, Currency};
use lightning_persister::FilesystemPersister;
use std::env;
use std::io;
continue;
}
- let invoice = match Invoice::from_str(invoice_str.unwrap()) {
+ let invoice = match Bolt11Invoice::from_str(invoice_str.unwrap()) {
Ok(inv) => inv,
Err(e) => {
println!("ERROR: invalid invoice: {:?}", e);
);
continue;
}
- let mut node_pks = Vec::new();
+ let mut intermediate_nodes = Vec::new();
let mut errored = false;
for pk_str in path_pks_str.unwrap().split(",") {
let node_pubkey_vec = match hex_utils::to_vec(pk_str) {
break;
}
};
- node_pks.push(node_pubkey);
+ intermediate_nodes.push(node_pubkey);
}
if errored {
continue;
continue;
}
};
- let destination_pk = node_pks.pop().unwrap();
+ let destination = Destination::Node(intermediate_nodes.pop().unwrap());
+ let message_path = OnionMessagePath { intermediate_nodes, destination };
match onion_messenger.send_onion_message(
- &node_pks,
- Destination::Node(destination_pk),
+ message_path,
OnionMessageContents::Custom(UserOnionMessageContents { tlv_type, data }),
None,
) {
}
fn send_payment(
- channel_manager: &ChannelManager, invoice: &Invoice,
+ channel_manager: &ChannelManager, invoice: &Bolt11Invoice,
outbound_payments: &mut PaymentInfoStorage, persister: Arc<FilesystemPersister>,
) {
let payment_hash = PaymentHash((*invoice.payment_hash()).into_inner());
let payment_hash = PaymentHash(Sha256::hash(&payment_preimage.0[..]).into_inner());
let route_params = RouteParameters {
- payment_params: PaymentParameters::for_keysend(payee_pubkey, 40),
+ payment_params: PaymentParameters::for_keysend(payee_pubkey, 40, false),
final_value_msat: amt_msat,
};
outbound_payments.payments.insert(
}
}
+pub struct MempoolMinFeeResponse {
+ pub feerate_sat_per_kw: Option<u32>,
+ pub errored: bool,
+}
+
+impl TryInto<MempoolMinFeeResponse> for JsonResponse {
+ type Error = std::io::Error;
+ fn try_into(self) -> std::io::Result<MempoolMinFeeResponse> {
+ let errored = !self.0["errors"].is_null();
+ assert_eq!(self.0["maxmempool"].as_u64(), Some(300000000));
+ Ok(MempoolMinFeeResponse {
+ errored,
+ feerate_sat_per_kw: match self.0["mempoolminfee"].as_f64() {
+ // Bitcoin Core gives us a feerate in BTC/KvB, which we need to convert to
+ // satoshis/KW. Thus, we first multiply by 10^8 to get satoshis, then divide by 4
+ // to convert virtual-bytes into weight units.
+ Some(feerate_btc_per_kvbyte) => {
+ Some((feerate_btc_per_kvbyte * 100_000_000.0 / 4.0).round() as u32)
+ }
+ None => None,
+ },
+ })
+ }
+}
+
pub struct BlockchainInfo {
pub latest_height: usize,
pub latest_blockhash: BlockHash,
use bitcoin::secp256k1::PublicKey;
use bitcoin::Network;
use chrono::Utc;
-use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringDecayParameters};
use lightning::util::logger::{Logger, Record};
use lightning::util::ser::{Readable, ReadableArgs, Writer};
use std::collections::HashMap;
pub(crate) fn read_scorer(
path: &Path, graph: Arc<NetworkGraph>, logger: Arc<FilesystemLogger>,
) -> ProbabilisticScorer<Arc<NetworkGraph>, Arc<FilesystemLogger>> {
- let params = ProbabilisticScoringParameters::default();
+ let params = ProbabilisticScoringDecayParameters::default();
if let Ok(file) = File::open(path) {
let args = (params.clone(), Arc::clone(&graph), Arc::clone(&logger));
if let Ok(scorer) = ProbabilisticScorer::read(&mut BufReader::new(file), args) {
use bitcoin::BlockHash;
use bitcoin_bech32::WitnessProgram;
use disk::{INBOUND_PAYMENTS_FNAME, OUTBOUND_PAYMENTS_FNAME};
-use lightning::chain::keysinterface::{
- EntropySource, InMemorySigner, KeysManager, SpendableOutputDescriptor,
-};
use lightning::chain::{chainmonitor, ChannelMonitorUpdateStatus};
use lightning::chain::{Filter, Watch};
use lightning::events::{Event, PaymentFailureReason, PaymentPurpose};
use lightning::ln::msgs::DecodeError;
use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler, SimpleArcPeerManager};
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
-use lightning::onion_message::SimpleArcOnionMessenger;
+use lightning::onion_message::{DefaultMessageRouter, SimpleArcOnionMessenger};
use lightning::routing::gossip;
use lightning::routing::gossip::{NodeId, P2PGossipSync};
use lightning::routing::router::DefaultRouter;
+use lightning::routing::scoring::ProbabilisticScoringFeeParameters;
+use lightning::sign::{EntropySource, InMemorySigner, KeysManager, SpendableOutputDescriptor};
use lightning::util::config::UserConfig;
use lightning::util::persist::KVStorePersister;
use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer};
via_user_channel_id: _,
claim_deadline: _,
onion_fields: _,
+ counterparty_skimmed_fee_msat: _,
} => {
println!(
"\nEVENT: received payment from payment hash {} of {} millisatoshis",
// the funding transaction either confirms, or this event is generated.
}
Event::HTLCIntercepted { .. } => {}
+ Event::BumpTransaction(_) => {}
}
}
)));
// Step 10: Create Router
+ let scoring_fee_params = ProbabilisticScoringFeeParameters::default();
let router = Arc::new(DefaultRouter::new(
network_graph.clone(),
logger.clone(),
keys_manager.get_secure_random_bytes(),
scorer.clone(),
+ scoring_fee_params,
));
// Step 11: Initialize the ChannelManager
keys_manager.clone(),
user_config,
chain_params,
+ cur.as_secs() as u32,
);
(polled_best_block_hash, fresh_channel_manager)
}
Arc::clone(&keys_manager),
Arc::clone(&keys_manager),
Arc::clone(&logger),
+ Arc::new(DefaultMessageRouter {}),
+ IgnoringMessageHandler {},
IgnoringMessageHandler {},
));
let mut ephemeral_bytes = [0; 32];
chan_handler: channel_manager.clone(),
route_handler: gossip_sync.clone(),
onion_message_handler: onion_messenger.clone(),
+ custom_message_handler: IgnoringMessageHandler {},
};
let peer_manager: Arc<PeerManager> = Arc::new(PeerManager::new(
lightning_msg_handler,
current_time.try_into().unwrap(),
&ephemeral_bytes,
logger.clone(),
- IgnoringMessageHandler {},
Arc::clone(&keys_manager),
));
Arc::clone(&logger),
Arc::clone(&persister),
Arc::clone(&bitcoind_client),
+ Arc::clone(&channel_manager),
));
// Start the CLI.
use std::{fs, io};
use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator};
-use lightning::chain::keysinterface::{EntropySource, KeysManager, SpendableOutputDescriptor};
+use lightning::sign::{EntropySource, KeysManager, SpendableOutputDescriptor};
use lightning::util::logger::Logger;
use lightning::util::persist::KVStorePersister;
use lightning::util::ser::{Readable, WithoutLength};
use bitcoin::secp256k1::Secp256k1;
+use bitcoin::{LockTime, PackedLockTime};
use crate::hex_utils;
use crate::BitcoindClient;
+use crate::ChannelManager;
use crate::FilesystemLogger;
use crate::FilesystemPersister;
pub(crate) async fn periodic_sweep(
ldk_data_dir: String, keys_manager: Arc<KeysManager>, logger: Arc<FilesystemLogger>,
persister: Arc<FilesystemPersister>, bitcoind_client: Arc<BitcoindClient>,
+ channel_manager: Arc<ChannelManager>,
) {
// Regularly claim outputs which are exclusively spendable by us and send them to Bitcoin Core.
// Note that if you more tightly integrate your wallet with LDK you may not need to do this -
let output_descriptors = &outputs.iter().map(|a| a).collect::<Vec<_>>();
let tx_feerate =
bitcoind_client.get_est_sat_per_1000_weight(ConfirmationTarget::Background);
+
+ // We set nLockTime to the current height to discourage fee sniping.
+ let cur_height = channel_manager.current_best_block().height();
+ let locktime: PackedLockTime =
+ LockTime::from_height(cur_height).map_or(PackedLockTime::ZERO, |l| l.into());
+
if let Ok(spending_tx) = keys_manager.spend_spendable_outputs(
output_descriptors,
Vec::new(),
destination_address.script_pubkey(),
tx_feerate,
+ Some(locktime),
&Secp256k1::new(),
) {
// Note that, most likely, we've already sweeped this set of outputs
// and they're already confirmed on-chain, so this broadcast will fail.
- bitcoind_client.broadcast_transaction(&spending_tx);
+ bitcoind_client.broadcast_transactions(&[&spending_tx]);
} else {
lightning::log_error!(
logger,