Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ require (
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
github.com/google/s2a-go v0.1.8 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/google/uuid v1.6.0
github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect
github.com/googleapis/gax-go/v2 v2.14.1 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
Expand Down
68 changes: 15 additions & 53 deletions pkg/utils/uuid.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,66 +7,28 @@ SPDX-License-Identifier: Apache-2.0
package utils

import (
"crypto/rand"
"fmt"
"io"
"github.com/google/uuid"
)

var randChar = &poolRandReader{
randReader: rand.Reader,
pool: []byte(`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`),
}

type poolRandReader struct {
randReader io.Reader
pool []byte
}
func init() {
// we enable rand pool for better performance.
// note that the pooled random bytes are stored in heap;
// for more details see uuid.EnableRandPool docs.

func (r *poolRandReader) Read(p []byte) (int, error) {
n, err := r.randReader.Read(p)
if err != nil {
return n, err
}

l := uint8(len(r.pool))
for i := range p {
p[i] = r.pool[p[i]%l]
}
return n, nil
// BenchmarkUUID/google_uuid_(pooled)
// BenchmarkUUID/google_uuid_(pooled)-10 18897972 63.14 ns/op 48 B/op 1 allocs/op
// BenchmarkUUID/google_uuid_(non-pooled)
// BenchmarkUUID/google_uuid_(non-pooled)-10 3658857 326.3 ns/op 64 B/op 2 allocs/op
uuid.EnableRandPool()
}

// GenerateBytesUUID returns a UUID based on RFC 4122 returning the generated bytes
// GenerateBytesUUID creates a new random UUID and returns it as []byte
func GenerateBytesUUID() []byte {
uuid := make([]byte, 16)
_, err := io.ReadFull(rand.Reader, uuid)
if err != nil {
panic(fmt.Sprintf("Error generating UUID: %s", err))
}

// variant bits; see section 4.1.1
uuid[8] = uuid[8]&^0xc0 | 0x80

// version 4 (pseudo-random); see section 4.1.3
uuid[6] = uuid[6]&^0xf0 | 0x40

return uuid
u := uuid.New()
return u[:]
}

// GenerateUUID returns a UUID based on RFC 4122
// GenerateUUID creates a new random UUID and returns it as a string
func GenerateUUID() string {
uuid := GenerateBytesUUID()
return idBytesToStr(uuid)
}

func idBytesToStr(id []byte) string {
return fmt.Sprintf("%x-%x-%x-%x-%x", id[0:4], id[4:6], id[6:8], id[8:10], id[10:])
}

// GenerateUUIDOnlyLetters returns a UUID without digits
func GenerateUUIDOnlyLetters() string {
uuid := make([]byte, 16)
if _, err := io.ReadFull(randChar, uuid); err != nil {
panic(err)
}
return string(uuid)
return uuid.NewString()
}
80 changes: 77 additions & 3 deletions pkg/utils/uuid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,85 @@ SPDX-License-Identifier: Apache-2.0
package utils

import (
"crypto/rand"
"fmt"
"io"
"testing"

"github.com/stretchr/testify/assert"
"github.com/google/uuid"
)

func TestUUIDLettersOnly(t *testing.T) {
assert.Regexp(t, "^[a-zA-Z]{16}$", GenerateUUIDOnlyLetters())
func BenchmarkUUID(b *testing.B) {
// generateUUIDv1 is our reference impl for rand UUID based on previous version of this code
oldGenerateUUID := func() string {
uuid := make([]byte, 16)

_, err := io.ReadFull(rand.Reader, uuid[:])
if err != nil {
panic(fmt.Sprintf("Error generating UUID: %s", err))
}

// variant bits; see section 4.1.1
uuid[8] = uuid[8]&^0xc0 | 0x80

// version 4 (pseudo-random); see section 4.1.3
uuid[6] = uuid[6]&^0xf0 | 0x40

id := uuid

return fmt.Sprintf("%x-%x-%x-%x-%x", id[0:4], id[4:6], id[6:8], id[8:10], id[10:])
}

b.Run("oldGenerateUUID", func(b *testing.B) {
report(b)
for b.Loop() {
_ = oldGenerateUUID()
}
})

b.Run("GenerateBytesUUID", func(b *testing.B) {
report(b)
for b.Loop() {
_ = GenerateBytesUUID()
}
})

b.Run("GenerateUUID", func(b *testing.B) {
report(b)
for b.Loop() {
_ = GenerateUUID()
}
})

b.Run("GenerateUUID (non-pooled)", func(b *testing.B) {
report(b)
uuid.DisableRandPool()
for b.Loop() {
_ = GenerateUUID()
}
})

b.Run("GenerateUUID parallel", func(b *testing.B) {
report(b)
uuid.EnableRandPool()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = GenerateUUID()
}
})
})

b.Run("GenerateUUID parallel (non-pooled)", func(b *testing.B) {
report(b)
uuid.DisableRandPool()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
_ = GenerateUUID()
}
})
})
}

func report(b *testing.B) {
b.ReportAllocs()
}
26 changes: 20 additions & 6 deletions platform/fabric/services/storage/vault/vaultstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"context"
"testing"

"github.com/hyperledger-labs/fabric-smart-client/pkg/utils"
"github.com/hyperledger-labs/fabric-smart-client/platform/common/driver"
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections"
q "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/storage/driver/sql/query"
Expand Down Expand Up @@ -265,9 +264,12 @@ func testPagination(store driver.VaultStore) {

func TestPaginationStoreMem(t *testing.T) {
RegisterTestingT(t)
db, err := OpenMemoryVault(utils.GenerateUUIDOnlyLetters())
db, err := OpenMemoryVault("testdb")
assert.NoError(t, err)
assert.NotNil(t, db)
t.Cleanup(func() {
_ = db.Close()
})

testPagination(db)
}
Expand All @@ -277,6 +279,9 @@ func TestPaginationStoreSqlite(t *testing.T) {
db, err := OpenSqliteVault("testdb", t.TempDir())
assert.NoError(t, err)
assert.NotNil(t, db)
t.Cleanup(func() {
_ = db.Close()
})

testPagination(db)
}
Expand All @@ -286,16 +291,19 @@ func TestPaginationStoreSPostgres(t *testing.T) {
db, terminate, err := OpenPostgresVault("testdb")
assert.NoError(t, err)
assert.NotNil(t, db)
defer terminate()
t.Cleanup(terminate)

testPagination(db)
}

func TestVaultStoreMem(t *testing.T) {
RegisterTestingT(t)
db, err := OpenMemoryVault(utils.GenerateUUIDOnlyLetters())
db, err := OpenMemoryVault("testdb")
assert.NoError(t, err)
assert.NotNil(t, db)
t.Cleanup(func() {
_ = db.Close()
})

testVaultStore(t, db)
testOneMore(t, db)
Expand All @@ -306,8 +314,10 @@ func TestVaultStoreSqlite(t *testing.T) {
db, err := OpenSqliteVault("testdb", t.TempDir())
assert.NoError(t, err)
assert.NotNil(t, db)
t.Cleanup(func() {
_ = db.Close()
})

assert.NotNil(t, db)
testVaultStore(t, db)
testOneMore(t, db)
}
Expand All @@ -317,13 +327,15 @@ func TestVaultStorePostgres(t *testing.T) {
db, terminate, err := OpenPostgresVault("testdb")
assert.NoError(t, err)
assert.NotNil(t, db)
defer terminate()
t.Cleanup(terminate)

testVaultStore(t, db)
testOneMore(t, db)
}

func testOneMore(t *testing.T, store driver.VaultStore) {
t.Helper()

err := store.SetStatuses(context.Background(), driver.TxStatusCode(valid), "", "txid3")
assert.NoError(t, err)

Expand Down Expand Up @@ -383,6 +395,8 @@ func fetchAll(store driver.VaultStore) ([]driver.TxID, error) {
}

func testVaultStore(t *testing.T, store driver.VaultStore) {
t.Helper()

txids, err := fetchAll(store)
assert.NoError(t, err)
assert.Empty(t, txids)
Expand Down
Loading