-
Notifications
You must be signed in to change notification settings - Fork 79
Improve payloadId generator #168
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
Improve payloadId generator #168
Conversation
jsonrpc/utils/src/format.ts
Outdated
} | ||
|
||
getRandomValue() { | ||
return (this.base++ << this.shift) + crypto.getRandomValues(this.typedArray)[0]; |
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.
Might need to reset this.base
if it gets larger than 2 ** 15 - 1
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.
Actually, I don't like that it has this limitation.
Let's use multiplication instead:
return (this.base++ << this.shift) + crypto.getRandomValues(this.typedArray)[0]; | |
return (this.base++ * (2 ** this.shift)) + crypto.getRandomValues(this.typedArray)[0]; |
I measured and it doesn't seem to have a significant performance penalty
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.
Can you please add some Unit Tests?
@arein Well, since this is a unique-number generator you can't conventionally unit-test it. The current Possible tests I can add are:
Is that what you had in mind? |
Yes that sounds good. It's obviously really sensitive and crucial logic and many of our systems e.g. the deduplication mechanism in the SDKs itself depend on properties of the generated
Thanks for raising the bar here |
@arein Yeah, writing tests for these was a good idea
|
@@ -25,10 +25,6 @@ describe("Payload Id", () => { | |||
chai.expect(payloadId().toString().length).to.equal(16); | |||
}); | |||
|
|||
it("returns a bigint with 19 digits", () => { |
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 are you removing this?
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 moved bigint
case into a separate test case. The check for length is there: https://github.com/WalletConnect/walletconnect-utils/pull/168/files#diff-2efdab1819dc17dfb490670403c52da588f22d53c99fb710b27848aada10e1acR81-R83
Thank you for the PR @everdimension 💯 💯 |
@ganchoradkov Did you have time to test this? Is there anything I can help with? |
@everdimension, I'm on it today 👍 |
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.
thank you for the PR @everdimension, I tested with
1.0.8-canary.0
- 23 digits IDs -> doesn't work1.0.8-canary.1
- 19 digits IDs that I suggested, works correctly
What do you mean by "doesn't work" btw? So some code relies on the generated id length? In which codebase? |
@everdimension https://github.com/WalletConnect/walletconnect-monorepo, it contains the main JS clients such as |
@ganchoradkov Pushed the update: cbaedce |
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.
Awesome! tested with 1.0.8-canary.2
and everything is working as expected 💯
Problem
Current
payloadId
function has defects:Date.now()
can return the same value if called in the same tick)Solution 1
Just use
randomUUID()
.This breaks the expected return type of current
payloadId
which is a numberSolution 2
Preserves function signature
The most simple, performant and (in my opinion) sufficient solution would be the following:
This would provide a sufficiently random number.
Solution 3
Provide incremental values
To always return a random value greater than the previous one, we have to introduce some state:
This way,
getPayloadId()
will guarantee a random value to be always greater than the previous one, even if the function is called in the same tick.But this guarantee would only exist within a single runtime, so it will not be preserved between different scripts or session restarts.
Solution 4
This is the solution from the current PR. It's quite convoluted, but aims to prevent breaking changes.
This guarantees incremental nature of the function if called within a single runtime and has a quite small intersection window of values between script restarts. Relying on timestamp can't guarantee us anything anyway because they can differ between systems, so this intersection I think is ok.
Also, this solution kinda ignores the
entropy
parameter (not fully, just branching whether or not it's larger than 3), but I don't see much value in preserving it.Tell me what you think. My personal vote is for Solution 2, but I understand that it might be undesired to get rid of the incremental nature of the function, even if it worked improperly.