Register a node
In this section we'll use a developer certificate to register a node.
We'll start with creating a seed that is used to derive node-secrets from. Each node on the lightning network is identified by a public key and the corresponding private key is one of these secrets. In the next step, we'll connect to the Scheduler using a developer identity and register the node. This requires you to prove that you own the private key mentioned previously.
At the end of this section your node will be registered on Greenlight and you will have a device-identity that can be used to connect the node.
Creating a seed
Let's start with the seed secret: the seed secret is a 32 byte secret that all other secrets and private keys are derived from, as such it is paramount that this secret never leaves your user's device and is only handled by the Signer.
We suggest to derive the seed secret from a BIP 39 seed phrase, so the user can back it up on a physical piece of paper, steel plate, or whatever creative way of storing it they can think of.
Note
The following code-snippets build on each other. By copying each snippet after the other you should get a working example. See the getting started project in examples to view the code in one file.
Install the bip39
and rand
crates required for secure randomness and conversion of mnemonics. Add the following lines to your Cargo.toml
[dependencies]
rand = "*"
bip39 = { version = "*", features=["rand_core"] }
Install the bip39
package which we'll use to encode the
seed secret as a seed phrase:
pip install bip39
Now we can securely generate some randomness, encode it as BIP 39 phrase and then convert it into a seed secret we can use:
let mut rng = rand::thread_rng();
let m = Mnemonic::generate_in_with(&mut rng, Language::English, 24).unwrap();
//Show seed phrase to user
let _phrase = m.word_iter().fold("".to_string(), |c, n| c + " " + n);
const EMPTY_PASSPHRASE: &str = "";
let seed = &m.to_seed(EMPTY_PASSPHRASE)[0..32]; // Only need the first 32 bytes
// Store the seed on the filesystem, or secure configuration system
save_to_file("seed", seed.to_vec());
rand = secrets.randbits(256).to_bytes(32, "big") # 32 bytes of randomness
# Show seed phrase to user
phrase = bip39.encode_bytes(rand)
seed = bip39.phrase_to_seed(phrase)[:32] # Only need the first 32 bytes
# Store the seed on the filesystem, or secure configuration system
save_to_file("seed", seed)
Important
Remember to store the seed somewhere (file on disk, registry, etc) because without it, you will not have access to the node, and any funds on the node will be lost forever! We mean it when we say you're the only one with access to the seed!
Initializing the signer
To initialize a signer we'll first need to configure Nobody
credentials so we can talk to the scheduler using mTLS. Nobody credentials require data from the files downloaded from the Greenlight Developer Console, so the files must be accessible from wherever the node registration program is run. Any connection using the
developer_creds
object will allow you to register new Greenlight
nodes.
let developer_cert = std::fs::read(developer_cert_path).unwrap_or_default();
let developer_key = std::fs::read(developer_key_path).unwrap_or_default();
let developer_creds = Nobody {
cert: developer_cert,
key: developer_key,
..Nobody::default()
};
developer_cert = Path(developer_cert_path).open(mode="rb").read()
developer_key = Path(developer_key_path).open(mode="rb").read()
developer_creds = Credentials.nobody_with(developer_cert, developer_key)
The next step is to create the Signer
which processes incoming signature
requests, and is used when registering a node to prove ownership of
the private key. The last thing to decide is which network we want the
node to run on. You can chose between the following networks:
testnet
bitcoin
We'll pick bitcoin
, because ... reckless 😉
let network = Network::Bitcoin;
let signer = Signer::new(seed, network, developer_creds.clone()).unwrap();
network = "bitcoin"
signer = Signer(seed, network, developer_creds)
Registering a new node
Registering a node with the Scheduler
creates the node on the
Greenlight service and ensures everything is setup to start the node.
In order to register a node, the client needs to prove it has access to the
node's private key. Since the private key is managed exclusively by the
Signer
we need to pass the Signer
to the
Scheduler
:
let scheduler = Scheduler::new(network, developer_creds).await.unwrap();
// Passing in the signer is required because the client needs to prove
// ownership of the `node_id`
let registration_response = scheduler.register(&signer, None).await.unwrap();
let device_creds = Device::from_bytes(registration_response.creds);
save_to_file("creds", device_creds.to_bytes());
scheduler = Scheduler(network, developer_creds)
# Passing in the signer is required because the client needs to prove
# ownership of the `node_id`
registration_response = scheduler.register(signer, invite_code=None)
device_creds = Credentials.from_bytes(registration_response.creds)
save_to_file("creds", device_creds.to_bytes())
The result of register
contains the credentials that can be used
going forward to talk to the scheduler and the node itself.
Important
Please make sure to store them somewhere safe, since anyone with these credentials can access your node.
let scheduler = scheduler.authenticate(device_creds).await.unwrap();
let _node: ClnClient = scheduler.node().await.unwrap();
scheduler = scheduler.authenticate(device_creds)
node = scheduler.node()
If you get an error about a certificate verification failure when
talking to the node, you most likely are using an unconfigured
TlsConfig
that doesn't have access to the node. See
Security for details on how authentication and
authorization work under the hood.