Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI Host, port, and token can be set at runtime #62

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

litch
Copy link

@litch litch commented Apr 25, 2022

Ok, this is my re-attempt at making the CLI work again

% cargo run --bin senseicli -- --node 0090a039-f1dd-4daa-a7e1-1446f9c9bbae --token 8d55f4eaba224b78788c866
a3be09f8c7dc0c2def0a57e9a55e658ac95689b17 nodeinfo

InfoResponse { node_info: Some(Info { node_pubkey: "02ccd784d90a263c60c50b248d0234e4ecf52a221438b2c525765072af4fb20de5", num_channels: 1, num_usable_channels: 1, num_peers: 1 }) }

It feels pretty verbose to put all that on the CLI, but this actually gets the CLI back to a working state. I'm seeing unrelated errors it looks with listchannels returning an empty set, but the other node can see my channel, and the nodeinfo command shows an active channel (as above). But this gets it to working

@johncantrell97
Copy link
Contributor

Getting closer! You shouldn't need (or require) the admin access token for accessing the individual node apis as those are completely authenticated by the macaroon.

Happy to merge this since it's completely broken in main at the moment but I still think the better path forward is to probably write out the 'admin access token' to filesystem in DATA_DIR/NEWORK/access.token or some fixed path based on data directory and network.

It can try to read it from that path if it's not provided as a cli arg.

Once the database work I'm doing lands I don't think there will even be these node directories anymore since there'll be a single database for all the nodes. Will probably make this simpler so maybe we don't take the cli too far until that lands.

@litch
Copy link
Author

litch commented Apr 25, 2022

Yes! I was looking at segmenting off the AdminClient api calls (init, start, create_node, list_nodes, to “want” separate data).

@litch
Copy link
Author

litch commented Apr 27, 2022

Ok, I've done a bit of restructuring, and thinking, and going to do a bit more restructuring -

[ ] - The ListNodes command should list the nodes
[ ] - Admin token is written to the caller filesystem

@litch
Copy link
Author

litch commented Apr 30, 2022

This turned into a bit of a mess. Sorry. I may re-do it once I have a better feel for what I'm actually trying to accomplish. I've discovered several error states I could put my system into, and trying to help them recover. Trying to add some instrumentation and such to help with debugging. Not sure that it's all totally appropriate in a "repair the CLI" bit of work, and almost certainly not worth doing if I'm just trying to get a few methods looking better. So probably worth making a decision about "smallest mergable/usable" piece of work and go from there.

use crate::sensei::{
CloseChannelRequest, ConnectPeerRequest, CreateAdminRequest, CreateInvoiceRequest,
CreateNodeRequest, GetUnusedAddressRequest, InfoRequest, KeysendRequest, ListChannelsRequest,
ListNodesRequest, ListPaymentsRequest, ListPeersRequest, OpenChannelRequest, PayInvoiceRequest,
SignMessageRequest, StartAdminRequest, StartNodeRequest,
SignMessageRequest, StartAdminRequest, StartNodeRequest, PaginationRequest
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed (I think) in order to make the CLI actually be able to send paginated requests (which allows, the list of nodes to be more than 0 items long).

@@ -35,14 +39,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.version("1.0")
.author("John Cantrell <[email protected]>")
.about("Control your sensei node from a cli")
.arg(
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed all the CLI knowing about the node data directory.

@@ -51,6 +47,37 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.help("Sets the node to issue commands to")
.takes_value(true),
)
.arg(
Arg::new("token")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The token is now passed in on the CLI, along with host and port.

@@ -83,6 +110,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
.required(true)
.index(2)
.help("alias to use for this lightning node"),
)
.arg(
Arg::new("start")
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows the create child node to pass the start value as well.

.connect()
.await?;
// This is only needed for a couple of queries. Disabling pagination effectively by large get
let pagination = PaginationRequest {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generally prefer pull request documentation/explanation for potentially surprising things, rather than comments, since comments tend to be lies waiting to happen, but put the explanatory comment there just in case. LMK if you'd like it out.


let message = response.into_inner();

let mut config = NodeConfig {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After we get the node created back from senseid, save that data to the local (to the CLI) filesystem for future use. I'm not exactly sure the best place to put this data_dir and would appreciate some input.

}
}

// I could not figure out how to improt this from the database/admin
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be easy to import this Role from the database::admin but for whatever reason I just couldn't make it happen.

@@ -360,10 +361,21 @@ impl AdminDatabase {
":pubkey": node.pubkey,
":status": node.status
})?;

dbg!("Wrote node to the database");
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove some of these dbg!s. I went a little crazy with them trying to understand why the code was failing.

Ok(self.connection.last_insert_rowid())
}

pub fn clear_pending_node(&mut self) -> Result<(), Error> {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is an error state I could pretty reliably put my system into.

Basically it goes

  • Create node in the sensei sqlite DB (empty string pubkey)
  • Create the actual lightning node (gets a pubkey)
  • Update the sensei sqlite record with the pubkey

If there was ever a problem creating the node in the lightning node or updating the sqlite record, then there is an existing empty-string-for-a-pubkey "node" that's basically WIP for the system, but a new node can never be created because it can't write any more "new node with empty string pubkey". So I made this to be able to "clean up after itself."

I actually think that's probably a wrong approach, and we should have a different table for like, "nodes to create" and then a "nodes created" and it's not just, "update the node record in place with a pubkey", but that's a bit larger scope.

statement.execute(named_params! {
":blank": "",
})?;
dbg!("I deleted the node with no pubkey because it sucks!");
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooops, will pull this.

@@ -376,7 +388,7 @@ impl AdminDatabase {
":pubkey": node.pubkey,
":status": node.status
})?;

dbg!("Ok now I just wrote a node update. It probably has a pubkey");
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO remove

@@ -8,6 +8,7 @@
// licenses.

use std::sync::Arc;
use tracing::{instrument, info, error, debug};
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how you feel about tracing/logging, but it seems like we need to get some kind of structured something in here. This library feels pretty fantastic for doing it. We can pull it back out for something better, but it felt good to me to use.

node.id = database.create_node(node.clone())
.map_err(|err| {
error!("Unable to create node in Sensei Database");
database.clear_pending_node();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a "Cleaning up after myself" I mentioned before. I got pretty good at putting my instance in this broken state.


let lightning_node = self.get_node(node.clone(), passphrase).await?;
let lightning_node = self.get_node(node.clone(), passphrase).await.unwrap();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the explicit unwrap here because it felt like a panic at this stage, if it failed, is pretty acceptable. Not sure - the previous behavior was, "Fail silently" and this seems better but not necessarily optimal.

node.pubkey = lightning_node.node_info()?.node_pubkey;

dbg!("I have a pubkey even {:?}", node.pubkey.clone());
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Todo remove

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants