feat: add p/uuid
I suggest adding a UUID package because I think it could be useful to have it available. I think it can further facilitate traceability and compatibility between different systems and apps as they would have a common standard for identifying entities.
To improve UUID generation, I wanted to add a resolver like Snowflake, but from what I've searched, sync/atomic is not supported on Gno. Is there another similar package that I might have missed ?
Codecov Report
All modified and coverable lines are covered by tests :white_check_mark:
Project coverage is 60.85%. Comparing base (
5503cca) to head (485ce8d).
Additional details and impacted files
@@ Coverage Diff @@
## master #2076 +/- ##
==========================================
+ Coverage 60.83% 60.85% +0.02%
==========================================
Files 563 563
Lines 75193 75193
==========================================
+ Hits 45743 45762 +19
+ Misses 26076 26066 -10
+ Partials 3374 3365 -9
| Flag | Coverage Δ | |
|---|---|---|
| contribs/gnodev | 61.46% <ø> (ø) |
|
| contribs/gnofaucet | 14.46% <ø> (ø) |
|
| gno.land | 67.17% <ø> (ø) |
|
| gnovm | 65.63% <ø> (ø) |
|
| misc/genstd | 80.54% <ø> (ø) |
|
| misc/logos | 20.23% <ø> (ø) |
|
| tm2 | 62.11% <ø> (+0.21%) |
:arrow_up: |
Flags with carried forward coverage won't be shown. Click here to find out more.
:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.
To improve
UUIDgeneration, I wanted to add a resolver likeSnowflake, but from what I've searched,sync/atomicis not supported on Gno. Is there another similar package that I might have missed ?
There is no other way to guarantee atomicity besides using time in environments where atomic is not supported. If we consider it further, it seems possible to generate a random value (using crypto/rand or not merged yet, but maybe later) like a machine ID, assign it, and then combine it. Of course, this is slightly different from the implementation of Snowflake.
To improve
UUIDgeneration, I wanted to add a resolver likeSnowflake, but from what I've searched,sync/atomicis not supported on Gno. Is there another similar package that I might have missed ?There is no other way to guarantee atomicity besides using time in environments where atomic is not supported. If we consider it further, it seems possible to generate a random value (using
crypto/randor not merged yet, but #1933 later) like a machine ID, assign it, and then combine it. Of course, this is slightly different from the implementation of Snowflake.
Thanks for your explanation. I will check the progress of crypto/rand to try to use it.
Hi, when you have time, could you please do a second review of my modifications cc @notJoon @moul @leohhhn
Hi, when you have time, could you please do a second review of my modifications cc @notJoon @moul @leohhhn
The implementation looks good. However, currently only the Snowflake algorithm is implemented. It would be nice if the output could be formatted like a UUID (especially, version 4), in the form of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
I've added a simple example functions for formatting the snowflake into UUID using Go. Please check this and let me know if you have any questions.
https://go.dev/play/p/iO-x2NDXHro
Hi, when you have time, could you please do a second review of my modifications cc @notJoon @moul @leohhhn
The implementation looks good. However, currently only the Snowflake algorithm is implemented. It would be nice if the output could be formatted like a UUID (especially, version 4), in the form of
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.I've added a simple example functions for formatting the snowflake into UUID using Go. Please check this and let me know if you have any questions.
Thanks for your example :)
I think your result for the UUID is better and I wanted to do the same but I saw in gno that crypto/rand is not implemented. I think it's because without Oracle randomizing, it's possible to predict the randomize.
Is this the case ?
Thanks for your example :) I think your result for the UUID is better and I wanted to do the same but I saw in gno that
crypto/randis not implemented. I think it's because withoutOraclerandomizing, it's possible to predict the randomize. Is this the case ?
Maybe related. The crypto/rand package is currently classified as nondet^1. I believe it will be added to gno in a different way, probably to hide the entropy source to prevent others guess values in advance.
nondet: the standard library in question would require non-deterministic behaviour to implement as in Go, such as cryptographical randomness or os/network access. The library may still be implemented at one point, with a different API.
Therefore, it seems difficult to manipulate Snowflake IDs generated using rand in the current gno (I forgot that the implementation hasn't been done). However, it is possible to convert the generated uint64 value to bytes and directly manipulate the bytes.
So, if we use the following two methods appropriately, we can resolve this problem to some context.
- Byte Rearrangement: By extracting bits from the generated Snoflake Id and placeing them in different positions within the UUID, we can increase the distriubution of data. For example, using the middle part of the ID or mixing the bits and placing them in different parts of the UUID.
- Using Hash Function: To compensate for the lack of randomness, we can consider using hash functions to transform the input ID. For example, we can think of methods such as circular shifting each byte of the ID or applying mathematical operations.
Of course, after applying these methods, it is important to maintain the format of the UUID. Below is the basic UUID format. We'll aim to keep this format for now.^2 But if you want to implement more complete UUID functionality, you can refer to RFC4122 but ignore it for now.
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Mis a 4-bit value representing the UUID version. If the version is4, it must be4.Nis a 1~3 bit value representing the UUID variant. In the case of variant1, it is one of8,9,a,b.- The remaining parts of the UUID(
X) are filled with randomly generated values.
This is the text I wrote before discovering the bug related to time package. The two code snippets below implement the generation of UUIDs by manipulating bits, as discussed above.
When executing the Go version, it works almost well. However, when running the same code using the Gno version, you can see that the UUIDs are not generated properly, and it produces the same ID for all of them.
go: https://go.dev/play/p/1Y3CT-r9Qaq gno: https://play.gno.land/p/plbJloUG2kn
Thanks for your example :) I think your result for the UUID is better and I wanted to do the same but I saw in gno that
crypto/randis not implemented. I think it's because withoutOraclerandomizing, it's possible to predict the randomize. Is this the case ?Maybe related. The
crypto/randpackage is currently classified asnondet1. I believe it will be added to gno in a different way, probably to hide the entropy source to prevent others guess values in advance.
nondet: the standard library in question would require non-deterministic behaviour to implement as in Go, such as cryptographical randomness or os/network access. The library may still be implemented at one point, with a different API.Therefore, it seems difficult to manipulate Snowflake IDs generated using rand in the current gno (I forgot that the implementation hasn't been done). However, it is possible to convert the generated
uint64value to bytes and directly manipulate the bytes.So, if we use the following two methods appropriately, we can resolve this problem to some context.
- Byte Rearrangement: By extracting bits from the generated Snoflake Id and placeing them in different positions within the UUID, we can increase the distriubution of data. For example, using the middle part of the ID or mixing the bits and placing them in different parts of the UUID.
- Using Hash Function: To compensate for the lack of randomness, we can consider using hash functions to transform the input ID. For example, we can think of methods such as circular shifting each byte of the ID or applying mathematical operations.
Of course, after applying these methods, it is important to maintain the format of the UUID. Below is the basic UUID format. We'll aim to keep this format for now.2 But if you want to implement more complete UUID functionality, you can refer to RFC4122 but ignore it for now.
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Mis a 4-bit value representing the UUID version. If the version is4, it must be4.Nis a 1~3 bit value representing the UUID variant. In the case of variant1, it is one of8,9,a,b.- The remaining parts of the UUID(
X) are filled with randomly generated values.This is the text I wrote before discovering the bug related to
timepackage. The two code snippets below implement the generation of UUIDs by manipulating bits, as discussed above.When executing the Go version, it works almost well. However, when running the same code using the Gno version, you can see that the UUIDs are not generated properly, and it produces the same ID for all of them.
go: go.dev/play/p/1Y3CT-r9Qaq gno: play.gno.land/p/plbJloUG2kn
Footnotes
Thank you for this very detailed and explicit explanation. I understand my issue with time.Now() output better now. I will look into implementing the UUID format in my code correction
With the merged of p/demo/entropy (https://github.com/gnolang/gno/pull/2487)
I called it to replace the counter for manual incrementation
seems not "gno-ified" enough :)
can you also provide some examples, like a screenshot or something so that we can see various generated output examples just by reviewing the PR, please?
Output this my last commit 485ce8d: