Skip to content

Commit 36a60d3

Browse files
Add del_state support (#640)
* Add del_state support * Add test cases Signed-off-by: Marcus Brandenburger <[email protected]>
1 parent 5febb77 commit 36a60d3

File tree

11 files changed

+117
-18
lines changed

11 files changed

+117
-18
lines changed

ecc/chaincode/enclave/shim.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,20 @@ func get_state_by_partial_composite_key(comp_key *C.char, values *C.uint8_t, max
182182
C._cpy_bytes(values, (*C.uint8_t)(C.CBytes(data)), C.uint32_t(len(data)))
183183
C._set_int(values_len, C.uint32_t(len(data)))
184184
}
185+
186+
//export del_state
187+
func del_state(key *C.char, ctx unsafe.Pointer) {
188+
stubs := registry.get(*(*int)(ctx))
189+
190+
// check if composite key
191+
key_str := C.GoString(key)
192+
if utils.IsFPCCompositeKey(key_str) {
193+
comp := utils.SplitFPCCompositeKey(key_str)
194+
key_str, _ = stubs.shimStub.CreateCompositeKey(comp[0], comp[1:])
195+
}
196+
197+
err := stubs.shimStub.DelState(key_str)
198+
if err != nil {
199+
panic("error while deleting state")
200+
}
201+
}

ecc_enclave/enclave/enclave.edl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ enclave {
3535
[in, string] const char *comp_key,
3636
[out, size=max_len] uint8_t *values, uint32_t max_len, [out] uint32_t *values_len,
3737
[user_check] void *u_shim_ctx);
38+
39+
void ocall_del_state(
40+
[in, string] const char *key,
41+
[user_check] void *u_shim_ctx);
3842
};
3943

4044
};

ecc_enclave/enclave/shim.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ void put_public_state(const char* key, uint8_t* val, uint32_t val_len, shim_ctx_
170170
// save write -- only the last one for the same key
171171
ctx->write_set.erase(key);
172172
ctx->write_set.insert({key, ByteArray(val, val + val_len)});
173+
ctx->del_set.erase(key);
173174

174175
ocall_put_state(key, val, val_len, ctx->u_shim_ctx);
175176
}
@@ -250,6 +251,15 @@ void get_public_state_by_partial_composite_key(
250251
unmarshal_values(values, (const char*)json, len);
251252
}
252253

254+
void del_state(const char* key, shim_ctx_ptr_t ctx)
255+
{
256+
ctx->write_set.erase(key);
257+
ctx->del_set.insert(key);
258+
259+
ocall_del_state(key, ctx->u_shim_ctx);
260+
return;
261+
}
262+
253263
int get_string_args(std::vector<std::string>& argss, shim_ctx_ptr_t ctx)
254264
{
255265
argss = ctx->string_args;

ecc_enclave/enclave/shim.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ void get_public_state_by_partial_composite_key(
166166
//
167167
// - other functions: {get,set}StateValidationParameter, getHistoryForKey. Can/should we ignore?
168168

169+
// - records the given `key` to be deleted in the writeset.
170+
void del_state(const char* key, shim_ctx_ptr_t ctx);
171+
169172
// retrieval for arguments
170173
//-------------------------------------------------
171174
// - retrieve the list of invocation parameters

ecc_enclave/enclave/shim_internals.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ bool rwset_to_proto(t_shim_ctx_t* ctx, fpc_FPCKVSet* fpc_rwset_proto)
2121

2222
COND2LOGERR(ctx == NULL || fpc_rwset_proto == NULL, "invalid input parameters");
2323

24-
LOG_DEBUG("Prepare rwset serialization");
24+
LOG_DEBUG("Prepare Fabric RWSet construction");
2525

2626
// reset structure
2727
*fpc_rwset_proto = fpc_FPCKVSet_init_default;
@@ -39,12 +39,12 @@ bool rwset_to_proto(t_shim_ctx_t* ctx, fpc_FPCKVSet* fpc_rwset_proto)
3939
COND2ERR(fpc_rwset_proto->rw_set.reads == NULL);
4040

4141
// initialiaze write sets (i.e., the arrays; later we serialize single items)
42-
fpc_rwset_proto->rw_set.writes_count = ctx->write_set.size();
42+
fpc_rwset_proto->rw_set.writes_count = ctx->write_set.size() + ctx->del_set.size();
4343
fpc_rwset_proto->rw_set.writes = (kvrwset_KVWrite*)pb_realloc(
4444
NULL, fpc_rwset_proto->rw_set.writes_count * sizeof(kvrwset_KVWrite));
4545
COND2ERR(fpc_rwset_proto->rw_set.writes == NULL);
4646

47-
LOG_DEBUG("Serializing read set items");
47+
LOG_DEBUG("Add read_set items");
4848
i = 0;
4949
for (auto it = ctx->read_set.begin(); it != ctx->read_set.end(); it++, i++)
5050
{
@@ -70,7 +70,7 @@ bool rwset_to_proto(t_shim_ctx_t* ctx, fpc_FPCKVSet* fpc_rwset_proto)
7070
COND2ERR(ret != 0);
7171
}
7272

73-
LOG_DEBUG("Serializing write set items");
73+
LOG_DEBUG("Add write_set items");
7474
i = 0;
7575
for (auto it = ctx->write_set.begin(); it != ctx->write_set.end(); it++, i++)
7676
{
@@ -98,7 +98,30 @@ bool rwset_to_proto(t_shim_ctx_t* ctx, fpc_FPCKVSet* fpc_rwset_proto)
9898
COND2ERR(ret != 0);
9999
}
100100

101-
LOG_DEBUG("Serialization successful");
101+
LOG_DEBUG("Add del_set items");
102+
for (auto it = ctx->del_set.begin(); it != ctx->del_set.end(); it++, i++)
103+
{
104+
// note that we continue to use i without resetting since we are appending to the
105+
// rw_set.writes
106+
LOG_DEBUG("k=%s", it->c_str());
107+
108+
// serialize write
109+
fpc_rwset_proto->rw_set.writes[i].is_delete = true;
110+
111+
// serialize key
112+
fpc_rwset_proto->rw_set.writes[i].key = (char*)pb_realloc(NULL, it->length() + 1);
113+
COND2ERR(fpc_rwset_proto->rw_set.writes[i].key == NULL);
114+
ret = memcpy_s(
115+
fpc_rwset_proto->rw_set.writes[i].key, it->length(), it->c_str(), it->length());
116+
fpc_rwset_proto->rw_set.writes[i].key[it->length()] = '\0';
117+
COND2ERR(ret != 0);
118+
119+
fpc_rwset_proto->rw_set.writes[i].value =
120+
(pb_bytes_array_t*)pb_realloc(NULL, PB_BYTES_ARRAY_T_ALLOCSIZE(0));
121+
COND2ERR(fpc_rwset_proto->rw_set.writes[i].value == NULL);
122+
}
123+
124+
LOG_DEBUG("Fabric RWSet construction successful");
102125
return true;
103126

104127
err:

ecc_enclave/enclave/shim_internals.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@
1616
// read/writeset
1717
typedef std::map<std::string, ByteArray> write_set_t;
1818
typedef std::map<std::string, ByteArray> read_set_t;
19+
typedef std::set<std::string> del_set_t;
1920

2021
// shim context
2122
typedef struct t_shim_ctx
2223
{
2324
void* u_shim_ctx;
2425
read_set_t read_set;
2526
write_set_t write_set;
27+
del_set_t del_set;
2628
std::vector<std::string> string_args;
2729
ByteArray signed_proposal;
2830
std::string tx_id;

ecc_enclave/sgxcclib/sgxcclib.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extern void get_state(
1818
extern void get_state_by_partial_composite_key(
1919
const char* comp_key, uint8_t* values, uint32_t max_len, uint32_t* values_len, void* ctx);
2020
extern void put_state(const char* key, uint8_t* val, uint32_t val_len, void* ctx);
21+
extern void del_state(const char* key, void* ctx);
2122

2223
int sgxcc_invoke(enclave_id_t eid,
2324
const uint8_t* signed_proposal_proto_bytes,
@@ -56,3 +57,8 @@ void ocall_get_state_by_partial_composite_key(
5657
{
5758
get_state_by_partial_composite_key(key, bids_bytes, max_len, bids_bytes_len, ctx);
5859
}
60+
61+
void ocall_del_state(const char* key, void* ctx)
62+
{
63+
del_state(key, ctx);
64+
}

integration/client_sdk/go/stress_test/stress_test.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ const (
3535
)
3636

3737
var (
38-
network *gateway.Network
39-
echoContract fpc.Contract
38+
network *gateway.Network
39+
contract fpc.Contract
4040
)
4141

4242
var _ = BeforeSuite(func() {
@@ -53,8 +53,8 @@ var _ = BeforeSuite(func() {
5353
Expect(network).ShouldNot(BeNil())
5454

5555
// Get FPC Contract
56-
echoContract = fpc.GetContract(network, ccID)
57-
Expect(echoContract).ShouldNot(BeNil())
56+
contract = fpc.GetContract(network, ccID)
57+
Expect(contract).ShouldNot(BeNil())
5858
})
5959

6060
var _ = Describe("Stress tests", func() {
@@ -73,13 +73,17 @@ var _ = Describe("Stress tests", func() {
7373
key := "some-key"
7474
value := base64.StdEncoding.EncodeToString(payload)
7575

76-
res, err := echoContract.SubmitTransaction("put_state", key, value)
76+
res, err := contract.SubmitTransaction("put_state", key, value)
7777
Expect(err).ShouldNot(HaveOccurred())
7878
Expect(res).Should(Equal([]byte("OK")))
7979

80-
res, err = echoContract.EvaluateTransaction("get_state", key)
80+
res, err = contract.EvaluateTransaction("get_state", key)
8181
Expect(err).ShouldNot(HaveOccurred())
8282
Expect(res).Should(Equal([]byte(value)))
83+
84+
res, err = contract.SubmitTransaction("del_state", key)
85+
Expect(err).ShouldNot(HaveOccurred())
86+
Expect(res).Should(Equal([]byte("OK")))
8387
}
8488
})
8589
})
@@ -99,7 +103,7 @@ var _ = Describe("Stress tests", func() {
99103
Expect(n).Should(Equal(size))
100104

101105
value := base64.StdEncoding.EncodeToString(payload)
102-
res, err := echoContract.SubmitTransaction("put_state", key, value)
106+
res, err := contract.SubmitTransaction("put_state", key, value)
103107
Expect(err).ShouldNot(HaveOccurred())
104108
Expect(res).Should(Equal([]byte("OK")))
105109

@@ -108,7 +112,7 @@ var _ = Describe("Stress tests", func() {
108112
if i%10 == 0 {
109113
fmt.Printf("i=%d\n", i)
110114
}
111-
res, err = echoContract.EvaluateTransaction("get_state", key)
115+
res, err = contract.EvaluateTransaction("get_state", key)
112116
Expect(err).ShouldNot(HaveOccurred())
113117
Expect(res).Should(Equal([]byte(value)))
114118
}

integration/kv_test.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ kv_test() {
4343

4444
try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"put_state", "Args": ["echo-0", "echo-0"]}' --waitForEvent
4545
check_result "OK"
46+
try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"get_state", "Args": ["echo-0"]}' --waitForEvent
47+
check_result "echo-0"
48+
try_out_r ${PEER_CMD} chaincode invoke -o ${ORDERER_ADDR} -C ${CHAN_ID} -n ${CC_ID} -c '{"Function":"del_state", "Args": ["echo-0"]}' --waitForEvent
49+
check_result "OK"
4650
}
4751

4852
# 1. prepare

internal/endorsement/validation.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ func (v *ValidatorImpl) ReplayReadWrites(stub shim.ChaincodeStubInterface, fpcrw
6060

6161
for i := 0; i < len(rwset.Reads); i++ {
6262
k := utils.TransformToFPCKey(rwset.Reads[i].Key)
63+
64+
// check if composite key, if so, derive Fabric key
65+
if utils.IsFPCCompositeKey(k) {
66+
comp := utils.SplitFPCCompositeKey(k)
67+
k, _ = stub.CreateCompositeKey(comp[0], comp[1:])
68+
}
69+
6370
v, err := stub.GetState(k)
6471
if err != nil {
6572
return fmt.Errorf("error (%s) reading key %s", err, k)
@@ -118,12 +125,17 @@ func (v *ValidatorImpl) ReplayReadWrites(stub shim.ChaincodeStubInterface, fpcrw
118125
k, _ = stub.CreateCompositeKey(comp[0], comp[1:])
119126
}
120127

121-
err := stub.PutState(k, w.Value)
122-
if err != nil {
123-
return fmt.Errorf("error (%s) writing key %s value(hex) %s", err, k, hex.EncodeToString(w.Value))
128+
if w.IsDelete {
129+
if err := stub.DelState(k); err != nil {
130+
return fmt.Errorf("error (%s) deleting key %s", err, k)
131+
}
132+
logger.Debugf("key %s deleted", k)
133+
} else {
134+
if err := stub.PutState(k, w.Value); err != nil {
135+
return fmt.Errorf("error (%s) writing key %s value(hex) %s", err, k, hex.EncodeToString(w.Value))
136+
}
137+
logger.Debugf("written key %s value(hex) %s", k, hex.EncodeToString(w.Value))
124138
}
125-
126-
logger.Debugf("written key %s value(hex) %s", k, hex.EncodeToString(w.Value))
127139
}
128140
}
129141

0 commit comments

Comments
 (0)