Test that HSM daemon creates deterministic node IDs in new mnemonic format
(node_factory)
| 1691 | |
| 1692 | |
| 1693 | def test_hsmtool_deterministic_node_ids(node_factory): |
| 1694 | """Test that HSM daemon creates deterministic node IDs in new mnemonic format""" |
| 1695 | # Create a node and start it to trigger HSM daemon to create new format |
| 1696 | l1 = node_factory.get_node(start=False) |
| 1697 | hsm_path = os.path.join(l1.daemon.lightning_dir, TEST_NETWORK, "hsm_secret") |
| 1698 | |
| 1699 | # Delete any existing hsm_secret so HSM daemon creates it in new format |
| 1700 | if os.path.exists(hsm_path): |
| 1701 | os.remove(hsm_path) |
| 1702 | |
| 1703 | # Start the node to get its node ID (this will create a new hsm_secret in new format) |
| 1704 | l1.start() |
| 1705 | normal_node_id = l1.rpc.getinfo()['id'] |
| 1706 | l1.stop() |
| 1707 | |
| 1708 | # Verify the hsm_secret was created in the new mnemonic format |
| 1709 | with open(hsm_path, 'rb') as f: |
| 1710 | content = f.read() |
| 1711 | # Should be longer than 32 bytes (new format has 32-byte hash + mnemonic) |
| 1712 | assert len(content) > 32, f"Expected new mnemonic format, got {len(content)} bytes" |
| 1713 | |
| 1714 | # First 32 bytes should be the passphrase hash (likely zeros for no passphrase) |
| 1715 | passphrase_hash = content[:32] |
| 1716 | assert passphrase_hash == b'\x00' * 32 |
| 1717 | mnemonic_bytes = content[32:] |
| 1718 | |
| 1719 | # Decode the mnemonic bytes |
| 1720 | mnemonic = mnemonic_bytes.decode('utf-8').strip() |
| 1721 | |
| 1722 | # Verify it's a valid mnemonic (should be 12 words) |
| 1723 | words = mnemonic.split() |
| 1724 | assert len(words) == 12, f"Expected 12 words, got {len(words)}: {mnemonic}" |
| 1725 | |
| 1726 | # Create a second node and use generatehsm with the mnemonic from the first node |
| 1727 | l2 = node_factory.get_node(start=False) |
| 1728 | hsm_path2 = os.path.join(l2.daemon.lightning_dir, TEST_NETWORK, "hsm_secret") |
| 1729 | |
| 1730 | # Delete any existing hsm_secret for the second node |
| 1731 | if os.path.exists(hsm_path2): |
| 1732 | os.remove(hsm_path2) |
| 1733 | |
| 1734 | # Generate hsm_secret with the mnemonic from the first node |
| 1735 | hsmtool = HsmTool(node_factory.directory, "generatehsm", hsm_path2) |
| 1736 | master_fd, slave_fd = os.openpty() |
| 1737 | hsmtool.start(stdin=slave_fd) |
| 1738 | hsmtool.wait_for_log(r"Introduce your BIP39 word list") |
| 1739 | write_all(master_fd, f"{mnemonic}\n".encode("utf-8")) |
| 1740 | hsmtool.wait_for_log(r"Enter your passphrase:") |
| 1741 | write_all(master_fd, "\n".encode("utf-8")) |
| 1742 | assert hsmtool.proc.wait(WAIT_TIMEOUT) == 0 |
| 1743 | |
| 1744 | # Get the node ID from the generated hsm_secret |
| 1745 | cmd_line = ["tools/lightning-hsmtool", "getnodeid", hsm_path2] |
| 1746 | generated_node_id = subprocess.check_output(cmd_line).decode("utf8").strip() |
| 1747 | |
| 1748 | # Verify both node IDs are identical |
| 1749 | assert normal_node_id == generated_node_id, f"Node IDs don't match: {normal_node_id} != {generated_node_id}" |
| 1750 |
nothing calls this directly
no test coverage detected