Skip to content

Commit

Permalink
add support GetMultipleKeys
Browse files Browse the repository at this point in the history
Signed-off-by: Fedor Partanskiy <[email protected]>
  • Loading branch information
pfi79 committed Feb 10, 2025
1 parent 9b20f5c commit 8113427
Show file tree
Hide file tree
Showing 20 changed files with 996 additions and 28 deletions.
4 changes: 4 additions & 0 deletions core/chaincode/chaincode_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type ChaincodeSupport struct {
UserRunsCC bool
UseWriteBatch bool
MaxSizeWriteBatch uint32
UseGetMultipleKeys bool
MaxSizeGetMultipleKeys uint32
}

// Launch starts executing chaincode if it is not already running. This method
Expand Down Expand Up @@ -130,6 +132,8 @@ func (cs *ChaincodeSupport) HandleChaincodeStream(stream ccintf.ChaincodeStream)
TotalQueryLimit: cs.TotalQueryLimit,
UseWriteBatch: cs.UseWriteBatch,
MaxSizeWriteBatch: cs.MaxSizeWriteBatch,
UseGetMultipleKeys: cs.UseGetMultipleKeys,
MaxSizeGetMultipleKeys: cs.MaxSizeGetMultipleKeys,
}

return handler.ProcessStream(stream)
Expand Down
40 changes: 25 additions & 15 deletions core/chaincode/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,27 @@ import (
)

const (
defaultExecutionTimeout = 30 * time.Second
minimumStartupTimeout = 5 * time.Second
defaultMaxSizeWriteBatch = 1000
defaultExecutionTimeout = 30 * time.Second
minimumStartupTimeout = 5 * time.Second
defaultMaxSizeWriteBatch = 1000
defaultMaxSizeGetMultipleKeys = 1000
)

type Config struct {
TotalQueryLimit int
TLSEnabled bool
Keepalive time.Duration
ExecuteTimeout time.Duration
InstallTimeout time.Duration
StartupTimeout time.Duration
LogFormat string
LogLevel string
ShimLogLevel string
SCCAllowlist map[string]bool
UseWriteBatch bool
MaxSizeWriteBatch uint32
TotalQueryLimit int
TLSEnabled bool
Keepalive time.Duration
ExecuteTimeout time.Duration
InstallTimeout time.Duration
StartupTimeout time.Duration
LogFormat string
LogLevel string
ShimLogLevel string
SCCAllowlist map[string]bool
UseWriteBatch bool
MaxSizeWriteBatch uint32
UseGetMultipleKeys bool
MaxSizeGetMultipleKeys uint32
}

func GlobalConfig() *Config {
Expand Down Expand Up @@ -81,6 +84,13 @@ func (c *Config) load() {
if c.MaxSizeWriteBatch <= 0 {
c.MaxSizeWriteBatch = defaultMaxSizeWriteBatch
}
if viper.IsSet("chaincode.runtimeParams.useGetMultipleKeys") {
c.UseGetMultipleKeys = viper.GetBool("chaincode.runtimeParams.useGetMultipleKeys")
}
c.MaxSizeGetMultipleKeys = viper.GetUint32("chaincode.runtimeParams.maxSizeGetMultipleKeys")
if c.MaxSizeGetMultipleKeys <= 0 {
c.MaxSizeGetMultipleKeys = defaultMaxSizeGetMultipleKeys
}
}

func parseBool(s string) bool {
Expand Down
52 changes: 50 additions & 2 deletions core/chaincode/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ type Handler struct {
UseWriteBatch bool
// MaxSizeWriteBatch maximum batch size for the change segment
MaxSizeWriteBatch uint32
// UseGetMultipleKeys an indication that the peer can handle get multiple keys
UseGetMultipleKeys bool
// MaxSizeGetMultipleKeys maximum size of batches with get multiple keys
MaxSizeGetMultipleKeys uint32

// stateLock is used to read and set State.
stateLock sync.RWMutex
Expand Down Expand Up @@ -221,6 +225,8 @@ func (h *Handler) handleMessageReadyState(msg *pb.ChaincodeMessage) error {
go h.HandleTransaction(msg, h.HandlePurgePrivateData)
case pb.ChaincodeMessage_WRITE_BATCH_STATE:
go h.HandleTransaction(msg, h.HandleWriteBatch)
case pb.ChaincodeMessage_GET_STATE_MULTIPLE:
go h.HandleTransaction(msg, h.HandleGetStateMultipleKeys)
default:
return fmt.Errorf("[%s] Fabric side handler cannot handle message (%s) while in ready state", msg.Txid, msg.Type)
}
Expand Down Expand Up @@ -449,8 +455,10 @@ func (h *Handler) sendReady() error {
chaincodeLogger.Debugf("sending READY for chaincode %s", h.chaincodeID)

chaincodeAdditionalParams := &pb.ChaincodeAdditionalParams{
UseWriteBatch: h.UseWriteBatch,
MaxSizeWriteBatch: h.MaxSizeWriteBatch,
UseWriteBatch: h.UseWriteBatch,
MaxSizeWriteBatch: h.MaxSizeWriteBatch,
UseGetMultipleKeys: h.UseGetMultipleKeys,
MaxSizeGetMultipleKeys: h.MaxSizeGetMultipleKeys,
}
payloadBytes, err := proto.Marshal(chaincodeAdditionalParams)
if err != nil {
Expand Down Expand Up @@ -678,6 +686,46 @@ func (h *Handler) HandleGetState(msg *pb.ChaincodeMessage, txContext *Transactio
return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: res, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil
}

// Handles query to ledger to get state
func (h *Handler) HandleGetStateMultipleKeys(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {
getState := &pb.GetStateMultiple{}
err := proto.Unmarshal(msg.Payload, getState)
if err != nil {
return nil, errors.Wrap(err, "unmarshal failed")
}

var res [][]byte
namespaceID := txContext.NamespaceID
collection := getState.GetCollection()
chaincodeLogger.Debugf("[%s] getting state for chaincode %s, keys %v, channel %s", shorttxid(msg.Txid), namespaceID, getState.GetKeys(), txContext.ChannelID)

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
}
res, err = txContext.TXSimulator.GetPrivateDataMultipleKeys(namespaceID, collection, getState.GetKeys())
} else {
res, err = txContext.TXSimulator.GetStateMultipleKeys(namespaceID, getState.GetKeys())
}
if err != nil {
return nil, errors.WithStack(err)
}
if len(res) == 0 {
chaincodeLogger.Debugf("[%s] No state associated with keys: %v. Sending %s with an empty payload", shorttxid(msg.Txid), getState.GetKeys(), pb.ChaincodeMessage_RESPONSE)
}

payloadBytes, err := proto.Marshal(&pb.GetStateMultipleResult{Values: res})
if err != nil {
return nil, errors.Wrap(err, "marshal failed")
}

// Send response msg back to chaincode. GetState will not trigger event
return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: payloadBytes, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil
}

func (h *Handler) HandleGetPrivateDataHash(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {
getState := &pb.GetState{}
err := proto.Unmarshal(msg.Payload, getState)
Expand Down
16 changes: 10 additions & 6 deletions core/chaincode/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,12 @@ var _ = Describe("Handler", func() {
UUIDGenerator: chaincode.UUIDGeneratorFunc(func() string {
return "generated-query-id"
}),
AppConfig: fakeApplicationConfigRetriever,
Metrics: chaincodeMetrics,
UseWriteBatch: true,
MaxSizeWriteBatch: 1000,
AppConfig: fakeApplicationConfigRetriever,
Metrics: chaincodeMetrics,
UseWriteBatch: true,
MaxSizeWriteBatch: 1000,
UseGetMultipleKeys: true,
MaxSizeGetMultipleKeys: 1000,
}
chaincode.SetHandlerChatStream(handler, fakeChatStream)
chaincode.SetHandlerChaincodeID(handler, "test-handler-name:1.0")
Expand Down Expand Up @@ -2786,8 +2788,10 @@ var _ = Describe("Handler", func() {
}))

chaincodeAdditionalParams := &pb.ChaincodeAdditionalParams{
UseWriteBatch: true,
MaxSizeWriteBatch: 1000,
UseWriteBatch: true,
MaxSizeWriteBatch: 1000,
UseGetMultipleKeys: true,
MaxSizeGetMultipleKeys: 1000,
}
payloadBytes, err := proto.Marshal(chaincodeAdditionalParams)
Expect(err).NotTo(HaveOccurred())
Expand Down
160 changes: 160 additions & 0 deletions core/chaincode/lifecycle/mock/chaincode_stub.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 8113427

Please sign in to comment.