Skip to content

Commit bc5a61f

Browse files
committed
add support GetMultipleKeys
Signed-off-by: Fedor Partanskiy <[email protected]>
1 parent e22c269 commit bc5a61f

File tree

11 files changed

+634
-29
lines changed

11 files changed

+634
-29
lines changed

core/chaincode/chaincode_support.go

+4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ type ChaincodeSupport struct {
7575
UserRunsCC bool
7676
UseWriteBatch bool
7777
MaxSizeWriteBatch uint32
78+
UseGetMultipleKeys bool
79+
MaxSizeGetMultipleKeys uint32
7880
}
7981

8082
// Launch starts executing chaincode if it is not already running. This method
@@ -130,6 +132,8 @@ func (cs *ChaincodeSupport) HandleChaincodeStream(stream ccintf.ChaincodeStream)
130132
TotalQueryLimit: cs.TotalQueryLimit,
131133
UseWriteBatch: cs.UseWriteBatch,
132134
MaxSizeWriteBatch: cs.MaxSizeWriteBatch,
135+
UseGetMultipleKeys: cs.UseGetMultipleKeys,
136+
MaxSizeGetMultipleKeys: cs.MaxSizeGetMultipleKeys,
133137
}
134138

135139
return handler.ProcessStream(stream)

core/chaincode/config.go

+25-15
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,27 @@ import (
1616
)
1717

1818
const (
19-
defaultExecutionTimeout = 30 * time.Second
20-
minimumStartupTimeout = 5 * time.Second
21-
defaultMaxSizeWriteBatch = 1000
19+
defaultExecutionTimeout = 30 * time.Second
20+
minimumStartupTimeout = 5 * time.Second
21+
defaultMaxSizeWriteBatch = 1000
22+
defaultMaxSizeGetMultipleKeys = 1000
2223
)
2324

2425
type Config struct {
25-
TotalQueryLimit int
26-
TLSEnabled bool
27-
Keepalive time.Duration
28-
ExecuteTimeout time.Duration
29-
InstallTimeout time.Duration
30-
StartupTimeout time.Duration
31-
LogFormat string
32-
LogLevel string
33-
ShimLogLevel string
34-
SCCAllowlist map[string]bool
35-
UseWriteBatch bool
36-
MaxSizeWriteBatch uint32
26+
TotalQueryLimit int
27+
TLSEnabled bool
28+
Keepalive time.Duration
29+
ExecuteTimeout time.Duration
30+
InstallTimeout time.Duration
31+
StartupTimeout time.Duration
32+
LogFormat string
33+
LogLevel string
34+
ShimLogLevel string
35+
SCCAllowlist map[string]bool
36+
UseWriteBatch bool
37+
MaxSizeWriteBatch uint32
38+
UseGetMultipleKeys bool
39+
MaxSizeGetMultipleKeys uint32
3740
}
3841

3942
func GlobalConfig() *Config {
@@ -81,6 +84,13 @@ func (c *Config) load() {
8184
if c.MaxSizeWriteBatch <= 0 {
8285
c.MaxSizeWriteBatch = defaultMaxSizeWriteBatch
8386
}
87+
if viper.IsSet("chaincode.runtimeParams.useGetMultipleKeys") {
88+
c.UseGetMultipleKeys = viper.GetBool("chaincode.runtimeParams.useGetMultipleKeys")
89+
}
90+
c.MaxSizeGetMultipleKeys = viper.GetUint32("chaincode.runtimeParams.maxSizeGetMultipleKeys")
91+
if c.MaxSizeGetMultipleKeys <= 0 {
92+
c.MaxSizeGetMultipleKeys = defaultMaxSizeGetMultipleKeys
93+
}
8494
}
8595

8696
func parseBool(s string) bool {

core/chaincode/config_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ var _ = Describe("Config", func() {
3737
viper.Set("chaincode.logging.level", "warning")
3838
viper.Set("chaincode.logging.shim", "warning")
3939
viper.Set("chaincode.system.somecc", true)
40+
viper.Set("chaincode.runtimeParams.useWriteBatch", true)
41+
viper.Set("chaincode.runtimeParams.maxSizeWriteBatch", 1001)
42+
viper.Set("chaincode.runtimeParams.useGetMultipleKeys", true)
43+
viper.Set("chaincode.runtimeParams.maxSizeGetMultipleKeys", 1001)
4044

4145
config := chaincode.GlobalConfig()
4246
Expect(config.TLSEnabled).To(BeTrue())
@@ -48,6 +52,10 @@ var _ = Describe("Config", func() {
4852
Expect(config.LogLevel).To(Equal("warn"))
4953
Expect(config.ShimLogLevel).To(Equal("warn"))
5054
Expect(config.SCCAllowlist).To(Equal(map[string]bool{"somecc": true}))
55+
Expect(config.UseWriteBatch).To(BeTrue())
56+
Expect(config.MaxSizeWriteBatch).To(Equal(uint32(1001)))
57+
Expect(config.UseGetMultipleKeys).To(BeTrue())
58+
Expect(config.MaxSizeGetMultipleKeys).To(Equal(uint32(1001)))
5159
})
5260

5361
Context("when an invalid keepalive is configured", func() {
@@ -95,6 +103,40 @@ var _ = Describe("Config", func() {
95103
Expect(config.ShimLogLevel).To(Equal("info"))
96104
})
97105
})
106+
107+
Context("when an runtime params is false and zero", func() {
108+
BeforeEach(func() {
109+
viper.Set("chaincode.runtimeParams.useWriteBatch", false)
110+
viper.Set("chaincode.runtimeParams.maxSizeWriteBatch", 0)
111+
viper.Set("chaincode.runtimeParams.useGetMultipleKeys", false)
112+
viper.Set("chaincode.runtimeParams.maxSizeGetMultipleKeys", 0)
113+
})
114+
115+
It("check runtime params", func() {
116+
config := chaincode.GlobalConfig()
117+
Expect(config.UseWriteBatch).To(BeFalse())
118+
Expect(config.MaxSizeWriteBatch).To(Equal(uint32(1000)))
119+
Expect(config.UseGetMultipleKeys).To(BeFalse())
120+
Expect(config.MaxSizeGetMultipleKeys).To(Equal(uint32(1000)))
121+
})
122+
})
123+
124+
Context("when an invalid runtime params", func() {
125+
BeforeEach(func() {
126+
viper.Set("chaincode.runtimeParams.useWriteBatch", "abc")
127+
viper.Set("chaincode.runtimeParams.maxSizeWriteBatch", "abc")
128+
viper.Set("chaincode.runtimeParams.useGetMultipleKeys", "abc")
129+
viper.Set("chaincode.runtimeParams.maxSizeGetMultipleKeys", "abc")
130+
})
131+
132+
It("check runtime params", func() {
133+
config := chaincode.GlobalConfig()
134+
Expect(config.UseWriteBatch).To(BeFalse())
135+
Expect(config.MaxSizeWriteBatch).To(Equal(uint32(1000)))
136+
Expect(config.UseGetMultipleKeys).To(BeFalse())
137+
Expect(config.MaxSizeGetMultipleKeys).To(Equal(uint32(1000)))
138+
})
139+
})
98140
})
99141

100142
Describe("IsDevMode", func() {

core/chaincode/handler.go

+50-2
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ type Handler struct {
134134
UseWriteBatch bool
135135
// MaxSizeWriteBatch maximum batch size for the change segment
136136
MaxSizeWriteBatch uint32
137+
// UseGetMultipleKeys an indication that the peer can handle get multiple keys
138+
UseGetMultipleKeys bool
139+
// MaxSizeGetMultipleKeys maximum size of batches with get multiple keys
140+
MaxSizeGetMultipleKeys uint32
137141

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

451457
chaincodeAdditionalParams := &pb.ChaincodeAdditionalParams{
452-
UseWriteBatch: h.UseWriteBatch,
453-
MaxSizeWriteBatch: h.MaxSizeWriteBatch,
458+
UseWriteBatch: h.UseWriteBatch,
459+
MaxSizeWriteBatch: h.MaxSizeWriteBatch,
460+
UseGetMultipleKeys: h.UseGetMultipleKeys,
461+
MaxSizeGetMultipleKeys: h.MaxSizeGetMultipleKeys,
454462
}
455463
payloadBytes, err := proto.Marshal(chaincodeAdditionalParams)
456464
if err != nil {
@@ -678,6 +686,46 @@ func (h *Handler) HandleGetState(msg *pb.ChaincodeMessage, txContext *Transactio
678686
return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: res, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil
679687
}
680688

689+
// Handles query to ledger to get state
690+
func (h *Handler) HandleGetStateMultipleKeys(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {
691+
getState := &pb.GetStateMultiple{}
692+
err := proto.Unmarshal(msg.Payload, getState)
693+
if err != nil {
694+
return nil, errors.Wrap(err, "unmarshal failed")
695+
}
696+
697+
var res [][]byte
698+
namespaceID := txContext.NamespaceID
699+
collection := getState.GetCollection()
700+
chaincodeLogger.Debugf("[%s] getting state for chaincode %s, keys %v, channel %s", shorttxid(msg.Txid), namespaceID, getState.GetKeys(), txContext.ChannelID)
701+
702+
if isCollectionSet(collection) {
703+
if txContext.IsInitTransaction {
704+
return nil, errors.New("private data APIs are not allowed in chaincode Init()")
705+
}
706+
if err = errorIfCreatorHasNoReadPermission(namespaceID, collection, txContext); err != nil {
707+
return nil, err
708+
}
709+
res, err = txContext.TXSimulator.GetPrivateDataMultipleKeys(namespaceID, collection, getState.GetKeys())
710+
} else {
711+
res, err = txContext.TXSimulator.GetStateMultipleKeys(namespaceID, getState.GetKeys())
712+
}
713+
if err != nil {
714+
return nil, errors.WithStack(err)
715+
}
716+
if len(res) == 0 {
717+
chaincodeLogger.Debugf("[%s] No state associated with keys: %v. Sending %s with an empty payload", shorttxid(msg.Txid), getState.GetKeys(), pb.ChaincodeMessage_RESPONSE)
718+
}
719+
720+
payloadBytes, err := proto.Marshal(&pb.GetStateMultipleResult{Values: res})
721+
if err != nil {
722+
return nil, errors.Wrap(err, "marshal failed")
723+
}
724+
725+
// Send response msg back to chaincode. GetState will not trigger event
726+
return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE, Payload: payloadBytes, Txid: msg.Txid, ChannelId: msg.ChannelId}, nil
727+
}
728+
681729
func (h *Handler) HandleGetPrivateDataHash(msg *pb.ChaincodeMessage, txContext *TransactionContext) (*pb.ChaincodeMessage, error) {
682730
getState := &pb.GetState{}
683731
err := proto.Unmarshal(msg.Payload, getState)

0 commit comments

Comments
 (0)