-
Notifications
You must be signed in to change notification settings - Fork 29
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
Allows using aliases within the config file #103
Allows using aliases within the config file #103
Conversation
@carlaKC @okjodom I've added the changes to allow aliases to be used as ids in the config file (check 8b65670 for the code and rationale). Looking for an Approach ACK/ tACK of this before moving along with the logging, given the data passed to the simulator to be able to handle logging both PKs and aliases is dependant on how we approach this. |
47d831d
to
e2d5fb3
Compare
sim-lib/src/lnd.rs
Outdated
))); | ||
} | ||
} | ||
crate::NodeId::Alias(a) => alias = a, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we assert that pubkey used as ID must match the node pubkey, but for the alias, we prefer the user provided value, ignoring the actual node alias
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a conversation w/ @carlaKC regarding this. We argued that the "alias" provided by the user can be anything, and does not really have to match the node alias, but in case it is not defined, we can default to that (tho a warning would be good to have).
I'm happy to go any alternative route
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do like it like this, reasoning being:
- Public key is very easily verifiable and unique - if you set this value, you've intentionally fetched it and it should be correct.
- Alias is inherently less strictly defined (it's not guaranteed to be unique in our network), so we can take advantage of this looser mapping to have an easier UX (ie, just call it
Alice
orcln1
). When I test things, I often name nodes in my head without setting an alias.
tho a warning would be good to have
- this clears up any ambiguity for the users IMO (if they did want it to match).
Also think that this the type of decision where we just do something and then see how it goes in user testing since there's no clear technical "right way".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've rebased ce036fa and added the warning
sim-lib/src/lib.rs
Outdated
let src_id = payment_flow | ||
.source | ||
.get_pk() | ||
.map_err(LightningError::ValidationError)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just realized these should be SimulationError::ValidationError
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, tho that does not exist, we may want to move it.
sim-lib/src/lib.rs
Outdated
if let NodeId::PublicKey(pk) = self { | ||
Ok(pk) | ||
} else { | ||
panic!("NodeId is not a PublicKey. This should never happen, please report") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we could just return a SimulationError
. No need to panic :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can message this as "NodeId is not a PublicKey. Please prefer to use actual node pubkey for the node aliased as {}"
.
Any dependent on sim-lib
who passes in activity definition with aliases knows what to change, instead of reporting (?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ups, I forgot to change that to an error.
Regarding encouraging one or the other, I don't think we should. I'm happy with getting rid of the reporting stuff if we think of this as something that can be used by a third party, but we actually don't care whether they use one variant or the other, we cast everything to PK internally
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
sim-lib/src/lib.rs
Outdated
@@ -383,8 +418,8 @@ impl Simulation { | |||
for (id, node) in self.nodes.iter().filter(|(pk, _)| { | |||
self.activity | |||
.iter() | |||
.map(|a| a.source) | |||
.collect::<HashSet<PublicKey>>() | |||
.map(|a| a.source.get_pk().unwrap()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay but can we avoid the assumption of having called validate_activity
before this point?
Same sentiment for the other get_pk.unwrap()
points
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we? Sure, but I don't think we should. validate_activity
is our sanity checker, we could modify all these calls to account for an alias being here, but that's exactly what is not supposed to happen. If any NodeId
contains an alias at this point, it means the code is wrong (hence why there was a "report message").
I could patch the code so it does not unwrap and it fails more "elegantly", but all in all we want it to fail if that happens
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively, we could have two different classes to account for node definition and activity definition, one that interfaces with the config file, and where we allow aliases and pks (data is parsed as NodeId
), and an internal one that gets constructed from the former, and only accepts pks. In that way, we can be sure at compile time that everything is identified by pk internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where we allow aliases and pks (data is parsed as NodeId), and an internal one that gets constructed from the former, and only accepts pks.
I think that this has nice layering separation - the simulation library only really cares about public keys, and allowing user-friendly parsing of pubkey/alias is a CLI responsibility/feature.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've split this into two sets of data structures in 75795ca. The Parsers
that interact directly with the config file and allow NodeId
s to be loaded, and the regular ones which roll back to use PublicKey
s and can be built from the former.
This commit can be squashed with the previous one. Also, I'm happy to replace Parser
with any other better term we can come up with (Loader
, Reader
, ...)
cACK on e2d5fb3 allowing aliases as source or destination.
Sounds to me like a specific feature offering of
I have strong reactions against this. Had suggestions to better communicate the error case and avoid the panic, but that doesn't seem sufficient. |
0cc7e8d
to
a85ab1e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK, with a slight preference to shift some handling to the cli as mentioned here.
sim-lib/src/cln.rs
Outdated
crate::NodeId::PublicKey(pk) => { | ||
if pk != node_id { | ||
return Err(LightningError::ValidationError(format!( | ||
"The provided node id does not match the one returned by the backend ({} != {})", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: full stop / lower case for errors?
sim-lib/src/lnd.rs
Outdated
))); | ||
} | ||
} | ||
crate::NodeId::Alias(a) => alias = a, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do like it like this, reasoning being:
- Public key is very easily verifiable and unique - if you set this value, you've intentionally fetched it and it should be correct.
- Alias is inherently less strictly defined (it's not guaranteed to be unique in our network), so we can take advantage of this looser mapping to have an easier UX (ie, just call it
Alice
orcln1
). When I test things, I often name nodes in my head without setting an alias.
tho a warning would be good to have
- this clears up any ambiguity for the users IMO (if they did want it to match).
Also think that this the type of decision where we just do something and then see how it goes in user testing since there's no clear technical "right way".
sim-lib/src/lib.rs
Outdated
@@ -383,8 +418,8 @@ impl Simulation { | |||
for (id, node) in self.nodes.iter().filter(|(pk, _)| { | |||
self.activity | |||
.iter() | |||
.map(|a| a.source) | |||
.collect::<HashSet<PublicKey>>() | |||
.map(|a| a.source.get_pk().unwrap()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where we allow aliases and pks (data is parsed as NodeId), and an internal one that gets constructed from the former, and only accepts pks.
I think that this has nice layering separation - the simulation library only really cares about public keys, and allowing user-friendly parsing of pubkey/alias is a CLI responsibility/feature.
And sorry or the rebase conflicts :') |
32e66a7
to
75795ca
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just done a high level read through of the new approach, cACK!
05a0056
to
3cc59e2
Compare
I've added the last bit here. Notice how the last commit is pretty opinionated. I'm happy to re-visit the approach or even changing it as long as it does not end up being super messy (which has been my experience when trying to go for some of the alternatives). |
0ab5b75
to
ab7ddf8
Compare
Addressed the latest comments from @carlaKC plus the pending ones from the last review. The issue with the repeated source/destination in an activity should be fixed now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change read through, lgtm
tested with a similar setup to this one, can confirm it does not crash anymore |
FYI #120 needs to go in before this, given otherwise we cannot rebase main without setting the network field for nodes we don't control to something meaningful. |
tACK f17662d pending rebase on #120. Tested out various scenarios and everything is looking great. When I test this PR the easy config makes me so happy 🎆
Also tested out positive paths of:
|
Node creation logic was mostly duplicated, creates a node based on LightningNode instead of on its implementations to reduce the code replication. I'd be nice the be able to do this with a different container than Arc<Mutex<T>>, since that will save us from having to acquire the mutex after creating `node`. However, I don't know of any other container that is is send and which size is known at compile time. We may need to ask this to some elder rust wizards
3710351
to
fe1690a
Compare
Crates a new enum, `NodeId`, which is used to parse the node identifier from the config file to either a `PublicKey` or an `Alias`. Internally, we will identify nodes as `PublicKey`s, so we add do further checks when creating {Cln, Lnd}Connection. Moreover, we make sure that the provided variant matches the one from the backend. In case of a `PublicKey`, if the assertion fails the code will return a `ValidationError`. In the case of an `Alias`, it will simply log a warning. The rationale for not failing if the provided alias does not match the one from the backend is that we want to allow user to identify nodes using whatever name they rather (alice/bob/carol/..., n1, n2, n3, ...), so there is not strong requirement for aliases to match (but it feels right to let the user know, just in case). Finally, if an identifier is used more than once, the simulation will also fail with a `ValidationError`, independently of the identifier variant.
ee0dd4e
to
5c5497d
Compare
Sorry, rebasing this took me longer than I wanted to. I was trying to move the I think keeping the I've squeezed a fix for #126 in 5c5497d since being able to check that depended on having |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only comment is on the final commit adding validation.
Would be happy to drop that off of this and open it in a separate PR so that we can hit the button on this one.
@@ -815,32 +815,37 @@ async fn produce_random_events<N: NetworkGenerator, A: PaymentGenerator + Displa | |||
// Wait until our time to next payment has elapsed then execute a random amount payment to a random | |||
// destination. | |||
_ = time::sleep(wait) => { | |||
let destination = network_generator.lock().await.sample_node_by_capacity(source.pubkey); | |||
let (destination, capacity) = network_generator.lock().await.sample_node_by_capacity(source.pubkey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would have thought we want to do this validation much higher up?
Like nodes that don't have enough capacity, if a node doesn't support keysend when we start running it never will so we should just exclude it from the start (and log a warning so the user knows why).
If we do this validation here, we could also theoretically end up effectively running with one node (in the case of two nodes and one doesn't have keysend) and then just run without ever sending a payment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can run this much higher up, as long as we are ok with compromising with --accept-keysend
being enabled for both source and destination nodes. Otherwise, we cannot know if keysend
receiving is really going to be necessary until a node is picked as a payment destination, and that happens on the fly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
compromising with --accept-keysend being enabled for both source and destination nodes.
In the case of random activity I think that's okay because every sending node can reasonably be expected to also receive?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. 279ad56 should have fixed that
The approach followed for this is pretty straight-forward: instead of loading `PublicKey`s directly to our `ActivityDefinition` data structure, we create an intermediary class `ActivityParser` that accepts `NodeId`. However, we internally identify activities using `PublicKey`s, so we do an additional mapping step once the data is loaded to go from `ActivityParser` to `ActivityDefinition`, hence, once data is passed to the simulator it is always identified by `PublicKey`. For activity destinations, we also need to make sure that if an alias has been provided we do control that node, otherwise the Alias->PublicKey mapping cannot be done, in which case we fail with a `ValidationError`.
This commit redefines what data about a node is passed along to the simulator on activities. Previously, we used to pass only the src/dst `PublicKey`. However, by doing this we had no way of logging (nor accessing) any other information about them. This is mainly because all this mapping is only available on `sim-cli::main.rs`, and also because the data is mostly logged by the producers/consumers functions, which are not even part or the `Simulator` class. Therefore, the alternative we are left with are passing the information to the simulator. This can be done in several ways, I've gone with the one that has a better balance between codediff and usefulness, which is passing `NodeInfo` along. This, however, means having to obtain the destination node features on `main` instead of on `validation`.
5c5497d
to
98c15d0
Compare
98c15d0
to
279ad56
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🐑 it !
Let's go 👶 ! |
The goal of this PR is to allow aliases to be used throughout the config file to identify nodes, so the file is more human-readable. This involves:
source
of activitiesdestination
of activities as long as we control those nodes** We cannot use aliases as
destination
for nodes we don't control, given we have no way of mapping the aliases to the nodes' public keys. Notice aliases here do not have to match node aliases, they are just user-defined identifiers, and even if they did, node aliases don't have to be unique.