@@ -3,7 +3,6 @@ package types
33import (
44 "bytes"
55 "errors"
6- "fmt"
76 "io"
87 "reflect"
98 "strings"
2928//
3029// Both stores are used for reads, but only the subjectStore is used for writes. For all operations, the key
3130// is checked to determine which store to use and must be prefixed with either "subject/" or "substitute/" accordingly.
32- // If the key is not prefixed with either "subject/" or "substitute/", a panic is thrown .
31+ // If the key is not prefixed with either "subject/" or "substitute/", a default action is taken (e.g. no-op for Set/Delete) .
3332type migrateClientWrappedStore struct {
3433 subjectStore storetypes.KVStore
3534 substituteStore storetypes.KVStore
@@ -44,72 +43,91 @@ func newMigrateClientWrappedStore(subjectStore, substituteStore storetypes.KVSto
4443
4544// Get implements the storetypes.KVStore interface. It allows reads from both the subjectStore and substituteStore.
4645//
47- // Get will panic if the key is not prefixed with either "subject/" or "substitute/".
46+ // Get will return an empty byte slice if the key is not prefixed with either "subject/" or "substitute/".
4847func (ws migrateClientWrappedStore ) Get (key []byte ) []byte {
4948 prefix , key := splitPrefix (key )
49+ found , store := ws .getStore (prefix )
50+ if ! found {
51+ // return a nil byte slice as KVStore.Get() does by default
52+ return []byte (nil )
53+ }
5054
51- return ws . getStore ( prefix ) .Get (key )
55+ return store .Get (key )
5256}
5357
5458// Has implements the storetypes.KVStore interface. It allows reads from both the subjectStore and substituteStore.
5559//
5660// Note: contracts do not have access to the Has method, it is only implemented here to satisfy the storetypes.KVStore interface.
5761func (ws migrateClientWrappedStore ) Has (key []byte ) bool {
5862 prefix , key := splitPrefix (key )
63+ found , store := ws .getStore (prefix )
64+ if ! found {
65+ // return false as value when store is not found
66+ return false
67+ }
5968
60- return ws . getStore ( prefix ) .Has (key )
69+ return store .Has (key )
6170}
6271
6372// Set implements the storetypes.KVStore interface. It allows writes solely to the subjectStore.
6473//
65- // Set will panic if the key is not prefixed with "subject/".
74+ // Set will no-op if the key is not prefixed with "subject/".
6675func (ws migrateClientWrappedStore ) Set (key , value []byte ) {
6776 prefix , key := splitPrefix (key )
6877 if ! bytes .Equal (prefix , subjectPrefix ) {
69- panic ( fmt . Errorf ( "writes only allowed on subject store; key must be prefixed with \" %s \" " , subjectPrefix ))
78+ return // no-op
7079 }
7180
7281 ws .subjectStore .Set (key , value )
7382}
7483
7584// Delete implements the storetypes.KVStore interface. It allows deletions solely to the subjectStore.
7685//
77- // Delete will panic if the key is not prefixed with "subject/".
86+ // Delete will no-op if the key is not prefixed with "subject/".
7887func (ws migrateClientWrappedStore ) Delete (key []byte ) {
7988 prefix , key := splitPrefix (key )
8089 if ! bytes .Equal (prefix , subjectPrefix ) {
81- panic ( fmt . Errorf ( "writes only allowed on subject store; key must be prefixed with \" %s \" " , subjectPrefix ))
90+ return // no-op
8291 }
8392
8493 ws .subjectStore .Delete (key )
8594}
8695
8796// Iterator implements the storetypes.KVStore interface. It allows iteration over both the subjectStore and substituteStore.
8897//
89- // Iterator will panic if the start or end keys are not prefixed with either "subject/" or "substitute/".
98+ // Iterator will return a closed iterator if the start or end keys are not prefixed with either "subject/" or "substitute/".
9099func (ws migrateClientWrappedStore ) Iterator (start , end []byte ) storetypes.Iterator {
91100 prefixStart , start := splitPrefix (start )
92101 prefixEnd , end := splitPrefix (end )
93102
94103 if ! bytes .Equal (prefixStart , prefixEnd ) {
95- panic (errors .New ("start and end keys must be prefixed with the same prefix" ))
104+ return ws .closedIterator ()
105+ }
106+ found , store := ws .getStore (prefixStart )
107+ if ! found {
108+ return ws .closedIterator ()
96109 }
97110
98- return ws . getStore ( prefixStart ) .Iterator (start , end )
111+ return store .Iterator (start , end )
99112}
100113
101114// ReverseIterator implements the storetypes.KVStore interface. It allows iteration over both the subjectStore and substituteStore.
102115//
103- // ReverseIterator will panic if the start or end keys are not prefixed with either "subject/" or "substitute/".
116+ // ReverseIterator will return a closed iterator if the start or end keys are not prefixed with either "subject/" or "substitute/".
104117func (ws migrateClientWrappedStore ) ReverseIterator (start , end []byte ) storetypes.Iterator {
105118 prefixStart , start := splitPrefix (start )
106119 prefixEnd , end := splitPrefix (end )
107120
108121 if ! bytes .Equal (prefixStart , prefixEnd ) {
109- panic (errors .New ("start and end keys must be prefixed with the same prefix" ))
122+ return ws .closedIterator ()
123+ }
124+
125+ found , store := ws .getStore (prefixStart )
126+ if ! found {
127+ return ws .closedIterator ()
110128 }
111129
112- return ws . getStore ( prefixStart ) .ReverseIterator (start , end )
130+ return store .ReverseIterator (start , end )
113131}
114132
115133// GetStoreType implements the storetypes.KVStore interface, it is implemented solely to satisfy the interface.
@@ -127,18 +145,29 @@ func (ws migrateClientWrappedStore) CacheWrapWithTrace(w io.Writer, tc storetype
127145 return cachekv .NewStore (tracekv .NewStore (ws , w , tc ))
128146}
129147
130- // getStore returns the store to be used for the given key. If the key is prefixed with "subject/", the subjectStore
131- // is returned. If the key is prefixed with "substitute/", the substituteStore is returned.
148+ // getStore returns the store to be used for the given key and a boolean flag indicating if that store was found.
149+ // If the key is prefixed with "subject/", the subjectStore is returned. If the key is prefixed with "substitute/",
150+ // the substituteStore is returned.
132151//
133- // If the key is not prefixed with either "subject/" or "substitute/", a panic is thrown .
134- func (ws migrateClientWrappedStore ) getStore (prefix []byte ) storetypes.KVStore {
152+ // If the key is not prefixed with either "subject/" or "substitute/", a nil store is returned and the boolean flag is false .
153+ func (ws migrateClientWrappedStore ) getStore (prefix []byte ) ( bool , storetypes.KVStore ) {
135154 if bytes .Equal (prefix , subjectPrefix ) {
136- return ws .subjectStore
155+ return true , ws .subjectStore
137156 } else if bytes .Equal (prefix , substitutePrefix ) {
138- return ws .substituteStore
157+ return true , ws .substituteStore
139158 }
140159
141- panic (fmt .Errorf ("key must be prefixed with either \" %s\" or \" %s\" " , subjectPrefix , substitutePrefix ))
160+ return false , nil
161+ }
162+
163+ // closedIterator returns an iterator that is always closed, used when Iterator() or ReverseIterator() is called
164+ // with an invalid prefix or start/end key.
165+ func (ws migrateClientWrappedStore ) closedIterator () storetypes.Iterator {
166+ // Create a dummy iterator that is always closed right away.
167+ it := ws .subjectStore .Iterator ([]byte {0 }, []byte {1 })
168+ it .Close ()
169+
170+ return it
142171}
143172
144173// splitPrefix splits the key into the prefix and the key itself, if the key is prefixed with either "subject/" or "substitute/".
0 commit comments