Skip to content

Commit df9bccd

Browse files
fixup! Reuse simpletxidstore
Signed-off-by: Alexandros Filios <[email protected]>
1 parent 1032657 commit df9bccd

File tree

9 files changed

+371
-788
lines changed

9 files changed

+371
-788
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package vault
8+
9+
type ValidationCode interface {
10+
comparable
11+
}
12+
13+
type ValidationCodeProvider[V ValidationCode] interface {
14+
IsValid(V) bool
15+
ToInt32(V) int32
16+
FromInt32(int32) V
17+
Unknown() V
18+
}
19+
20+
type SeekStart struct{}
21+
22+
type SeekEnd struct{}
23+
24+
type SeekPos struct {
25+
Txid string
26+
}
27+
28+
type SeekSet struct {
29+
TxIDs []string
30+
}
31+
32+
type ByNum[V comparable] struct {
33+
TxID string
34+
Code V
35+
Message string
36+
}
37+
38+
type TxIDIterator[V comparable] interface {
39+
Next() (*ByNum[V], error)
40+
Close()
41+
}
42+
43+
type TXIDStore[V comparable] interface {
44+
GetLastTxID() (string, error)
45+
Iterator(pos interface{}) (TxIDIterator[V], error)
46+
}

platform/fabric/core/generic/vault/txidstore/ftxid.proto renamed to platform/common/core/generic/vault/txidstore/ftxid.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
syntax = "proto3";
22

3-
option go_package = "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic/vault/txidstore";
3+
option go_package = "github.com/hyperledger-labs/fabric-smart-client/platform/common/core/generic/vault/txidstore";
44

55
package txidstore;
66

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package txidstore
8+
9+
import (
10+
"encoding/binary"
11+
"math"
12+
13+
errors2 "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
14+
"github.com/hyperledger-labs/fabric-smart-client/platform/common/core/generic/vault"
15+
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils"
16+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver"
17+
"github.com/pkg/errors"
18+
"google.golang.org/protobuf/proto"
19+
)
20+
21+
//go:generate protoc -I=. --go_out=. ftxid.proto
22+
23+
const (
24+
txidNamespace = "txid"
25+
ctrKey = "ctr"
26+
byCtrPrefix = "C"
27+
byTxidPrefix = "T"
28+
lastTX = "last"
29+
)
30+
31+
type SimpleTXIDStore[V vault.ValidationCode] struct {
32+
persistence driver.Persistence
33+
ctr uint64
34+
vcProvider vault.ValidationCodeProvider[V]
35+
}
36+
37+
func NewSimpleTXIDStore[V vault.ValidationCode](persistence driver.Persistence, vcProvider vault.ValidationCodeProvider[V]) (*SimpleTXIDStore[V], error) {
38+
ctrBytes, err := persistence.GetState(txidNamespace, ctrKey)
39+
if err != nil {
40+
return nil, errors.Errorf("error retrieving txid counter [%s]", err.Error())
41+
}
42+
43+
if ctrBytes == nil {
44+
if err = persistence.BeginUpdate(); err != nil {
45+
return nil, errors.Errorf("error starting update to store counter [%s]", err.Error())
46+
}
47+
48+
err = setCtr(persistence, 0)
49+
if err != nil {
50+
persistence.Discard()
51+
return nil, err
52+
}
53+
54+
if err = persistence.Commit(); err != nil {
55+
return nil, errors.Errorf("error committing update to store counter [%s]", err.Error())
56+
}
57+
58+
ctrBytes = make([]byte, binary.MaxVarintLen64)
59+
}
60+
61+
return &SimpleTXIDStore[V]{
62+
persistence: persistence,
63+
ctr: getCtrFromBytes(ctrBytes),
64+
vcProvider: vcProvider,
65+
}, nil
66+
}
67+
68+
func (s *SimpleTXIDStore[V]) get(txID string) (*ByTxid, error) {
69+
bytes, err := s.persistence.GetState(txidNamespace, keyByTxID(txID))
70+
if err != nil {
71+
return nil, errors.Errorf("error retrieving txid %s [%s]", txID, err.Error())
72+
}
73+
74+
if len(bytes) == 0 {
75+
return nil, nil
76+
}
77+
78+
bt := &ByTxid{}
79+
err = proto.Unmarshal(bytes, bt)
80+
if err != nil {
81+
return nil, errors.Errorf("error unmarshalling data for txid %s [%s]", txID, err.Error())
82+
}
83+
84+
return bt, nil
85+
}
86+
87+
func (s *SimpleTXIDStore[V]) Get(txID string) (V, string, error) {
88+
bt, err := s.get(txID)
89+
if err != nil {
90+
return s.vcProvider.Unknown(), "", err
91+
}
92+
93+
if bt == nil {
94+
return s.vcProvider.Unknown(), "", nil
95+
}
96+
97+
return s.vcProvider.FromInt32(bt.Code), bt.Message, nil
98+
}
99+
100+
func (s *SimpleTXIDStore[V]) Set(txID string, code V, message string) error {
101+
// NOTE: we assume that the commit is in progress so no need to update/commit
102+
// err := s.persistence.BeginUpdate()
103+
// if err != nil {
104+
// return errors.Errorf("error starting update to set txid %s [%s]", txid, err.Error())
105+
// }
106+
107+
// 1: increment ctr in persistence
108+
err := setCtr(s.persistence, s.ctr+1)
109+
if err != nil { // TODO: && !errors2.HasCause(err, driver.UniqueKeyViolation)
110+
s.persistence.Discard()
111+
return errors.Errorf("error storing updated counter for txid %s [%s]", txID, err.Error())
112+
}
113+
114+
// 2: store by counter
115+
byCtrBytes, err := proto.Marshal(&ByNum{
116+
Txid: txID,
117+
Code: s.vcProvider.ToInt32(code),
118+
Message: message,
119+
})
120+
if err != nil {
121+
s.persistence.Discard()
122+
return errors.Errorf("error marshalling ByNum for txID %s [%s]", txID, err.Error())
123+
}
124+
err = s.persistence.SetState(txidNamespace, keyByCtr(s.ctr), byCtrBytes)
125+
if err != nil { // TODO: && !errors2.HasCause(err, driver.UniqueKeyViolation)
126+
s.persistence.Discard()
127+
return errors.Errorf("error storing ByNum for txid %s [%s]", txID, err.Error())
128+
}
129+
130+
// 3: store by txid
131+
byTxidBytes, err := proto.Marshal(&ByTxid{
132+
Pos: s.ctr,
133+
Code: s.vcProvider.ToInt32(code),
134+
Message: message,
135+
})
136+
if err != nil {
137+
s.persistence.Discard()
138+
return errors.Errorf("error marshalling ByTxid for txid %s [%s]", txID, err.Error())
139+
}
140+
err = s.persistence.SetState(txidNamespace, keyByTxID(txID), byTxidBytes)
141+
if err != nil {
142+
s.persistence.Discard()
143+
return errors.Errorf("error storing ByTxid for txid %s [%s]", txID, err.Error())
144+
}
145+
146+
if s.vcProvider.IsValid(code) {
147+
err = s.persistence.SetState(txidNamespace, lastTX, []byte(txID))
148+
if err != nil { // TODO: && !errors2.HasCause(err, driver.UniqueKeyViolation)
149+
s.persistence.Discard()
150+
return errors.Errorf("error storing ByTxid for txid %s [%s]", txID, err.Error())
151+
}
152+
}
153+
// NOTE: we assume that the commit is in progress so no need to update/commit
154+
// err = s.persistence.Commit()
155+
// if err != nil {
156+
// return errors.Errorf("error committing update to set txid %s [%s]", txid, err.Error())
157+
// }
158+
159+
s.ctr++
160+
161+
return nil
162+
}
163+
164+
func (s *SimpleTXIDStore[V]) GetLastTxID() (string, error) {
165+
v, err := s.persistence.GetState(txidNamespace, lastTX)
166+
if err != nil {
167+
return "", errors.Wrapf(err, "failed to get last TxID")
168+
}
169+
if len(v) == 0 {
170+
return "", nil
171+
}
172+
return string(v), nil
173+
}
174+
175+
func (s *SimpleTXIDStore[V]) Iterator(pos interface{}) (vault.TxIDIterator[V], error) {
176+
var iterator utils.Iterator[*ByNum]
177+
if ppos, ok := pos.(*vault.SeekSet); ok {
178+
it, err := s.persistence.GetStateSetIterator(txidNamespace, ppos.TxIDs...)
179+
if err != nil {
180+
return nil, err
181+
}
182+
iterator = &SimpleTxIDIterator{it}
183+
184+
} else {
185+
startKey, err := s.getStartKey(pos)
186+
if err != nil {
187+
return nil, err
188+
}
189+
190+
it, err := s.persistence.GetStateRangeScanIterator(txidNamespace, keyByCtr(startKey), keyByCtr(math.MaxUint64))
191+
if err != nil {
192+
return nil, err
193+
}
194+
iterator = &SimpleTxIDIterator{it}
195+
}
196+
197+
return utils.Map(iterator, s.mapByNum), nil
198+
}
199+
200+
func (s *SimpleTXIDStore[V]) getStartKey(pos interface{}) (uint64, error) {
201+
switch ppos := pos.(type) {
202+
case *vault.SeekStart:
203+
return 0, nil
204+
case *vault.SeekEnd:
205+
ctr, err := getCtr(s.persistence)
206+
if err != nil {
207+
return 0, err
208+
}
209+
return ctr - 1, nil
210+
case *vault.SeekPos:
211+
bt, err := s.get(ppos.Txid)
212+
if err != nil {
213+
return 0, err
214+
}
215+
if bt == nil {
216+
return 0, errors.Errorf("txid %s was not found", ppos.Txid)
217+
}
218+
return bt.Pos, nil
219+
}
220+
return 0, errors.Errorf("invalid position %T", pos)
221+
}
222+
223+
func (s *SimpleTXIDStore[V]) mapByNum(bn *ByNum) (*vault.ByNum[V], error) {
224+
return &vault.ByNum[V]{
225+
TxID: bn.Txid,
226+
Code: s.vcProvider.FromInt32(bn.Code),
227+
Message: bn.Message,
228+
}, nil
229+
}
230+
231+
type SimpleTxIDIterator struct {
232+
t driver.ResultsIterator
233+
}
234+
235+
func (i *SimpleTxIDIterator) Next() (*ByNum, error) {
236+
d, err := i.t.Next()
237+
if err != nil {
238+
return nil, err
239+
}
240+
241+
if d == nil {
242+
return nil, nil
243+
}
244+
245+
bn := &ByNum{}
246+
err = proto.Unmarshal(d.Raw, bn)
247+
if err != nil {
248+
return nil, err
249+
}
250+
return bn, err
251+
252+
//return &vault.ByNum[V]{
253+
// TxID: bn.Txid,
254+
// Code: fdriver.ValidationCode(bn.Code),
255+
// Message: bn.Message,
256+
//}, nil
257+
}
258+
259+
func (i *SimpleTxIDIterator) Close() {
260+
i.t.Close()
261+
}
262+
263+
func keyByCtr(ctr uint64) string {
264+
ctrBytes := new([binary.MaxVarintLen64]byte)
265+
binary.BigEndian.PutUint64(ctrBytes[:], ctr)
266+
267+
return byCtrPrefix + string(ctrBytes[:])
268+
}
269+
270+
func keyByTxID(txID string) string {
271+
return byTxidPrefix + txID
272+
}
273+
274+
func setCtr(persistence driver.Persistence, ctr uint64) error {
275+
ctrBytes := make([]byte, binary.MaxVarintLen64)
276+
binary.BigEndian.PutUint64(ctrBytes, ctr)
277+
278+
err := persistence.SetState(txidNamespace, ctrKey, ctrBytes)
279+
if err != nil && !errors2.HasCause(err, driver.UniqueKeyViolation) {
280+
return errors.Errorf("error storing the counter [%s]", err.Error())
281+
}
282+
283+
return nil
284+
}
285+
286+
func getCtr(persistence driver.Persistence) (uint64, error) {
287+
ctrBytes, err := persistence.GetState(txidNamespace, ctrKey)
288+
if err != nil {
289+
return 0, errors.Errorf("error retrieving txid counter [%s]", err.Error())
290+
}
291+
292+
return getCtrFromBytes(ctrBytes), nil
293+
}
294+
295+
func getCtrFromBytes(ctrBytes []byte) uint64 {
296+
return binary.BigEndian.Uint64(ctrBytes)
297+
}

platform/common/utils/iterators.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package utils
2+
3+
type Iterator[V any] interface {
4+
Next() (V, error)
5+
Close()
6+
}
7+
8+
func Map[A any, B any](iterator Iterator[A], transformer func(A) (B, error)) Iterator[B] {}

0 commit comments

Comments
 (0)