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

identities: updated delegation causes replication failure #711

Merged
merged 3 commits into from
Aug 9, 2021

Conversation

FintanH
Copy link
Contributor

@FintanH FintanH commented Jun 21, 2021

We have the following steps:

  • Peer 1 creates a Person document
  • Peer 2 replicates this Person
  • Peer 1 updates Person document
  • Peer 1 creates Project delegating to new Person document
  • Peer 2 attempts to replicate the Project, but fails with error below

Error:

Revision 7bb4bbce268d89a62e1962f5dded7a9f68c9e665 of 4b84e8407d602317b01f22207908dbea1d9d4e17 not in ancestry path of eada5419806f643d402c92b790c9b471098f1e81

The error originates from updated_person, which seems to not consider the fact that the Person in the delegate is a fast-forward of the Person that Peer 2 knows about at the top-level. Instead, it only checks that the Person delegate was a previous version of the Person at the top-level.

Should this check be done for fast-forwards as well and do the following if it is?

self.as_person().verify(known.revision)

@kim
Copy link
Contributor

kim commented Jun 21, 2021

I think this is related to #709, which, however, doesn't actually fix the root cause. At some point, it did work that a fetch would update the top-level person-typed namespace, such that the symref can never be ahead or behind. I'm not sure why or when this broke, but it is possible that we shouldn't rely on it anyways: there is still a TODO which punts on the problem that technically more top-level namespaces need to be updated, because the tracking graph may have changed.

A possible fix could thus be that #709 resets the top-level rad/id to the local remotes/../rad/self iff the latter can be fast-forwarded onto the former. I also think that the fetch turns any symrefs into direct refs if they get updated as a result of the fetch, so the symrefs need to be forced always.

@FintanH
Copy link
Contributor Author

FintanH commented Jun 23, 2021

At some point, it did work that a fetch would update the top-level person-typed namespace, such that the symref can never be ahead or behind.

I think in this case because the rad/id of the Person is replicated before the Project it doesn't get a chance to create the symref, because it will fail the verification with the above error before it gets to the symref creation point.

Hmmm, actually it seems we've had a similar conversation before here: #420.

A possible fix could thus be that #709 resets the top-level rad/id to the local remotes/../rad/self iff the latter can be fast-forwarded onto the former. I also think that the fetch turns any symrefs into direct refs if they get updated as a result of the fetch, so the symrefs need to be forced always.

Ok, I can look into this on top of #709 :)

@kim
Copy link
Contributor

kim commented Jun 23, 2021 via email

@FintanH FintanH force-pushed the finto/updated-delegation branch from 9b6d685 to 46b943d Compare June 24, 2021 13:06
@FintanH FintanH changed the base branch from master to finto/rad-id-symref June 24, 2021 13:06
@FintanH FintanH force-pushed the finto/updated-delegation branch from 46b943d to 4ecd47c Compare June 24, 2021 13:07
// Nb. technically we could coerce `known` into a `VerifiedPerson` if its
// `content_id` equals `latest_head`. Let's not introduce an unsafe
// coercion, but rely on caching to be implemented efficiently.
if self.is_in_ancestry_path(latest_head, known.revision.into())? {
self.as_person().verify(latest_head)
// If the latest is a fast-forward then we can update the top-level
} else if is_fast_forward(&known, latest_head)? {
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'm not sure about the placement of this, but I was struggling to find where the logic could go. What do you think @kim?

Copy link
Contributor

Choose a reason for hiding this comment

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

Into replication.

I said here that it is probably a mistake to fail verification if top level delegates fail verification. The reason is this:

Imagine you create that project with valid delegates, which are then "checkpointed" as rad/ids/*. Now, one of them creates an invalid revision after this checkpoint. If the project fails verification by auto-resolving to the top-level, it can never recover from that (eg. by removing the faulty delegate), because we never replicate it again.

To solve this, we'd need to allow passing the find_latest_head function to git::identities::project::verify, and make it resolve to rad/ids/<urn.id> on the first pass. After replication is done doing its thing, we run verification again, this time resolving to refs/namespaces/<urn.id>/rad/id, and return a different value from replicate if that fails.

@FintanH FintanH force-pushed the finto/updated-delegation branch from 4ecd47c to d5f1af2 Compare June 25, 2021 14:08
@FintanH FintanH force-pushed the finto/rad-id-symref branch from 723a08b to 39cd7fb Compare June 25, 2021 14:11
@FintanH FintanH force-pushed the finto/updated-delegation branch from d5f1af2 to 6a1fb60 Compare June 25, 2021 14:12
@FintanH FintanH marked this pull request as ready for review June 25, 2021 14:12
@FintanH FintanH requested a review from a team as a code owner June 25, 2021 14:12
@FintanH FintanH force-pushed the finto/rad-id-symref branch from 39cd7fb to a98218d Compare June 25, 2021 20:07
Base automatically changed from finto/rad-id-symref to master June 25, 2021 20:07
@FintanH FintanH force-pushed the finto/updated-delegation branch from 6a1fb60 to 509c498 Compare June 25, 2021 20:08
xla
xla previously approved these changes Jun 29, 2021
Copy link
Contributor

@xla xla left a comment

Choose a reason for hiding this comment

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

Respect your elders.

🔒 🛫 🏃 🏙

@@ -189,6 +189,21 @@ where
Ok(verified(storage).newer(a, b)?)
}

pub fn fast_forward<S>(
Copy link
Contributor

Choose a reason for hiding this comment

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

I get how you're guided by the types, but you end up with a lot of IO:

  • see if known exists
  • load and verify known
  • do ancestry check between known and latest
  • update ref

There is also a correctness problem: the reason for introducing this is to reset refs/namespaces/XXX/rad/id to refs/namespaces/YYY/rad/ids/XXX iff the latter can be fast-forwarded onto the former. However, this must be a fast-forward in the git sense, not the tree history sense, otherwise YYY can rewrite the history of XXX!

(No, we cannot actually prevent this entirely without a blockchain, but it is surely safer to disallow history rewrites on identity branches wherever possible)

So I think this can be simplified to a function which takes a VerifiedPerson and:

  1. Looks up the oid of the rad/id(ie. refname_to_id(RefLike::try_from(pers.urn().with_path(None))?))
  2. Calls graph_descendant_of(pers.content_id, canonical_oid)
  3. If true, reset the ref from 1. to pers.content_id

Nb.: VerifiedPerson is already verified (qed), so if 1. and 2. pass we have also proven validity of the top-level person.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the help, that makes more sense. Hopefully, the simplified version is right 🤞

let proj = identities::project::verify(storage, &rad_id)?
.ok_or(Error::MissingIdentity)?;
let proj = identities::project::verify_with(storage, &rad_id, |delegate| {
let refname =
Copy link
Contributor

Choose a reason for hiding this comment

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

It is a bit hard to see from the code how the lookup functions are different for the various invocations. Do you think this could be extracted out somehow (maybe curried function "constructors" or something)?

@FintanH FintanH force-pushed the finto/updated-delegation branch 2 times, most recently from 72e04fc to fba6595 Compare July 1, 2021 14:37
@FintanH FintanH force-pushed the finto/updated-delegation branch from fba6595 to fc011df Compare July 12, 2021 09:53
@FintanH FintanH force-pushed the finto/updated-delegation branch from fc011df to db80379 Compare July 27, 2021 12:19
@FintanH
Copy link
Contributor Author

FintanH commented Aug 9, 2021

Is there anything blocking this @kim? Or is it a matter of you working on replication v3?

kim
kim previously approved these changes Aug 9, 2021
FintanH added 3 commits August 9, 2021 16:03
We have the following steps:
* Peer 1 creates a Person document
* Peer 2 replicates this Person
* Peer 1 updates Person document
* Peer 1 creates Project delegating to new Person document
* Peer 2 attempts to replicate the Project, but fails with error below

Error:
```
Revision 7bb4bbce268d89a62e1962f5dded7a9f68c9e665 of 4b84e8407d602317b01f22207908dbea1d9d4e17 not in ancestry path of eada5419806f643d402c92b790c9b471098f1e81
```

Signed-off-by: Fintan Halpenny <[email protected]>
We introduce verify_with for projects, which allows the caller to
specify where the tips of the delegates are found. We use this in
replication to verify the projects via their rad/ids/<urn>.

Signed-off-by: Fintan Halpenny <[email protected]>
When a delegate's rad/id already exists we check that the
rad/ids/<urn.id> for the project being replicated is a fast-forward for
rad/id. If that's the case we can safely update the rad/id to the latest
tip.

The `fast_forward` function works as follows:
1. Get tip of rad/id
2. Check the verified person's tip is a descendant of 1.
3. If so, update rad/id

Signed-off-by: Fintan Halpenny <[email protected]>
@FintanH FintanH force-pushed the finto/updated-delegation branch from b192331 to c01da9f Compare August 9, 2021 15:03
@FintanH FintanH merged commit c01da9f into master Aug 9, 2021
@FintanH FintanH deleted the finto/updated-delegation branch August 9, 2021 15:16
@github-pages github-pages bot temporarily deployed to github-pages August 9, 2021 15:16 Inactive
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.

3 participants