-
-
Notifications
You must be signed in to change notification settings - Fork 44
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
E2e protocol ricardo 20231025 login sync #1780
E2e protocol ricardo 20231025 login sync #1780
Conversation
Having checked this PR mainly focusing on the user flow, I could see several issues. Issue 1
|
Issue 2
|
Issue 3
|
Issue 4
|
Issue 5
|
Thanks again, @Silver-IT! As discussed:
In addition, I've implemented fixes for all of the issues reported here, except issue 3. I'll continue working on this until issue 3 is resolved. Regarding issue 1, there is the double sync, that I've tracked down to the login functionality. I'll work on addressing this as well (but it seems to be the case that implementing the @taoeffect: You'll probably be pleased to see that I've mostly removed |
@Silver-IT I've made another commit addressing issue 3. The solution so far is using Besides that, two issues remain. One is at leaving; specifically, when someone else leaves a chatroom we have left: To write to a contract, we need to be subscribed to it. This is done in The second issue is at joining. You'll see that the I think that we need to either adapt Related to this, there is a third issue, which is a variant of issue 3:
To recap, apart from the issues mentioned, which are related to removing contracts, there is the double-sync issue I mentioned earlier. Although double-syncs are a concern, I'll focus now on trying to address the actual issues that happen from missing contract states, which are errors. Do you have a suggestion on how we could call |
c8cbd3b
to
9364fdf
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.
Nice work, @corrideat. I did a very partial review, and left a just two comments.
I can see many updates in contract parts (model/contracts, controller/actions) but I don't think most of them are needed. I have almost finished my PR #1728 and I want you to have even a brief look at it. I fixed most of the login issues with the smaller changes than this.
Also will check the 5 Issues (described above) again, and left comments here.
frontend/model/contracts/group.js
Outdated
sbp('chelonia/queueInvocation', contractID, () => sbp('gi.contracts/group/leaveGroup', { data, meta, contractID }, { state, getters })).catch(e => { | ||
console.error(`[gi.contracts/group/removeMember/sideEffect] Error ${e.name} during queueInvocation for ${contractID}`, e) | ||
}) |
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 don't need to call gi.contracts/group/leaveGroup
when the member has joined the group after this action.
So it would be necessary to check the group contract profile state in this invocation.
Please reference my PR for this.
sideEffect ({ data, meta, contractID }, { state, getters }) {
const rootState = sbp('state/vuex/state')
const rootGetters = sbp('state/vuex/getters')
const contracts = rootState.contracts || {}
const { username } = rootState.loggedIn
if (data.member === username) {
// If this member is re-joining the group, ignore the rest
// so the member doesn't remove themself again.
sbp('chelonia/queueInvocation', contractID, async () => {
if (rootState[contractID].profiles?.[username]?.status === PROFILE_STATUS.REMOVED) {
// NOTE: should remove archived data from IndexedStorage
// regarding the current group (proposals, payments)
await sbp('gi.contracts/group/removeArchivedProposals', contractID)
await sbp('gi.contracts/group/removeArchivedPayments', contractID)
preSendCheck: (_, state) => { | ||
// Avoid sending a duplicate action if the person has already | ||
// left or been removed from the chatroom | ||
return !!state?.users?.[member] | ||
} |
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.
Inside group
contract, it doesn't make sense to decide the next operation depending on the chatroom
contract state.
Issue 1 (#1780 (comment)) This issue is not fixed yet. Problem: three errors and 2 redundant |
Issue 2 (#1780 (comment)) This issue is not fixed yet. Problem: 1 redundant |
Issue 3 (#1780 (comment)) seems not to be fixed yet. Problem: two errors in console |
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.
Preliminary review
shared/domains/chelonia/GIMessage.js
Outdated
} catch { | ||
// Signature or encryption error | ||
return undefined |
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.
No console.warn
is needed here?
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.
This is doing the same as was it was doing earlier, more or less. There could be a console.warn
, but that is already done elsewhere and it feels repetitive to warn multiple times.
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.
Then a comment about that should be here...
@@ -407,7 +406,7 @@ export class GIMessage { | |||
return `${desc}|${this.hash()} of ${this.contractID()}>` | |||
} | |||
|
|||
isFirstMessage (): boolean { return !this.head().previousHEAD } | |||
isFirstMessage (): boolean { return !this.head().contractID } |
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 was this changed?
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.
Because I removed a bunch of the repetitive code in chelonia.js
that was looking up the previous HEAD, which is now done by publishEvent
. Since the previous HEAD could now momentarily be null, the check as it was would fail. Note that either condition is correct (if the previous HEAD were set).
@@ -36,7 +37,7 @@ export default ({ | |||
...mapState(['currentGroupId']), | |||
ourGroupProfile () { | |||
if (!this.ephemeral.groupIdWhenMounted) return | |||
return this.$store.state[this.ephemeral.groupIdWhenMounted]?.profiles?.[this.ourUsername] | |||
return this.$store.state[this.ephemeral.groupIdWhenMounted]?.profiles?.[this.ourUsername]?.status === PROFILE_STATUS.ACTIVE |
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.
This change changes the meaning of this computed property.
The computed property is named ourGroupProfile
, which implies it returns our group profile. But now this no longer happens, instead it returns a boolean.
So either the condition needs to be removed or the name of the computed property needs to be changed.
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.
frontend/common/errors.js
Outdated
|
||
export class GIErrorMissingSigningKeyError extends Error { | ||
constructor (...params: any[]) { | ||
super(...params) | ||
// this.name = this.constructor.name | ||
this.name = 'GIErrorMissingSigningKeyError' // string literal so minifier doesn't overwrite | ||
if (Error.captureStackTrace) { | ||
Error.captureStackTrace(this, this.constructor) | ||
} | ||
} | ||
} |
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 think this is a good time to copy over that utility function from Chelonia to define these using 1-liners...
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.
shared/domains/chelonia/internals.js
Outdated
|
||
// TODO: The [pubsub] code seems to miss events that happened between | ||
// a call to sync and the subscription time. This is a temporary measure | ||
// to handle this until [pubsub] is updated. | ||
if (entry.height() === lastAttemptedHeight) { | ||
await sbp('okTurtles.eventQueue/queueEvent', entry.contractID(), ['chelonia/private/in/syncContract', entry.contractID()]) |
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.
So I agree that we should address this in this PR... one way to go about it is to make sure the pubsub is connected before 'chelonia/contract/sync'
does the sync.
We might also want to verify that we are in fact connected to the pubsub server before allowing messages to be sent.
frontend/model/contracts/group.js
Outdated
memberKey, member, profile, active: (profile: any)?.status === PROFILE_STATUS.ACTIVE | ||
}) | ||
if (memberKey === member && (profile: any)?.status === PROFILE_STATUS.ACTIVE) { | ||
return [memberKey, { status: PROFILE_STATUS.REMOVED }] |
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.
This line seems to be removing many profile fields... that seems wrong.
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.
There isn't much in the profile and this is for removed members. Would you prefer { ...profile, status: PROFILE_STATUS.REMOVED }
instead?
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.
Yes, I think that would be much more robust.
// When a group is being left, we want to also leave chatrooms, | ||
// including private chatrooms. Since the user issuing the action | ||
// may not be a member of the chatroom, we use the group's CSK | ||
// unconditionally in this situation, which should be a key in the | ||
// chatroom (either the CSK or the groupKey) | ||
if (leavingGroup) { | ||
const signingKeyId = sbp('chelonia/contract/currentKeyIdByName', state, 'csk', true) | ||
|
||
// If we don't have a CSK, it is because we've already been removed. | ||
// Proceeding would cause an error |
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.
These are good comments 👍
} | ||
|
||
extraParams.signingKeyId = signingKeyId | ||
extraParams.innerSigningContractID = null |
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.
Does innerSigningContractID = null
need to be specified? If yes, could you add a comment explaining why?
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.
Yes, it needs to be specified or else it'll be set to the identity CSK.
shared/domains/chelonia/utils.js
Outdated
const newOp = opT === GIMessage.OP_ATOMIC && (newRawOpV: any).length === 1 | ||
? (newRawOpV: any)[0] | ||
: [opT, newRawOpV] |
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.
What's going on here? Are you sure this is right? Is ? (newRawOpV: any)[0]
correct?
Why is this being done? Is it rewriting what the user is sending? We should probably keep the developer intent and not modify messages the developer is sending.
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.
Reverted
shared/domains/chelonia/internals.js
Outdated
} | ||
return Promise.resolve(sbp(`${manifestHash}/${action}/sideEffect`, mutation)) |
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 is this wrapping the result in Promise.resolve
? What if an error occurred? What's the point of later checking .then
and Promise.allSettled
if they're guaranteed to settled because of the Promise.resolve
?
Or is that not how it works? If so please add a comment explaining because this is confusing...
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
|
@corrideat, @taoeffect. I have just checked the test scenario. Still existing issues in terms of workflow(user1 = alexjin, user2 = greg, user3 = andrea) IMHO, I don't approve the many updates in |
…itching to newly created chatroom)
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.
This is looking really solid now, thanks @Silver-IT for finding those issues and @corrideat for figuring out the fixes! I think it's ready to merge into e2e-protocol
but with also double-check with @Silver-IT to see if he can confirm that the issues he found have been fixed.
@@ -926,8 +969,8 @@ export default (sbp('sbp/selectors/register', { | |||
// of waiting, we need to remove it ourselves | |||
const keyId = findKeyIdByName(contractState, keyName) | |||
if (!keyId) { | |||
console.log('@@@@ pendingWatch --- pushed to keysToDelete', { contractID, externalContractID, keyName, state: cloneDeep(contractState) }) |
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.
Is this logging still needed?
No description provided.