Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support GetMultipleKeys #5140

Merged
merged 1 commit into from
Feb 11, 2025
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
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
42 changes: 42 additions & 0 deletions core/chaincode/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ var _ = Describe("Config", func() {
viper.Set("chaincode.logging.level", "warning")
viper.Set("chaincode.logging.shim", "warning")
viper.Set("chaincode.system.somecc", true)
viper.Set("chaincode.runtimeParams.useWriteBatch", true)
viper.Set("chaincode.runtimeParams.maxSizeWriteBatch", 1001)
viper.Set("chaincode.runtimeParams.useGetMultipleKeys", true)
viper.Set("chaincode.runtimeParams.maxSizeGetMultipleKeys", 1001)

config := chaincode.GlobalConfig()
Expect(config.TLSEnabled).To(BeTrue())
Expand All @@ -48,6 +52,10 @@ var _ = Describe("Config", func() {
Expect(config.LogLevel).To(Equal("warn"))
Expect(config.ShimLogLevel).To(Equal("warn"))
Expect(config.SCCAllowlist).To(Equal(map[string]bool{"somecc": true}))
Expect(config.UseWriteBatch).To(BeTrue())
Expect(config.MaxSizeWriteBatch).To(Equal(uint32(1001)))
Expect(config.UseGetMultipleKeys).To(BeTrue())
Expect(config.MaxSizeGetMultipleKeys).To(Equal(uint32(1001)))
})

Context("when an invalid keepalive is configured", func() {
Expand Down Expand Up @@ -95,6 +103,40 @@ var _ = Describe("Config", func() {
Expect(config.ShimLogLevel).To(Equal("info"))
})
})

Context("when an runtime params is false and zero", func() {
BeforeEach(func() {
viper.Set("chaincode.runtimeParams.useWriteBatch", false)
viper.Set("chaincode.runtimeParams.maxSizeWriteBatch", 0)
viper.Set("chaincode.runtimeParams.useGetMultipleKeys", false)
viper.Set("chaincode.runtimeParams.maxSizeGetMultipleKeys", 0)
})

It("check runtime params", func() {
config := chaincode.GlobalConfig()
Expect(config.UseWriteBatch).To(BeFalse())
Expect(config.MaxSizeWriteBatch).To(Equal(uint32(1000)))
Expect(config.UseGetMultipleKeys).To(BeFalse())
Expect(config.MaxSizeGetMultipleKeys).To(Equal(uint32(1000)))
})
})

Context("when an invalid runtime params", func() {
BeforeEach(func() {
viper.Set("chaincode.runtimeParams.useWriteBatch", "abc")
viper.Set("chaincode.runtimeParams.maxSizeWriteBatch", "abc")
viper.Set("chaincode.runtimeParams.useGetMultipleKeys", "abc")
viper.Set("chaincode.runtimeParams.maxSizeGetMultipleKeys", "abc")
})

It("check runtime params", func() {
config := chaincode.GlobalConfig()
Expect(config.UseWriteBatch).To(BeFalse())
Expect(config.MaxSizeWriteBatch).To(Equal(uint32(1000)))
Expect(config.UseGetMultipleKeys).To(BeFalse())
Expect(config.MaxSizeGetMultipleKeys).To(Equal(uint32(1000)))
})
})
})

Describe("IsDevMode", func() {
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
}

// HandleGetStateMultipleKeys 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
Loading