Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
`NodeError::InvalidMnemonic` for invalid input; generated mnemonics can be converted back to a
string through their language's standard string conversion.
- `generate_entropy_mnemonic` has been removed. Use `bip39::Mnemonic::generate` in Rust and
`Mnemonic::generate` in the language bindings instead.
`Mnemonic::generate` in the language bindings instead, passing a `WordCount` variant.
`WordCount` is now re-exported from bip39 rather than defined by LDK Node.
- Migrating between storage backends does not preserve the relative creation order of
pre-existing payments, as the generic KV store migration copies entries in an unspecified
order. Expect the order in which `Node::list_payments` returns pre-existing payments to
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ bitreq = { version = "0.3", default-features = false, features = ["async-https",
rustls = { version = "0.23", default-features = false }
rusqlite = { version = "0.31.0", features = ["bundled"], optional = true }
bitcoin = "0.32.7"
bip39 = { version = "2.0.0", features = ["rand"] }
bip39 = { version = "3.0.0", features = ["rand"] }
bip21 = { version = "0.5", features = ["std"], default-features = false, optional = true }

base64 = { version = "0.22.1", default-features = false, features = ["std"] }
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The primary abstraction of the library is the [`Node`][api_docs_node], which can
```rust
use ldk_node::bitcoin::secp256k1::PublicKey;
use ldk_node::bitcoin::Network;
use ldk_node::bip39::Mnemonic;
use ldk_node::bip39::{Mnemonic, WordCount};
use ldk_node::entropy::NodeEntropy;
use ldk_node::lightning::ln::msgs::SocketAddress;
use ldk_node::lightning_invoice::Bolt11Invoice;
Expand All @@ -33,7 +33,7 @@ fn main() {
);


let mnemonic = Mnemonic::generate(24).unwrap();
let mnemonic = Mnemonic::generate(WordCount::Words24).unwrap();
let node_entropy = NodeEntropy::from_bip39_mnemonic(mnemonic, None);
let node = builder.build(node_entropy).unwrap();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ class AndroidLibTest {
val builder1 = Builder.fromConfig(config1)
val builder2 = Builder.fromConfig(config2)

val mnemonic1 = Mnemonic.generate(24u)
val mnemonic1 = Mnemonic.generate(WordCount.WORDS24)
val nodeEntropy1 = NodeEntropy.fromBip39Mnemonic(mnemonic1, null)
val node1 = builder1.build(nodeEntropy1)

val mnemonic2 = Mnemonic.generate(24u)
val mnemonic2 = Mnemonic.generate(WordCount.WORDS24)
val nodeEntropy2 = NodeEntropy.fromBip39Mnemonic(mnemonic2, null)
val node2 = builder2.build(nodeEntropy2)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,11 @@ class LibraryTest {
builder2.setChainSourceEsplora(esploraEndpoint, null)
builder2.setCustomLogger(logWriter2)

val mnemonic1 = Mnemonic.generate(24u)
val mnemonic1 = Mnemonic.generate(WordCount.WORDS24)
val nodeEntropy1 = NodeEntropy.fromBip39Mnemonic(mnemonic1, null)
val node1 = builder1.build(nodeEntropy1)

val mnemonic2 = Mnemonic.generate(24u)
val mnemonic2 = Mnemonic.generate(WordCount.WORDS24)
val nodeEntropy2 = NodeEntropy.fromBip39Mnemonic(mnemonic2, null)
val node2 = builder2.build(nodeEntropy2)

Expand Down
9 changes: 9 additions & 0 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,15 @@ typedef string UserChannelId;

typedef interface Mnemonic;

[Remote]
enum WordCount {
"Words12",
"Words15",
"Words18",
"Words21",
"Words24",
};

[Custom]
typedef string UntrustedString;

Expand Down
30 changes: 22 additions & 8 deletions bindings/python/src/ldk_node/test_ldk_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def send_to_address(address, amount_sats):


def setup_node(tmp_dir, esplora_endpoint, listening_addresses):
mnemonic = Mnemonic.generate(24)
mnemonic = Mnemonic.generate(WordCount.WORDS24)
node_entropy = NodeEntropy.from_bip39_mnemonic(mnemonic, None)
config = default_config()
builder = Builder.from_config(config)
Expand Down Expand Up @@ -206,6 +206,25 @@ def init_features_exposed(test_case, init_features):


class TestMnemonic(unittest.TestCase):
def test_mnemonic_word_counts(self):
word_count_type = globals().get("WordCount")
self.assertIsNotNone(word_count_type, "Mnemonic generation must expose WordCount")

for word_count, expected_words, expected_entropy_bytes in [
(word_count_type.WORDS12, 12, 16),
(word_count_type.WORDS15, 15, 20),
(word_count_type.WORDS18, 18, 24),
(word_count_type.WORDS21, 21, 28),
(word_count_type.WORDS24, 24, 32),
]:
with self.subTest(word_count=word_count):
mnemonic = Mnemonic.generate(word_count)
self.assertEqual(mnemonic.word_count(), expected_words)
self.assertEqual(len(mnemonic.words()), expected_words)
self.assertEqual(len(mnemonic.to_entropy()), expected_entropy_bytes)
self.assertEqual(Mnemonic.from_entropy(mnemonic.to_entropy()), mnemonic)
self.assertEqual(Mnemonic.from_str(str(mnemonic)), mnemonic)

def test_invalid_mnemonic_returns_node_error(self):
invalid_mnemonic = "abandon " * 11 + "abandon"
mnemonic_constructor = getattr(Mnemonic, "from_str", Mnemonic)
Expand All @@ -216,7 +235,7 @@ def test_invalid_mnemonic_returns_node_error(self):
self.assertIsInstance(error.exception, NodeError.InvalidMnemonic)

def test_mnemonic_round_trip(self):
mnemonic = Mnemonic.generate(24)
mnemonic = Mnemonic.generate(WordCount.WORDS24)
parsed_mnemonic = Mnemonic.from_str(str(mnemonic))

self.assertIsInstance(mnemonic, Mnemonic)
Expand All @@ -237,12 +256,7 @@ def test_mnemonic_functionality(self):
"c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e5349553"
"1f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04",
)
self.assertEqual(Mnemonic.generate(12).word_count(), 12)

with self.assertRaises(NodeError) as error:
Mnemonic.generate(13)

self.assertIsInstance(error.exception, NodeError.InvalidMnemonic)
self.assertEqual(Mnemonic.generate(WordCount.WORDS12).word_count(), 12)

with self.assertRaises(NodeError) as error:
Mnemonic.from_entropy(bytes(15))
Expand Down
2 changes: 2 additions & 0 deletions src/entropy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use std::fmt;

pub use bip39::WordCount;

use crate::config::WALLET_KEYS_SEED_LEN;
use crate::ffi::maybe_deref;
use crate::io;
Expand Down
10 changes: 4 additions & 6 deletions src/ffi/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::sync::Arc;
use std::time::Duration;

use bip39::Mnemonic as Bip39Mnemonic;
pub use bip39::WordCount;
use bitcoin::hashes::sha256::Hash as Sha256;
use bitcoin::hashes::Hash;
use bitcoin::secp256k1::PublicKey;
Expand Down Expand Up @@ -1201,10 +1202,8 @@ impl Mnemonic {

/// Generates a random English mnemonic with the specified word count.
#[uniffi::constructor]
pub fn generate(word_count: u8) -> Result<Self, Error> {
Bip39Mnemonic::generate(word_count.into())
.map(Self::from)
.map_err(|_| Error::InvalidMnemonic)
pub fn generate(word_count: WordCount) -> Result<Self, Error> {
Bip39Mnemonic::generate(word_count).map(Self::from).map_err(|_| Error::InvalidMnemonic)
}

/// Returns the words in the mnemonic.
Expand Down Expand Up @@ -3031,8 +3030,7 @@ mod tests {
assert_eq!(mnemonic.to_entropy(), entropy);
assert_eq!(mnemonic.checksum(), 3);
assert_eq!(mnemonic.to_seed("TREZOR").len(), 64);
assert_eq!(Mnemonic::generate(12).unwrap().word_count(), 12);
assert_eq!(Mnemonic::generate(13), Err(Error::InvalidMnemonic));
assert_eq!(Mnemonic::generate(WordCount::Words12).unwrap().word_count(), 12);
assert_eq!(Mnemonic::from_entropy(&[0; 15]), Err(Error::InvalidMnemonic));
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
//! # {
//! use std::str::FromStr;
//!
//! use ldk_node::bip39::Mnemonic;
//! use ldk_node::bip39::{Mnemonic, WordCount};
//! use ldk_node::bitcoin::secp256k1::PublicKey;
//! use ldk_node::bitcoin::Network;
//! use ldk_node::entropy::NodeEntropy;
Expand All @@ -43,7 +43,7 @@
//! "https://rapidsync.lightningdevkit.org/testnet/v2/snapshot".to_string(),
//! );
//!
//! let mnemonic = Mnemonic::generate(24).unwrap();
//! let mnemonic = Mnemonic::generate(WordCount::Words24).unwrap();
//! let node_entropy = NodeEntropy::from_bip39_mnemonic(mnemonic, None);
//! let node = builder.build(node_entropy).unwrap();
//!
Expand Down Expand Up @@ -2267,7 +2267,7 @@ impl Node {
/// # use ldk_node::config::Config;
/// # use ldk_node::payment::{PaymentDetails, PaymentDirection};
/// # use ldk_node::bitcoin::Network;
/// # use ldk_node::bip39::Mnemonic;
/// # use ldk_node::bip39::{Mnemonic, WordCount};
/// # use ldk_node::entropy::NodeEntropy;
/// # use rand::distr::Alphanumeric;
/// # use rand::{rng, Rng};
Expand All @@ -2278,7 +2278,7 @@ impl Node {
/// # temp_path.push(rand_dir);
/// # config.storage_dir_path = temp_path.display().to_string();
/// # let builder = Builder::from_config(config);
/// # let mnemonic = Mnemonic::generate(24).unwrap();
/// # let mnemonic = Mnemonic::generate(WordCount::Words24).unwrap();
/// # let node_entropy = NodeEntropy::from_bip39_mnemonic(mnemonic, None);
/// # let node = builder.build(node_entropy.into()).unwrap();
/// let mut outbound = Vec::new();
Expand Down
4 changes: 2 additions & 2 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use bitcoin::{
use electrsd::corepc_node::{Client as BitcoindClient, Node as BitcoinD};
use electrsd::electrum_client::ElectrumApi;
use electrsd::{corepc_node, ElectrsD};
use ldk_node::bip39::Mnemonic;
use ldk_node::bip39::{Mnemonic, WordCount};
#[cfg(feature = "chain-electrum")]
use ldk_node::config::ElectrumSyncConfig;
#[cfg(feature = "chain-esplora")]
Expand Down Expand Up @@ -683,7 +683,7 @@ impl Default for TestConfig {
let log_writer = Default::default();
let store_type = Default::default();

let mnemonic = Mnemonic::generate(24).unwrap();
let mnemonic = Mnemonic::generate(WordCount::Words24).unwrap();
#[cfg(not(feature = "uniffi"))]
let node_entropy = NodeEntropy::from_bip39_mnemonic(mnemonic, None);
#[cfg(feature = "uniffi")]
Expand Down
Loading