From e8139fca97115d7b5d0902ef4a4bdd553df23606 Mon Sep 17 00:00:00 2001 From: David VIEJO Date: Tue, 17 Dec 2024 12:52:26 +0100 Subject: [PATCH 1/9] Fixes #5001 and gossip panic when high concurrency Signed-off-by: David VIEJO --- core/chaincode/handler.go | 71 +++++++++---------- .../statedb/stateleveldb/stateleveldb.go | 23 +++++- gossip/gossip/algo/pull.go | 15 ++-- gossip/util/misc.go | 16 +++-- 4 files changed, 76 insertions(+), 49 deletions(-) diff --git a/core/chaincode/handler.go b/core/chaincode/handler.go index a270cca7a20..878179721e0 100644 --- a/core/chaincode/handler.go +++ b/core/chaincode/handler.go @@ -474,7 +474,7 @@ func (h *Handler) notifyRegistry(err error) { h.Registry.Ready(h.chaincodeID) } -// HandleRegister is invoked when chaincode tries to register. +// handleRegister is invoked when chaincode tries to register. func (h *Handler) HandleRegister(msg *pb.ChaincodeMessage) { h.stateLock.RLock() state := h.state @@ -746,55 +746,54 @@ func (h *Handler) HandleGetStateByRange(msg *pb.ChaincodeMessage, txContext *Tra totalReturnLimit := h.calculateTotalReturnLimit(metadata) iterID := h.UUIDGenerator.New() + var rangeIter commonledger.ResultsIterator isPaginated := false namespaceID := txContext.NamespaceID collection := getStateByRange.Collection - if isCollectionSet(collection) { - if txContext.IsInitTransaction { - return nil, errors.New("private data APIs are not allowed in chaincode Init()") - } - if err := errorIfCreatorHasNoReadPermission(namespaceID, collection, txContext); err != nil { - return nil, err - } - rangeIter, err = txContext.TXSimulator.GetPrivateDataRangeScanIterator(namespaceID, collection, - getStateByRange.StartKey, getStateByRange.EndKey) - } else if isMetadataSetForPagination(metadata) { - isPaginated = true - startKey := getStateByRange.StartKey - if isMetadataSetForPagination(metadata) { + + // Wrap the iterator creation in a recover block + func() { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("panic in range scan: %v", r) + } + }() + + if isCollectionSet(collection) { + if txContext.IsInitTransaction { + err = errors.New("private data APIs are not allowed in chaincode Init()") + return + } + if err = errorIfCreatorHasNoReadPermission(namespaceID, collection, txContext); err != nil { + return + } + rangeIter, err = txContext.TXSimulator.GetPrivateDataRangeScanIterator(namespaceID, collection, + getStateByRange.StartKey, getStateByRange.EndKey) + } else if isMetadataSetForPagination(metadata) { + isPaginated = true + startKey := getStateByRange.StartKey if metadata.Bookmark != "" { startKey = metadata.Bookmark } + rangeIter, err = txContext.TXSimulator.GetStateRangeScanIteratorWithPagination(namespaceID, + startKey, getStateByRange.EndKey, metadata.PageSize) + } else { + rangeIter, err = txContext.TXSimulator.GetStateRangeScanIterator(namespaceID, getStateByRange.StartKey, getStateByRange.EndKey) } - rangeIter, err = txContext.TXSimulator.GetStateRangeScanIteratorWithPagination(namespaceID, - startKey, getStateByRange.EndKey, metadata.PageSize) - } else { - rangeIter, err = txContext.TXSimulator.GetStateRangeScanIterator(namespaceID, getStateByRange.StartKey, getStateByRange.EndKey) - } - if err != nil { - return nil, errors.WithStack(err) - } - txContext.InitializeQueryContext(iterID, rangeIter) + }() - payload, err := h.QueryResponseBuilder.BuildQueryResponse(txContext, rangeIter, iterID, isPaginated, totalReturnLimit) if err != nil { - txContext.CleanupQueryContext(iterID) - return nil, errors.WithStack(err) - } - if payload == nil { - txContext.CleanupQueryContext(iterID) - return nil, errors.New("marshal failed: proto: Marshal called with nil") + return nil, errors.WithMessage(err, "error getting range scan iterator") } - payloadBytes, err := proto.Marshal(payload) - if err != nil { - txContext.CleanupQueryContext(iterID) - return nil, errors.Wrap(err, "marshal failed") + if rangeIter == nil { + return nil, errors.New("nil iterator returned") } - chaincodeLogger.Debugf("Got keys and values. Sending %s", pb.ChaincodeMessage_RESPONSE) - return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: payloadBytes, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil + txContext.InitializeQueryContext(iterID, rangeIter) + + return createResponse(txContext, rangeIter, isPaginated, totalReturnLimit) } // Handles query to ledger for query state next diff --git a/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go b/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go index 6865630d1e2..7c43bd177f4 100644 --- a/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go +++ b/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go @@ -8,6 +8,7 @@ package stateleveldb import ( "bytes" + "fmt" "github.com/hyperledger/fabric-lib-go/common/flogging" "github.com/hyperledger/fabric/common/ledger/dataformat" @@ -164,10 +165,28 @@ func (vdb *versionedDB) GetStateRangeScanIteratorWithPagination(namespace string if endKey == "" { dataEndKey[len(dataEndKey)-1] = lastKeyIndicator } - dbItr, err := vdb.db.GetIterator(dataStartKey, dataEndKey) + + // Wrap the iterator creation in a recover block + var dbItr iterator.Iterator + var err error + + func() { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("panic while creating iterator: %v", r) + } + }() + dbItr, err = vdb.db.GetIterator(dataStartKey, dataEndKey) + }() + if err != nil { - return nil, err + return nil, errors.WithMessage(err, "error getting iterator from db") + } + + if dbItr == nil { + return nil, errors.New("nil iterator returned from db") } + return newKVScanner(namespace, dbItr, pageSize), nil } diff --git a/gossip/gossip/algo/pull.go b/gossip/gossip/algo/pull.go index a1fd8aff7ff..0e025804d08 100644 --- a/gossip/gossip/algo/pull.go +++ b/gossip/gossip/algo/pull.go @@ -319,11 +319,18 @@ func (engine *PullEngine) OnRes(items []string, nonce uint64) { } func (engine *PullEngine) newNONCE() uint64 { - n := uint64(0) - for { - n = util.RandomUInt64() - if !engine.outgoingNONCES.Exists(n) { + engine.lock.Lock() + defer engine.lock.Unlock() + + maxAttempts := 100 + for i := 0; i < maxAttempts; i++ { + n := util.RandomUInt64() + if n != 0 && !engine.outgoingNONCES.Exists(n) { return n } } + + // If we couldn't generate a unique NONCE after max attempts, + // use time-based fallback + return uint64(time.Now().UnixNano()) } diff --git a/gossip/util/misc.go b/gossip/util/misc.go index 7d9b6d1350e..b18c09597b1 100644 --- a/gossip/util/misc.go +++ b/gossip/util/misc.go @@ -7,9 +7,8 @@ SPDX-License-Identifier: Apache-2.0 package util import ( - crand "crypto/rand" "fmt" - "math/rand/v2" + "math/rand" "reflect" "runtime" "sync" @@ -18,12 +17,13 @@ import ( "github.com/spf13/viper" ) -var r *rand.Rand +var ( + r *rand.Rand + rMutex sync.Mutex +) func init() { // do we really need this? - var seed [32]byte - _, _ = crand.Read(seed[:]) - r = rand.New(rand.NewChaCha8(seed)) + r = rand.New(rand.NewSource(time.Now().UnixNano())) } // Equals returns whether a and b are the same @@ -179,7 +179,7 @@ func SetVal(key string, val interface{}) { // RandomInt returns, as an int, a non-negative pseudo-random integer in [0,n) // It panics if n <= 0 func RandomInt(n int) int { - return r.IntN(n) + return r.Intn(n) } // RandomUInt64 returns a random uint64 @@ -187,6 +187,8 @@ func RandomInt(n int) int { // If we want a rand that's non-global and specific to gossip, we can // establish one. Otherwise this uses the process-global locking RNG. func RandomUInt64() uint64 { + rMutex.Lock() + defer rMutex.Unlock() return r.Uint64() } From 8cae2b2e7359a37ccd985b701758ad36f1e38777 Mon Sep 17 00:00:00 2001 From: David VIEJO Date: Tue, 17 Dec 2024 13:22:47 +0100 Subject: [PATCH 2/9] Add createResponse function for building paginated QueryResponse This commit introduces the createResponse function in handler.go, which constructs a QueryResponse for range queries. It handles pagination and includes error handling for payload marshaling, ensuring proper cleanup of the query context in case of errors. Signed-off-by: David VIEJO --- core/chaincode/handler.go | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/core/chaincode/handler.go b/core/chaincode/handler.go index 878179721e0..49aeb407cc5 100644 --- a/core/chaincode/handler.go +++ b/core/chaincode/handler.go @@ -1320,3 +1320,33 @@ func (s State) String() string { return "UNKNOWN" } } + +// createResponse builds a QueryResponse for range queries. If the query is paginated, +// it will include bookmark information in the response. +func createResponse(txContext *TransactionContext, iter commonledger.ResultsIterator, isPaginated bool, totalReturnLimit int32) (*pb.ChaincodeMessage, error) { + // Use the QueryResponseBuilder to construct the response + payload, err := txContext.Handler.QueryResponseBuilder.BuildQueryResponse(txContext, iter, txContext.QueryIterator.GetID(), isPaginated, totalReturnLimit) + if err != nil { + txContext.CleanupQueryContext(txContext.QueryIterator.GetID()) + return nil, errors.WithStack(err) + } + if payload == nil { + txContext.CleanupQueryContext(txContext.QueryIterator.GetID()) + return nil, errors.New("marshal failed: proto: Marshal called with nil") + } + + // Marshal the payload into bytes + payloadBytes, err := proto.Marshal(payload) + if err != nil { + txContext.CleanupQueryContext(txContext.QueryIterator.GetID()) + return nil, errors.Wrap(err, "marshal failed") + } + + // Create and return the chaincode message response + return &pb.ChaincodeMessage{ + Type: pb.ChaincodeMessage_RESPONSE, + Payload: payloadBytes, + Txid: txContext.TxID, + ChannelId: txContext.ChannelID, + }, nil +} From 0e1b6344450a920d403d4e14bbd0b02d0830de71 Mon Sep 17 00:00:00 2001 From: David VIEJO Date: Tue, 17 Dec 2024 13:29:18 +0100 Subject: [PATCH 3/9] Update Signed-off-by: David VIEJO --- core/chaincode/handler.go | 121 +++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/core/chaincode/handler.go b/core/chaincode/handler.go index 49aeb407cc5..8a0f653b67e 100644 --- a/core/chaincode/handler.go +++ b/core/chaincode/handler.go @@ -733,6 +733,17 @@ func (h *Handler) HandleGetStateMetadata(msg *pb.ChaincodeMessage, txContext *Tr // Handles query to ledger to rage query state func (h *Handler) HandleGetStateByRange(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) { + // Defer panic recovery + defer func() { + if r := recover(); r != nil { + chaincodeLogger.Errorf("Panic in HandleGetStateByRange: %v", r) + // Clean up any query context that may have been created + if txContext != nil { + txContext.CleanupQueryContext("") + } + } + }() + getStateByRange := &pb.GetStateByRange{} err := proto.Unmarshal(msg.Payload, getStateByRange) if err != nil { @@ -746,54 +757,76 @@ func (h *Handler) HandleGetStateByRange(msg *pb.ChaincodeMessage, txContext *Tra totalReturnLimit := h.calculateTotalReturnLimit(metadata) iterID := h.UUIDGenerator.New() - var rangeIter commonledger.ResultsIterator isPaginated := false namespaceID := txContext.NamespaceID collection := getStateByRange.Collection - // Wrap the iterator creation in a recover block - func() { - defer func() { - if r := recover(); r != nil { - err = fmt.Errorf("panic in range scan: %v", r) - } - }() + // Validate start and end keys + if getStateByRange.StartKey == "" && getStateByRange.EndKey == "" { + return nil, errors.New("start key and end key must not both be empty") + } - if isCollectionSet(collection) { - if txContext.IsInitTransaction { - err = errors.New("private data APIs are not allowed in chaincode Init()") - return - } - if err = errorIfCreatorHasNoReadPermission(namespaceID, collection, txContext); err != nil { - return - } - rangeIter, err = txContext.TXSimulator.GetPrivateDataRangeScanIterator(namespaceID, collection, - getStateByRange.StartKey, getStateByRange.EndKey) - } else if isMetadataSetForPagination(metadata) { - isPaginated = true - startKey := getStateByRange.StartKey + if isCollectionSet(collection) { + if txContext.IsInitTransaction { + return nil, errors.New("private data APIs are not allowed in chaincode Init()") + } + if err := errorIfCreatorHasNoReadPermission(namespaceID, collection, txContext); err != nil { + return nil, err + } + rangeIter, err = txContext.TXSimulator.GetPrivateDataRangeScanIterator(namespaceID, collection, + getStateByRange.StartKey, getStateByRange.EndKey) + } else if isMetadataSetForPagination(metadata) { + isPaginated = true + startKey := getStateByRange.StartKey + if isMetadataSetForPagination(metadata) { if metadata.Bookmark != "" { startKey = metadata.Bookmark } - rangeIter, err = txContext.TXSimulator.GetStateRangeScanIteratorWithPagination(namespaceID, - startKey, getStateByRange.EndKey, metadata.PageSize) - } else { - rangeIter, err = txContext.TXSimulator.GetStateRangeScanIterator(namespaceID, getStateByRange.StartKey, getStateByRange.EndKey) } - }() + + // Validate page size + if metadata.PageSize < 1 { + return nil, errors.New("page size must be greater than zero") + } + + rangeIter, err = txContext.TXSimulator.GetStateRangeScanIteratorWithPagination(namespaceID, + startKey, getStateByRange.EndKey, metadata.PageSize) + } else { + rangeIter, err = txContext.TXSimulator.GetStateRangeScanIterator(namespaceID, getStateByRange.StartKey, getStateByRange.EndKey) + } if err != nil { - return nil, errors.WithMessage(err, "error getting range scan iterator") + // Clean up any resources if error occurs + txContext.CleanupQueryContext(iterID) + return nil, errors.WithStack(err) } if rangeIter == nil { - return nil, errors.New("nil iterator returned") + txContext.CleanupQueryContext(iterID) + return nil, errors.New("range query iterator is nil") } txContext.InitializeQueryContext(iterID, rangeIter) - return createResponse(txContext, rangeIter, isPaginated, totalReturnLimit) + payload, err := h.QueryResponseBuilder.BuildQueryResponse(txContext, rangeIter, iterID, isPaginated, totalReturnLimit) + if err != nil { + txContext.CleanupQueryContext(iterID) + return nil, errors.WithStack(err) + } + if payload == nil { + txContext.CleanupQueryContext(iterID) + return nil, errors.New("marshal failed: proto: Marshal called with nil") + } + + payloadBytes, err := proto.Marshal(payload) + if err != nil { + txContext.CleanupQueryContext(iterID) + return nil, errors.Wrap(err, "marshal failed") + } + + chaincodeLogger.Debugf("Got keys and values. Sending %s", pb.ChaincodeMessage_RESPONSE) + return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: payloadBytes, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil } // Handles query to ledger for query state next @@ -1320,33 +1353,3 @@ func (s State) String() string { return "UNKNOWN" } } - -// createResponse builds a QueryResponse for range queries. If the query is paginated, -// it will include bookmark information in the response. -func createResponse(txContext *TransactionContext, iter commonledger.ResultsIterator, isPaginated bool, totalReturnLimit int32) (*pb.ChaincodeMessage, error) { - // Use the QueryResponseBuilder to construct the response - payload, err := txContext.Handler.QueryResponseBuilder.BuildQueryResponse(txContext, iter, txContext.QueryIterator.GetID(), isPaginated, totalReturnLimit) - if err != nil { - txContext.CleanupQueryContext(txContext.QueryIterator.GetID()) - return nil, errors.WithStack(err) - } - if payload == nil { - txContext.CleanupQueryContext(txContext.QueryIterator.GetID()) - return nil, errors.New("marshal failed: proto: Marshal called with nil") - } - - // Marshal the payload into bytes - payloadBytes, err := proto.Marshal(payload) - if err != nil { - txContext.CleanupQueryContext(txContext.QueryIterator.GetID()) - return nil, errors.Wrap(err, "marshal failed") - } - - // Create and return the chaincode message response - return &pb.ChaincodeMessage{ - Type: pb.ChaincodeMessage_RESPONSE, - Payload: payloadBytes, - Txid: txContext.TxID, - ChannelId: txContext.ChannelID, - }, nil -} From fff8c7c45ca2c62acb4a2bd3288b1d0404b82d88 Mon Sep 17 00:00:00 2001 From: David VIEJO Date: Tue, 17 Dec 2024 14:00:48 +0100 Subject: [PATCH 4/9] Update based on the comments Signed-off-by: David VIEJO --- gossip/gossip/algo/pull.go | 21 +++++++++++++++++---- gossip/util/misc.go | 4 +++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/gossip/gossip/algo/pull.go b/gossip/gossip/algo/pull.go index 0e025804d08..ea5ef5fb13e 100644 --- a/gossip/gossip/algo/pull.go +++ b/gossip/gossip/algo/pull.go @@ -7,6 +7,8 @@ SPDX-License-Identifier: Apache-2.0 package algo import ( + "crypto/rand" + "encoding/binary" "sync" "sync/atomic" "time" @@ -322,7 +324,7 @@ func (engine *PullEngine) newNONCE() uint64 { engine.lock.Lock() defer engine.lock.Unlock() - maxAttempts := 100 + maxAttempts := 1000000 for i := 0; i < maxAttempts; i++ { n := util.RandomUInt64() if n != 0 && !engine.outgoingNONCES.Exists(n) { @@ -330,7 +332,18 @@ func (engine *PullEngine) newNONCE() uint64 { } } - // If we couldn't generate a unique NONCE after max attempts, - // use time-based fallback - return uint64(time.Now().UnixNano()) + // If we still couldn't generate a unique NONCE after max attempts, + // keep trying with crypto/rand until we find one + var n uint64 + for { + bytes := make([]byte, 8) + if _, err := rand.Read(bytes); err != nil { + // Fallback to time-based if crypto/rand fails + return uint64(time.Now().UnixNano()) + } + n = binary.BigEndian.Uint64(bytes) + if n != 0 && !engine.outgoingNONCES.Exists(n) { + return n + } + } } diff --git a/gossip/util/misc.go b/gossip/util/misc.go index b18c09597b1..aa88ecb3388 100644 --- a/gossip/util/misc.go +++ b/gossip/util/misc.go @@ -23,7 +23,9 @@ var ( ) func init() { // do we really need this? - r = rand.New(rand.NewSource(time.Now().UnixNano())) + var seed [32]byte + _, _ = crand.Read(seed[:]) + r = rand.New(rand.NewChaCha8(seed)) } // Equals returns whether a and b are the same From 3330b4a1c3eae2395a3efb30f109ea265203733a Mon Sep 17 00:00:00 2001 From: David VIEJO Date: Tue, 17 Dec 2024 15:02:24 +0100 Subject: [PATCH 5/9] Refactor comments and update import path - Corrected comment capitalization for the HandleRegister function in handler.go. - Updated the import path for the math/rand package to math/rand/v2 in misc.go. These changes improve code readability and maintain consistency in import statements. Signed-off-by: David VIEJO --- core/chaincode/handler.go | 2 +- gossip/util/misc.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/chaincode/handler.go b/core/chaincode/handler.go index 8a0f653b67e..7fb89b42a70 100644 --- a/core/chaincode/handler.go +++ b/core/chaincode/handler.go @@ -474,7 +474,7 @@ func (h *Handler) notifyRegistry(err error) { h.Registry.Ready(h.chaincodeID) } -// handleRegister is invoked when chaincode tries to register. +// HandleRegister is invoked when chaincode tries to register. func (h *Handler) HandleRegister(msg *pb.ChaincodeMessage) { h.stateLock.RLock() state := h.state diff --git a/gossip/util/misc.go b/gossip/util/misc.go index aa88ecb3388..99829f4aa32 100644 --- a/gossip/util/misc.go +++ b/gossip/util/misc.go @@ -8,7 +8,7 @@ package util import ( "fmt" - "math/rand" + "math/rand/v2" "reflect" "runtime" "sync" From 6c6880daafb96174b5274445baad0a8f5fb60771 Mon Sep 17 00:00:00 2001 From: David VIEJO Date: Tue, 17 Dec 2024 15:03:21 +0100 Subject: [PATCH 6/9] Enhance misc.go by adding crypto/rand import This commit introduces the import of the crypto/rand package in misc.go, which may be utilized for secure random number generation. This addition complements the existing math/rand/v2 import and prepares the code for future enhancements requiring cryptographic randomness. Signed-off-by: David VIEJO --- gossip/util/misc.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gossip/util/misc.go b/gossip/util/misc.go index 99829f4aa32..140fae0d19e 100644 --- a/gossip/util/misc.go +++ b/gossip/util/misc.go @@ -7,6 +7,7 @@ SPDX-License-Identifier: Apache-2.0 package util import ( + crand "crypto/rand" "fmt" "math/rand/v2" "reflect" From 367cf4fd1296c78f54203734871d9e52d3cf4d65 Mon Sep 17 00:00:00 2001 From: David VIEJO Date: Tue, 17 Dec 2024 15:04:13 +0100 Subject: [PATCH 7/9] Fix typo in RandomInt function name in misc.go This commit corrects the function name from `Intn` to `IntN` in the RandomInt function, ensuring consistency with the updated import path for the math/rand package. This change enhances code clarity and correctness. Signed-off-by: David VIEJO --- gossip/util/misc.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gossip/util/misc.go b/gossip/util/misc.go index 140fae0d19e..8cc3b1c3d6c 100644 --- a/gossip/util/misc.go +++ b/gossip/util/misc.go @@ -182,7 +182,7 @@ func SetVal(key string, val interface{}) { // RandomInt returns, as an int, a non-negative pseudo-random integer in [0,n) // It panics if n <= 0 func RandomInt(n int) int { - return r.Intn(n) + return r.IntN(n) } // RandomUInt64 returns a random uint64 From 4907e18161bf2ca5336c060c5740698efa18b2c1 Mon Sep 17 00:00:00 2001 From: David VIEJO Date: Tue, 17 Dec 2024 19:23:43 +0100 Subject: [PATCH 8/9] Revert back the changes since the bug was fixed using math/rand/v2 Signed-off-by: David VIEJO --- gossip/gossip/algo/pull.go | 26 +++----------------------- gossip/util/misc.go | 7 +------ 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/gossip/gossip/algo/pull.go b/gossip/gossip/algo/pull.go index ea5ef5fb13e..a1fd8aff7ff 100644 --- a/gossip/gossip/algo/pull.go +++ b/gossip/gossip/algo/pull.go @@ -7,8 +7,6 @@ SPDX-License-Identifier: Apache-2.0 package algo import ( - "crypto/rand" - "encoding/binary" "sync" "sync/atomic" "time" @@ -321,28 +319,10 @@ func (engine *PullEngine) OnRes(items []string, nonce uint64) { } func (engine *PullEngine) newNONCE() uint64 { - engine.lock.Lock() - defer engine.lock.Unlock() - - maxAttempts := 1000000 - for i := 0; i < maxAttempts; i++ { - n := util.RandomUInt64() - if n != 0 && !engine.outgoingNONCES.Exists(n) { - return n - } - } - - // If we still couldn't generate a unique NONCE after max attempts, - // keep trying with crypto/rand until we find one - var n uint64 + n := uint64(0) for { - bytes := make([]byte, 8) - if _, err := rand.Read(bytes); err != nil { - // Fallback to time-based if crypto/rand fails - return uint64(time.Now().UnixNano()) - } - n = binary.BigEndian.Uint64(bytes) - if n != 0 && !engine.outgoingNONCES.Exists(n) { + n = util.RandomUInt64() + if !engine.outgoingNONCES.Exists(n) { return n } } diff --git a/gossip/util/misc.go b/gossip/util/misc.go index 8cc3b1c3d6c..7d9b6d1350e 100644 --- a/gossip/util/misc.go +++ b/gossip/util/misc.go @@ -18,10 +18,7 @@ import ( "github.com/spf13/viper" ) -var ( - r *rand.Rand - rMutex sync.Mutex -) +var r *rand.Rand func init() { // do we really need this? var seed [32]byte @@ -190,8 +187,6 @@ func RandomInt(n int) int { // If we want a rand that's non-global and specific to gossip, we can // establish one. Otherwise this uses the process-global locking RNG. func RandomUInt64() uint64 { - rMutex.Lock() - defer rMutex.Unlock() return r.Uint64() } From 82226421fc227b455b576bb58bc1aeb6b0a05a6c Mon Sep 17 00:00:00 2001 From: David VIEJO Date: Tue, 17 Dec 2024 21:24:14 +0100 Subject: [PATCH 9/9] Fix some issues for leveldb Signed-off-by: David VIEJO --- .../ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go b/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go index 7c43bd177f4..9e25786a15e 100644 --- a/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go +++ b/core/ledger/kvledger/txmgmt/statedb/stateleveldb/stateleveldb.go @@ -180,7 +180,7 @@ func (vdb *versionedDB) GetStateRangeScanIteratorWithPagination(namespace string }() if err != nil { - return nil, errors.WithMessage(err, "error getting iterator from db") + return nil, err } if dbItr == nil {