gno icon indicating copy to clipboard operation
gno copied to clipboard

feat: add p/uuid

Open DIGIX666 opened this issue 1 year ago • 3 comments

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 ?

DIGIX666 avatar May 12 '24 15:05 DIGIX666

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.

codecov[bot] avatar May 12 '24 15:05 codecov[bot]

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 ?

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.

notJoon avatar May 13 '24 01:05 notJoon

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 ?

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 #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.

DIGIX666 avatar May 13 '24 02:05 DIGIX666

Hi, when you have time, could you please do a second review of my modifications cc @notJoon @moul @leohhhn

DIGIX666 avatar Jun 06 '24 16:06 DIGIX666

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

notJoon avatar Jun 07 '24 03:06 notJoon

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.

go.dev/play/p/iO-x2NDXHro

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 ?

DIGIX666 avatar Jun 12 '24 14:06 DIGIX666

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 ?

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.

  1. 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.
  2. 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
  • M is a 4-bit value representing the UUID version. If the version is 4, it must be 4.
  • N is a 1~3 bit value representing the UUID variant. In the case of variant 1, it is one of 8, 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

notJoon avatar Jun 13 '24 05:06 notJoon

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 ?

Maybe related. The crypto/rand package is currently classified as nondet1. 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.

  1. 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.
  2. 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
  • M is a 4-bit value representing the UUID version. If the version is 4, it must be 4.
  • N is a 1~3 bit value representing the UUID variant. In the case of variant 1, it is one of 8, 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: go.dev/play/p/1Y3CT-r9Qaq gno: play.gno.land/p/plbJloUG2kn

Footnotes

  1. master/docs/reference/go-gno-compatibility.md
  2. medium.com/@gaspm/understanding-uuid-purpose-and-benefits-of-a-universal-unique-identifier-59110154d897

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

DIGIX666 avatar Jun 13 '24 22:06 DIGIX666

With the merged of p/demo/entropy (https://github.com/gnolang/gno/pull/2487) I called it to replace the counter for manual incrementation

DIGIX666 avatar Aug 13 '24 18:08 DIGIX666

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: SCR-20240917-txql

DIGIX666 avatar Sep 17 '24 21:09 DIGIX666