Skip to content
This repository has been archived by the owner on Apr 15, 2024. It is now read-only.

[v2.0] Introduce Topics #236

Merged
merged 37 commits into from
Jun 14, 2022
Merged

Conversation

DyrellC
Copy link
Contributor

@DyrellC DyrellC commented May 19, 2022

Description of change

Introduce Topic type and split KeyStore into BranchStore.
Changes:

  • Cursor and Key management are mapped to Topic's in BranchStore
  • Topic's will be sent inside the HDF of messages
  • Each branch will have an anchor message to attach Keyload messages to
  • Each branch will keep track of the latest link sent to it for iterative attachment purposes
  • Messages can be sent without a link_to address
  • Introduce new_branch function to allow users to announce (and retrieve) branches and store them before Keyload messages are parsed

Type of change

  • Enhancement (a non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

How the change has been tested

  • Examples updated to include branch announcements, removal of link_to from send functions
  • Existing cargo tests have been updated and tested

@DyrellC DyrellC changed the title V2.0/test topics [v2.0] Introduce Topics May 19, 2022
lets/src/message/topic.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
@DyrellC
Copy link
Contributor Author

DyrellC commented May 20, 2022

I need to investigate something that's happening here: The example is not completing consistently, for some reason it looks like a user that is not supposed to be able to read a signed packet is retrieving, need to look into it to see where the bug is

Copy link
Contributor

@arnauorriols arnauorriols left a comment

Choose a reason for hiding this comment

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

First feedback, that focuses on 2 aspects that I think need to be discussed before continuing with the review:

streams/src/lib.rs Outdated Show resolved Hide resolved
streams/examples/full-example/scenarios/basic.rs Outdated Show resolved Hide resolved
streams/examples/full-example/scenarios/basic.rs Outdated Show resolved Hide resolved
streams/src/api/mod.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@arnauorriols arnauorriols left a comment

Choose a reason for hiding this comment

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

Reviewed key_store.rs. I've found an important bug in remove_from_all() (and similar methods that use the fold pattern). I've written a test that replicates the bug, give it a look!

streams/src/api/key_store.rs Outdated Show resolved Hide resolved
streams/src/api/key_store.rs Outdated Show resolved Hide resolved
streams/src/api/key_store.rs Outdated Show resolved Hide resolved
streams/src/api/key_store.rs Outdated Show resolved Hide resolved
streams/src/api/key_store.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
Copy link
Contributor Author

@DyrellC DyrellC left a comment

Choose a reason for hiding this comment

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

The main issues that needs resolving first are:

  1. Topic internal and the Copy in HDF
  2. The fold bug that may be responsible for intermittent false removal of subscribers

lets/src/message/topic.rs Outdated Show resolved Hide resolved
streams/src/lib.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
streams/src/api/key_store.rs Outdated Show resolved Hide resolved
streams/src/api/key_store.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
streams/examples/full-example/scenarios/basic.rs Outdated Show resolved Hide resolved
streams/examples/full-example/scenarios/basic.rs Outdated Show resolved Hide resolved
streams/src/api/mod.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Show resolved Hide resolved
lets/src/address.rs Outdated Show resolved Hide resolved
lets/src/message/preparsed.rs Outdated Show resolved Hide resolved
lets/src/message/message.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Show resolved Hide resolved
streams/src/api/cursor_store.rs Outdated Show resolved Hide resolved
streams/src/api/cursor_store.rs Outdated Show resolved Hide resolved
streams/src/api/cursor_store.rs Outdated Show resolved Hide resolved
streams/src/api/user.rs Outdated Show resolved Hide resolved
streams/src/api/user.rs Outdated Show resolved Hide resolved
Copy link
Contributor Author

@DyrellC DyrellC left a comment

Choose a reason for hiding this comment

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

Fresh round of changes in response to the reviews. Still need to do the Option/upserting for BranchStore but most of the rest has been addressed.

self.0.resize(new_size, 0)
// Return an error if size exceeds u32 max size to avoid panic
// TODO: Remove anyhow error and replace with no_std compatible error handling
pub(crate) fn resize(&mut self, new_size: usize) -> anyhow::Result<()> {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

When recovering a user we end up unmasking the stream of wrapped topics/cursors, but if you use the wrong password (as we do in the examples) it mixes up the unmasked Size value for number of topics, and the Size within the topic Byte unwrap gets messed up as well. This results in an attempt to create a Vec with a size that exceeds its max allocation availability (https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.reserve), resulting in a panic that we have no way to catch.

One thing that threw me off was I tried to use isize::MAX and it still resulted in panics on occassion when the new size exceeded u32::MAX, so I made that the default max length. From a Streams perspective, we have no instance where Bytes should exceed 32Kb let alone u32::MAX so I thought that was an appropriate value to use.

lets/src/address.rs Outdated Show resolved Hide resolved
lets/src/message/message.rs Outdated Show resolved Hide resolved
lets/src/message/preparsed.rs Outdated Show resolved Hide resolved
lets/src/message/topic.rs Show resolved Hide resolved
streams/src/api/user_builder.rs Outdated Show resolved Hide resolved
streams/src/api/user.rs Outdated Show resolved Hide resolved
streams/src/api/user.rs Outdated Show resolved Hide resolved
streams/src/api/cursor_store.rs Outdated Show resolved Hide resolved
streams/src/api/cursor_store.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@arnauorriols arnauorriols left a comment

Choose a reason for hiding this comment

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

Ok, here goes some more comments. I did not had time to finish reviewing user.rs, but I'm confident the big chunk is done. There are some clone() here and there that I think can be spared but didn't comment on it. We'll clean them up along the way.

The most important discussions I'm opening are:

  • branch announcement as a separate message type
  • keyloads linked to tip of branch, and joining the stream announcement spongos

streams/src/api/cursor_store.rs Outdated Show resolved Hide resolved
streams/src/api/cursor_store.rs Outdated Show resolved Hide resolved
streams/src/api/user.rs Outdated Show resolved Hide resolved
streams/src/api/cursor_store.rs Outdated Show resolved Hide resolved
// Prepare HDF and PCF
let header = HDF::new(message_types::ANNOUNCEMENT, ANN_MESSAGE_NUM, self.identifier())?;
let header = HDF::new(
message_types::ANNOUNCEMENT,
Copy link
Contributor

Choose a reason for hiding this comment

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

(I have the feeling to had already raised this concern somewhere, but can't remember where nor if it got any answer, so I'm raising it again from scratch 😆 )

Are we sure we want to reuse the announcement message for both stream announcement and branch announcement? In my opinion that's not a very good idea, mainly for 2 reasons:

  • the announcement message is a fundamentally different entity than the branch announcement, as proven by the fact that it includes the author's identifier, which is not necessary for the branch announcement. Instead, if we want to support a tree structure branching from other branches, branch announcements will need the topic they are branching from. Also haven't really thought about it, but are we sure it's ok that branch announcements are not linked to any message?
  • the previous fact forces us to introduce the is_base_branch if-branching in the announcement-related methods. Now it seems harmless, but it will become uglier once we introduce admin permissions (admin subscribers can send branch announcements, but not stream announcements)

We can agree on an iterative approach as long as we are aligned on the design.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wouldn't be opposed to having branch announcement be its own thing, although I'd prefer to make that a focused PR of its own. This one is already undergoing a pretty significant number of changes/reviews as is

Copy link
Contributor

Choose a reason for hiding this comment

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

more than fair.

@@ -229,10 +231,11 @@ impl MsgId {
Self(bytes)
}

pub fn gen(appaddr: AppAddr, identifier: Identifier, seq_num: usize) -> MsgId {
pub fn gen(appaddr: AppAddr, identifier: Identifier, topic: Topic, seq_num: usize) -> MsgId {
Copy link
Contributor

Choose a reason for hiding this comment

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

Topic does not need to be taken by value, and it is not Copy now so it should be taken by ref

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we not do this for Identifier as well despite the Copy? It's an extra allocation without it being necessary.

Copy link
Contributor

@arnauorriols arnauorriols Jun 10, 2022

Choose a reason for hiding this comment

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

As long as something is Copy, you can be certain it does not incur in a heap allocation (basically because that's a hard condition for types to be able to implement Copy). Generally speaking, Copy is a marker that says that "cloning" the type is essentially the same as moving the type (a memcpy). For this reason, Copy types can keep using the old variable, even after a move to another variable (aka the copy semantics). Types that don't implement Copy have a more complex cloning (for example, because they handle resources, like the pointer to some heap allocated memory that tneeds to be freed when dropping the value), therefore move != clone anymore.

For the types that don't implement Copy, it's important not to take ownership in function parameters if it's not needed, cause you are forcing a potentially costly clone unnecessarily. For Copy types, this clone is as cheap as a move, and the extra cost of the move vs reference, even if arguable, I'd say is under the ream of "profile before assuming anything" and definitely negligible in our case. So in this case ergonomics prevail.

TL;DR: performance is not a factor in this decision. But still passing Identifier by reference would be valid if you prefer it (for coherence, or any other reason)

lets/src/address.rs Outdated Show resolved Hide resolved
streams/src/api/user.rs Outdated Show resolved Hide resolved
streams/src/api/messages.rs Outdated Show resolved Hide resolved
streams/src/api/user.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@arnauorriols arnauorriols left a comment

Choose a reason for hiding this comment

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

From my side, this can be merged. I'll create the issue to discuss and track the comments that have been postponed (keyload linking, branch announcement message type)

@DyrellC
Copy link
Contributor Author

DyrellC commented Jun 10, 2022

@kwek20 any further comments/change requests before we merge?

@kwek20
Copy link
Contributor

kwek20 commented Jun 13, 2022

Hmm only thing is maybe the name of cursor_store. SHouldnt it be branch_store now? Or maybe just state_store? (Im assuming you guys dont want to call it just store :D)

@DyrellC
Copy link
Contributor Author

DyrellC commented Jun 13, 2022

Probalby reasonable to change the module name, but I don't think it matters all that much, the only purpose of BranchStore is to map CursorStore's. So we either we pull cursor_store::{BranchStore, CursorStore} or branch_store::{BranchStore, CursorStore}. Seems rather negligible which is used since it's only ever pulled into User anyways. @arnauorriols any feelings one way or the other?

@arnauorriols
Copy link
Contributor

arnauorriols commented Jun 14, 2022

Seems rather negligible which is used since it's only ever pulled into User anyways

Even if it's not part of the public API, we should view this naming decision from a new contributor perspective, and what name would be most intuitive for her when trying to make sense of the code structure. In my opinion, the only meaningful name is cursor_store, cause at the end of the day what we are storing are cursors (that happen to be grouped by branch, but the ultimate item stored is cursors). I didn't want to open this topic, but now that you have mention it, ideally I'd rename BranchStore to CursorStore, and come up with any other name for what is currently called CursorStore (InnerStore for all I care 😄).

But I really don't think it's that important, you both have equally valid arguments, I'm fine with any decision as long as this beast gets merged!

@DyrellC DyrellC merged commit 35ea66f into iotaledger:v2.0-dev Jun 14, 2022
@DyrellC DyrellC deleted the v2.0/test-topics branch March 13, 2023 23:02
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants