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  }