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

Flag locally created logs as direct #374

Merged
merged 5 commits into from
Jun 12, 2020
Merged

Conversation

carsonfarmer
Copy link
Member

@carsonfarmer carsonfarmer commented Jun 10, 2020

Fixes #373, and a better alternative to #372.

The approach here is to simply take advantage of the existing metadata store on the logstore to set a flag as to whether a given log is "managed?" by the local peer. Directly "managed" logs are those logs created or directly added by the local peer. Otherwise, unmanaged logs are those from other peers in a given thread. Related, "owned" logs are those logs for which the peer has the private key. There can only be one "owned" log, versus potentially many "managed" logs.

This should support multiple use cases:

  • The local peer is the client peer. One "owned" log is used to interact with a given thread (single-tenant, single-writer setup)
  • The local peer is (also) a relay peer. Maybe multiple "managed" logs on behalf of other clients, and zero or one "owned" log to also participate in the thread on its own (multi-tenant, multi-writer setup)
  • The local peer is (also) a proxy-writer. Maybe multiple "managed" logs on behalf of other clients, and one "owned" log that is written to on behalf of other 'agents' (multi-tenant, single-writer setup)

Signed-off-by: Carson Farmer <carson.farmer@gmail.com>
@carsonfarmer carsonfarmer added bug Something isn't working enhancement New feature or request labels Jun 10, 2020
@carsonfarmer carsonfarmer added this to the Sprint 38 milestone Jun 10, 2020
@carsonfarmer carsonfarmer requested a review from sanderpick June 10, 2020 23:36
@carsonfarmer carsonfarmer self-assigned this Jun 10, 2020
core/logstore/logstore.go Outdated Show resolved Hide resolved
core/logstore/logstore.go Show resolved Hide resolved
core/thread/id.go Show resolved Hide resolved
logstore/logstore.go Outdated Show resolved Hide resolved
logstore/logstore.go Outdated Show resolved Hide resolved
net/net.go Show resolved Hide resolved
net/net.go Show resolved Hide resolved
net/net.go Show resolved Hide resolved
net/api/pb/threadsnet.proto Outdated Show resolved Hide resolved
core/thread/id.go Outdated Show resolved Hide resolved
Copy link
Member

@sanderpick sanderpick left a comment

Choose a reason for hiding this comment

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

Looking good! Some comments and questions...

core/logstore/logstore.go Outdated Show resolved Hide resolved
core/logstore/logstore.go Show resolved Hide resolved
core/thread/id.go Show resolved Hide resolved
core/thread/id.go Outdated Show resolved Hide resolved
logstore/logstore.go Outdated Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
net/net.go Show resolved Hide resolved
net/net.go Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
Copy link
Member Author

@carsonfarmer carsonfarmer left a comment

Choose a reason for hiding this comment

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

Thanks for the comments @sanderpick. I'm going to address these in the AM, but I think nothing outstanding, all comments and suggestions were clear and helpful 👍

core/thread/id.go Show resolved Hide resolved
logstore/logstore.go Outdated Show resolved Hide resolved
logstore/logstore.go Outdated Show resolved Hide resolved
net/api/pb/threadsnet.proto Outdated Show resolved Hide resolved
net/net.go Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
net/net.go Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
Signed-off-by: Carson Farmer <carson.farmer@gmail.com>
core/logstore/logstore.go Show resolved Hide resolved
core/thread/id.go Show resolved Hide resolved
core/thread/id.go Show resolved Hide resolved
logstore/logstore.go Show resolved Hide resolved
logstore/logstore.go Show resolved Hide resolved
logstore/logstore.go Show resolved Hide resolved
logstore/logstore.go Show resolved Hide resolved
net/net.go Outdated
@@ -218,6 +218,7 @@ func (n *net) CreateThread(_ context.Context, id thread.ID, opts ...core.NewThre
if !info.Key.Defined() {
info.Key = thread.NewRandomKey()
}
// This may overwrite ThreadKey information if there is a mismatch
Copy link
Member Author

Choose a reason for hiding this comment

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

Note that some existing tests relied on the ability to overwrite read and service keys, so no check or error is thrown when this happens. This seems ok, because it would support things like key rotation etc... but I've added this comment as a reminder and perhaps this should be documented in the public APIs?

Copy link
Member

Choose a reason for hiding this comment

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

What about only adding new keys if they don't already exists? So, modifying logstore.AddThread to not blindly overwrite?

Copy link
Member Author

Choose a reason for hiding this comment

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

So silently ignore if new/mismatched keys are used? That's an option for sure, would it lead to unexpected results?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe just error if something would be overwritten?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeh that's what I had, but we have some existing tests that rely on being able to overwrite. Hence my comment above... unless I'm missing something here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

We could modify NewDB to allow passing in ThreadOptions, so that you could specify the same keys again, and if you didn't, return an error.

Copy link
Member Author

Choose a reason for hiding this comment

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

That's what I went with.

net/net.go Outdated Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
Signed-off-by: Carson Farmer <carson.farmer@gmail.com>
@carsonfarmer carsonfarmer requested a review from sanderpick June 11, 2020 19:56
Copy link
Member

@sanderpick sanderpick left a comment

Choose a reason for hiding this comment

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

Couple more comments and questions!

net/net.go Outdated Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
net/net.go Outdated Show resolved Hide resolved
net/net.go Outdated
@@ -218,6 +218,7 @@ func (n *net) CreateThread(_ context.Context, id thread.ID, opts ...core.NewThre
if !info.Key.Defined() {
info.Key = thread.NewRandomKey()
}
// This may overwrite ThreadKey information if there is a mismatch
Copy link
Member

Choose a reason for hiding this comment

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

What about only adding new keys if they don't already exists? So, modifying logstore.AddThread to not blindly overwrite?

Signed-off-by: Carson Farmer <carson.farmer@gmail.com>
@carsonfarmer carsonfarmer requested a review from sanderpick June 12, 2020 18:03
@carsonfarmer
Copy link
Member Author

Ok, @sanderpick, this ended up touching a lot more places than I had initially anticipated, but it should now cover all our bases. Checks for all keys types have been added, and errors thrown for any mismatches. One 'own' log per thread is enforced, but multiple 'managed' logs are possible. There are also tests for the expected behavior, and peers can even replicate managed logs which is important for our JS use-cases.

@@ -68,6 +69,13 @@ func WithNewToken(t thread.Token) NewOption {
}
}

// WithNewThreadKey provides control over thread keys to use with a db.
func WithNewThreadKey(key thread.Key) NewOption {
Copy link
Member Author

Choose a reason for hiding this comment

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

This was required to be able to get some tests passing again, but is also useful/required.

@@ -89,13 +92,35 @@ func (ls *logstore) AddThread(info thread.Info) error {
if info.Key.Service() == nil {
return fmt.Errorf("a service-key is required to add a thread")
}
if err := ls.AddServiceKey(info.ID, info.Key.Service()); err != nil {
sk, err := ls.ServiceKey(info.ID)
Copy link
Member Author

Choose a reason for hiding this comment

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

Keeping these checks in the high-level AddThread function rather than in the individual stores because it might still be useful to override this behavior in certain cases. So seems like the most common operation should fail, but if you're digging into internals, its your fault if something get's messed up.

_, err := n.store.GetThread(id)
if err == nil {
return lstore.ErrThreadExists
func (n *net) ensureUnique(id thread.ID, key crypto.Key) error {
Copy link
Member Author

Choose a reason for hiding this comment

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

This is now a lot more verbose, as there are multiple different possible scenarios here, but I think the early outs help.

Signed-off-by: Carson Farmer <carson.farmer@gmail.com>
if err != nil {
return err
}
// Early out if no log key required.
Copy link
Member Author

Choose a reason for hiding this comment

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

If we don't care about log keys, then we'll end up creating a random one downstream, with negligible chance of a collision.

return nil
}
// Ensure we don't already have this log in our store.
if _, ok := key.(crypto.PrivKey); ok {
Copy link
Member Author

Choose a reason for hiding this comment

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

If this is a private key, and we don't already have a private key for this thread, we're good to go, otherwise, we fail 'early' here.

}
return nil
}
pubKey, ok := key.(crypto.PubKey)
Copy link
Member Author

Choose a reason for hiding this comment

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

If this is a public key, just make sure we don't already have a log for this key.

Copy link
Member

@sanderpick sanderpick left a comment

Choose a reason for hiding this comment

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

Awesome, looks great! This is a great improvement... thanks for hanging in with the back and forth 💥

net/net_test.go Show resolved Hide resolved
@carsonfarmer
Copy link
Member Author

Thank you @sanderpick!

@carsonfarmer carsonfarmer merged commit a8477ff into master Jun 12, 2020
@carsonfarmer carsonfarmer deleted the carson/log-ownership branch June 12, 2020 18:34
dgtony pushed a commit to anyproto/go-threads that referenced this pull request Aug 24, 2020
feat: own vs managed log concepts and tooling

Directly "managed" logs are those logs created or directly added by the local peer. Otherwise, unmanaged logs are those from other peers in a given thread. Related, "owned" logs are those logs for which the peer has the private key. There can only be one "owned" log, versus potentially many "managed" logs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Invalid log information from getOwnLog if peer doesn't 'own' the log
2 participants