-
Notifications
You must be signed in to change notification settings - Fork 89
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
feat(backend): unique keys per wallet address #2863
base: main
Are you sure you want to change the base?
Conversation
…posit input (#2817) * fix(frontend): asset scale consistency in liquidity dialogs. * Ensure asset scale consistency when displaying and withdrawing liquidity by adding asset info to the liquidity dialog component and updating the input handling in Rafiki Admin UI. --------- Co-authored-by: Blair Currey <[email protected]>
* fix: getting the localenv docs and readme in sync * chore: updated MASE screenshots * chore: updating the code block language identifier to have consistent approach through the docs
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* fixed(frontend) asset page now retains page scroll position. * feat(frontend) added autofocus to liquidity dialog input * feat(fronted) made eslint happy
* feat(auth): build with alpine3.19 * feat(backend): build with alpine3.19 * feat(frontend): build with alpine3.19 * bump(localenv): docker image to alpine 3.19
* fix(auth): interact redirect * fix(auth): session cookie not expiring in browser * fix(auth): session expiration time unit --------- Co-authored-by: Blair Currey <[email protected]>
* feat(auth): return granId for the grant lookup via interaction id * test(auth): check grantId is returned for grant lookup via interaction id * docs(openapi): auth return grantId for grant lookup via interaction id
* feat(backend): support for returning grantId when querying outgoing payment When querying outgoing payment, either single one, or list of them via pagination, etc., it will be possible to also get a grantId under which the outgoing * test(outgoing-payment): check if grantId is returned * docs(bruno): include grantId when fetching outgoing payment
* feat(localenv): add span metric generation - adds configuration that generates span metrics from tempo traces - can see new `traces_spanmetrics_bucket` etc. in local grafana dashboard * feat(localenv): add gql resolver metric * chore(localenv): give panel title
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
* feat(2737): add fees as metric for outgoing payment. * feat(2737): rename to payment_fees. * feat(2737): test case updates. * feat(2737): formatting. * feat(2737): re-order test cases. Move fee collector. * feat(2737): dashboard and doc updates. * feat(2737): merged with main. * feat(2737): review feedback applied from @JoblersTune. * feat(2737): review feedback applied from @mkurapov. * feat(2737): additional tests for covert of assets and rates. * feat(2737): additional tests ensuring the increment counter was called. * feat(2737): additional tests ensuring the increment counter was called. * feat(2737): readme.
Our builds are failing due to Trivy scanner. Trivy scanner actually found that our Axios version v1.6.8 has a vulnerability - CVE-2024-39338. This was fixed in version 1.7.4, hence, the upgrade. fix #2860
✅ Deploy Preview for brilliant-pasca-3e80ec ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
FROM walletAddressKeys | ||
GROUP BY walletAddressId, kid, x | ||
); | ||
`) |
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.
played around with it and it seems to be working. Had to lookup ctid but I guess it probably makes for an easier query than using the uuid.
What's the user experience going to be for the people using the keys being deleted here? I recall the discussion and read the issue but I guess I'm still not quite connecting the dots. For example, is some normal user going to see invalid signature
or similar from the grant request process and have no idea they need to upload some new key? I guess probably not because they should still have a key right (just not duplicates of it)? I suppose maybe it just fixes the bug in that issue and otherwise people wont be impacted from these duplicates being deleted.
I see the error for duplicate writes in gql - that makes sense.
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.
The users should not have any issues since they still have another copy of the key. But this makes me think I need to check what happens when a user re-adds a key that they have previously revoked. That should be un-revoked and not throw the duplicate error. And I'll also double check that we actually delete the older versions of the key in the migration and keep the most recent.
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.
yeah thats a good point... since we're not deleting these and instead setting revoked
to true I imagine re-adding the previously revoked key will trigger the unique constraint error. I dont think we can just add the revoked
to the unique constraint because you couldnt revoke it twice.
- add key, OK
- revoke key, OK
- re-add same key, OK
- revoke same key, NOT OK. already have a revoked key with these unique fields.
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.
Not tested, but I think a partial index like this would work:
CREATE UNIQUE INDEX wallet_address_keys_revoked_false_idx
ON "walletAddressKeys" (walletAddressId, kid, x)
WHERE revoked = false;
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.
do we really want to unrevoke the key? if we do this, we lose the information that sometime in the past, this key was revoked. I think that we need to have new entry in the database if revoked key was again added
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 with @golobitch re: unrevoking (we should just create a new row instead) & @BlairCurrey's partial index suggestion
exports.up = function (knex) { | ||
// delete any existing duplicates per wallet address | ||
knex.raw(` | ||
DELETE FROM walletAddressKeys | ||
WHERE ctid NOT IN ( | ||
SELECT MIN(ctid) | ||
FROM walletAddressKeys | ||
GROUP BY walletAddressId, kid, x | ||
); | ||
`) | ||
|
||
return knex.schema.alterTable('walletAddressKeys', (table) => { | ||
table.unique(['walletAddressId', 'kid', 'x']) | ||
}) | ||
} |
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.
noticed this wasn't actually running the DELETE (and when it does postgres doesnt like the unquoted camelCase names). Need to do something like:
exports.up = function (knex) { | |
// delete any existing duplicates per wallet address | |
knex.raw(` | |
DELETE FROM walletAddressKeys | |
WHERE ctid NOT IN ( | |
SELECT MIN(ctid) | |
FROM walletAddressKeys | |
GROUP BY walletAddressId, kid, x | |
); | |
`) | |
return knex.schema.alterTable('walletAddressKeys', (table) => { | |
table.unique(['walletAddressId', 'kid', 'x']) | |
}) | |
} | |
exports.up = function (knex) { | |
// delete any existing duplicates per wallet address | |
return knex | |
.raw( | |
` | |
DELETE FROM "walletAddressKeys" | |
WHERE ctid NOT IN ( | |
SELECT MIN(ctid) | |
FROM "walletAddressKeys" | |
GROUP BY "walletAddressId", kid, x | |
); | |
` | |
) | |
.then(() => { | |
return knex.schema.alterTable('walletAddressKeys', (table) => { | |
table.unique(['walletAddressId', 'kid', 'x']) | |
}) | |
}) | |
} |
Tested locally and it works.
Its kind of annoying but when I want to test migrating data I:
- move the file out of the migration dir
- spin up the containers and add whatever data that needs to be migrated (adding a duplicate key in this case)
- stop the containers (dont remove the volume) and move migration file back in
- spin back up and check
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, in PostgreSQL you need to put camel case in quotes. Delete statement was not performed probably because of the missing await, because it is async operation.
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.
wish we would have used the snake case mapper when we setup the db initially: https://vincit.github.io/objection.js/recipes/snake-case-to-camel-case-conversion.html
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'll add the quotes.
@golobitch all of these have to be async functions?
EDIT: I googled, looks like just the up
needs to be async.
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.
With knex and objection, if you dont await the function the query is not executed. Instead it returns a query builder (so you can modify further).
That's what happened originally and asserting as much here really made me stop and think how that was even possible (aka, "am I wrong???"). Guess I simply was not familiar with then()
(MDN).
- A SO post asking the same thing: https://stackoverflow.com/questions/65319822/how-does-knex-await-execute-a-database-query
- a little knex query builder prototype that connects all the dots https://gist.github.com/BlairCurrey/ece2557b75487fc2bec6c006526b0324
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 found there to be a lot of gotchas with promises in the knex migrations. Another important thing is returning from the migration (which we are doing). We couldn't, for example, await all the queries and not return (something I've done).
I've also seen/tried using Promise.All
like this but I don't think it would guarantee resolution order because they run concurrently (ie, second might actually modify the db before the first):
return Promise.All([
knex.raw(...),
knex.raw(...)
])
Usually I actually use the dreaded promise chaining 😱 :
return knex.raw(...)
.then(()=>{
knex.raw(...)
})
Ugly, I know. But clear.
The way it is now seems fine - just wanted to chime in with other general pitfalls I've run into.
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.
@sabineschaller No, I meant that knex.raw
needs to be awaited
hmmm what's going on with the history? Just surprised to see a bunch of commits already in main. |
@BlairCurrey I messed up merging in main. I haven't touched code in a while so I'm out of practice 😬 |
@sabineschaller to double check, are we good to review this? |
Changes proposed in this pull request
This prevents uploading the same key per wallet address multiple times.
Context
Checklist
fixes #number