github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/tracekv/store.go (about) 1 package tracekv 2 3 import ( 4 "encoding/base64" 5 "encoding/json" 6 "fmt" 7 "io" 8 9 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types" 10 ) 11 12 const ( 13 writeOp operation = "write" 14 readOp operation = "read" 15 deleteOp operation = "delete" 16 iterKeyOp operation = "iterKey" 17 iterValueOp operation = "iterValue" 18 ) 19 20 type ( 21 // Store implements the KVStore interface with tracing enabled. 22 // Operations are traced on each core KVStore call and written to the 23 // underlying io.writer. 24 // 25 // TODO: Should we use a buffered writer and implement Commit on 26 // Store? 27 Store struct { 28 parent types.KVStore 29 writer io.Writer 30 context types.TraceContext 31 } 32 33 // operation represents an IO operation 34 operation string 35 36 // traceOperation implements a traced KVStore operation 37 traceOperation struct { 38 Operation operation `json:"operation"` 39 Key string `json:"key"` 40 Value string `json:"value"` 41 Metadata map[string]interface{} `json:"metadata"` 42 } 43 ) 44 45 // NewStore returns a reference to a new traceKVStore given a parent 46 // KVStore implementation and a buffered writer. 47 func NewStore(parent types.KVStore, writer io.Writer, tc types.TraceContext) *Store { 48 return &Store{parent: parent, writer: writer, context: tc} 49 } 50 51 // Get implements the KVStore interface. It traces a read operation and 52 // delegates a Get call to the parent KVStore. 53 func (tkv *Store) Get(key []byte) []byte { 54 value := tkv.parent.Get(key) 55 56 writeOperation(tkv.writer, readOp, tkv.context, key, value) 57 return value 58 } 59 60 // Set implements the KVStore interface. It traces a write operation and 61 // delegates the Set call to the parent KVStore. 62 func (tkv *Store) Set(key []byte, value []byte) { 63 writeOperation(tkv.writer, writeOp, tkv.context, key, value) 64 tkv.parent.Set(key, value) 65 } 66 67 // Delete implements the KVStore interface. It traces a write operation and 68 // delegates the Delete call to the parent KVStore. 69 func (tkv *Store) Delete(key []byte) { 70 writeOperation(tkv.writer, deleteOp, tkv.context, key, nil) 71 tkv.parent.Delete(key) 72 } 73 74 // Has implements the KVStore interface. It delegates the Has call to the 75 // parent KVStore. 76 func (tkv *Store) Has(key []byte) bool { 77 return tkv.parent.Has(key) 78 } 79 80 // Iterator implements the KVStore interface. It delegates the Iterator call 81 // the to the parent KVStore. 82 func (tkv *Store) Iterator(start, end []byte) types.Iterator { 83 return tkv.iterator(start, end, true) 84 } 85 86 // ReverseIterator implements the KVStore interface. It delegates the 87 // ReverseIterator call the to the parent KVStore. 88 func (tkv *Store) ReverseIterator(start, end []byte) types.Iterator { 89 return tkv.iterator(start, end, false) 90 } 91 92 // iterator facilitates iteration over a KVStore. It delegates the necessary 93 // calls to it's parent KVStore. 94 func (tkv *Store) iterator(start, end []byte, ascending bool) types.Iterator { 95 var parent types.Iterator 96 97 if ascending { 98 parent = tkv.parent.Iterator(start, end) 99 } else { 100 parent = tkv.parent.ReverseIterator(start, end) 101 } 102 103 return newTraceIterator(tkv.writer, parent, tkv.context) 104 } 105 106 type traceIterator struct { 107 parent types.Iterator 108 writer io.Writer 109 context types.TraceContext 110 } 111 112 func newTraceIterator(w io.Writer, parent types.Iterator, tc types.TraceContext) types.Iterator { 113 return &traceIterator{writer: w, parent: parent, context: tc} 114 } 115 116 // Domain implements the Iterator interface. 117 func (ti *traceIterator) Domain() (start []byte, end []byte) { 118 return ti.parent.Domain() 119 } 120 121 // Valid implements the Iterator interface. 122 func (ti *traceIterator) Valid() bool { 123 return ti.parent.Valid() 124 } 125 126 // Next implements the Iterator interface. 127 func (ti *traceIterator) Next() { 128 ti.parent.Next() 129 } 130 131 // Key implements the Iterator interface. 132 func (ti *traceIterator) Key() []byte { 133 key := ti.parent.Key() 134 135 writeOperation(ti.writer, iterKeyOp, ti.context, key, nil) 136 return key 137 } 138 139 // Value implements the Iterator interface. 140 func (ti *traceIterator) Value() []byte { 141 value := ti.parent.Value() 142 143 writeOperation(ti.writer, iterValueOp, ti.context, nil, value) 144 return value 145 } 146 147 // Close implements the Iterator interface. 148 func (ti *traceIterator) Close() { 149 ti.parent.Close() 150 } 151 152 // Error delegates the Error call to the parent iterator. 153 func (ti *traceIterator) Error() error { 154 return ti.parent.Error() 155 } 156 157 // GetStoreType implements the KVStore interface. It returns the underlying 158 // KVStore type. 159 func (tkv *Store) GetStoreType() types.StoreType { 160 return tkv.parent.GetStoreType() 161 } 162 163 // CacheWrap implements the KVStore interface. It panics as a Store 164 // cannot be cache wrapped. 165 func (tkv *Store) CacheWrap() types.CacheWrap { 166 panic("cannot CacheWrap a Store") 167 } 168 169 // CacheWrapWithTrace implements the KVStore interface. It panics as a 170 // Store cannot be cache wrapped. 171 func (tkv *Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap { 172 panic("cannot CacheWrapWithTrace a Store") 173 } 174 175 // writeOperation writes a KVStore operation to the underlying io.Writer as 176 // JSON-encoded data where the key/value pair is base64 encoded. 177 func writeOperation(w io.Writer, op operation, tc types.TraceContext, key, value []byte) { 178 traceOp := traceOperation{ 179 Operation: op, 180 Key: base64.StdEncoding.EncodeToString(key), 181 Value: base64.StdEncoding.EncodeToString(value), 182 } 183 184 if tc != nil { 185 traceOp.Metadata = tc 186 } 187 188 raw, err := json.Marshal(traceOp) 189 if err != nil { 190 panic(fmt.Sprintf("failed to serialize trace operation: %v", err)) 191 } 192 193 if _, err := w.Write(raw); err != nil { 194 panic(fmt.Sprintf("failed to write trace operation: %v", err)) 195 } 196 197 io.WriteString(w, "\n") 198 }