github.com/s7techlab/cckit@v0.10.5/state/state.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hyperledger/fabric-chaincode-go/shim"
     7  	"github.com/hyperledger/fabric-protos-go/ledger/queryresult"
     8  	"github.com/pkg/errors"
     9  	"go.uber.org/zap"
    10  
    11  	pb "github.com/hyperledger/fabric-protos-go/peer"
    12  
    13  	"github.com/s7techlab/cckit/convert"
    14  )
    15  
    16  // HistoryEntry struct containing history information of a single entry
    17  type HistoryEntry struct {
    18  	TxId      string      `json:"txId"`
    19  	Timestamp int64       `json:"timestamp"`
    20  	IsDeleted bool        `json:"isDeleted"`
    21  	Value     interface{} `json:"value"`
    22  }
    23  
    24  // HistoryEntryList list of history entries
    25  type HistoryEntryList []HistoryEntry
    26  
    27  type Impl struct {
    28  	stub   shim.ChaincodeStubInterface
    29  	logger *zap.Logger
    30  
    31  	// wrappers for state access methods
    32  	PutState                                    func(string, []byte) error
    33  	GetState                                    func(string) ([]byte, error)
    34  	DelState                                    func(string) error
    35  	GetStateByPartialCompositeKey               func(objectType string, keys []string) (shim.StateQueryIteratorInterface, error)
    36  	GetStateByPartialCompositeKeyWithPagination func(objectType string, keys []string, pageSize int32, bookmark string) (shim.StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)
    37  
    38  	StateKeyTransformer        KeyTransformer
    39  	StateKeyReverseTransformer KeyTransformer
    40  	StateGetTransformer        FromBytesTransformer
    41  	StatePutTransformer        ToBytesTransformer
    42  }
    43  
    44  // NewState creates wrapper on shim.ChaincodeStubInterface for working with state
    45  func NewState(stub shim.ChaincodeStubInterface, logger *zap.Logger) *Impl {
    46  	i := &Impl{
    47  		stub:                       stub,
    48  		logger:                     logger,
    49  		StateKeyTransformer:        KeyAsIs,
    50  		StateKeyReverseTransformer: KeyAsIs,
    51  		StateGetTransformer:        ConvertFromBytes,
    52  		StatePutTransformer:        ConvertToBytes,
    53  	}
    54  
    55  	// Get data by key from state, direct from stub
    56  	i.GetState = func(key string) ([]byte, error) {
    57  		return stub.GetState(key)
    58  	}
    59  
    60  	// PutState puts the specified `key` and `value` into the transaction's
    61  	// writeset as a data-write proposal.
    62  	i.PutState = func(key string, bb []byte) error {
    63  		return stub.PutState(key, bb)
    64  	}
    65  
    66  	// DelState records the specified `key` to be deleted in the writeset of
    67  	// the transaction proposal.
    68  	i.DelState = func(key string) error {
    69  		return stub.DelState(key)
    70  	}
    71  
    72  	// GetStateByPartialCompositeKey queries the state in the ledger based on
    73  	// a given partial composite key
    74  	i.GetStateByPartialCompositeKey = func(objectType string, keys []string) (shim.StateQueryIteratorInterface, error) {
    75  		return stub.GetStateByPartialCompositeKey(objectType, keys)
    76  	}
    77  
    78  	i.GetStateByPartialCompositeKeyWithPagination = func(
    79  		objectType string, keys []string, pageSize int32, bookmark string) (
    80  		shim.StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) {
    81  		return stub.GetStateByPartialCompositeKeyWithPagination(objectType, keys, pageSize, bookmark)
    82  	}
    83  
    84  	return i
    85  }
    86  
    87  func (s *Impl) Clone() State {
    88  	return &Impl{
    89  		stub:                          s.stub,
    90  		logger:                        s.logger,
    91  		PutState:                      s.PutState,
    92  		GetState:                      s.GetState,
    93  		DelState:                      s.DelState,
    94  		GetStateByPartialCompositeKey: s.GetStateByPartialCompositeKey,
    95  		GetStateByPartialCompositeKeyWithPagination: s.GetStateByPartialCompositeKeyWithPagination,
    96  		StateKeyTransformer:                         s.StateKeyTransformer,
    97  		StateKeyReverseTransformer:                  s.StateKeyReverseTransformer,
    98  		StateGetTransformer:                         s.StateGetTransformer,
    99  		StatePutTransformer:                         s.StatePutTransformer,
   100  	}
   101  }
   102  
   103  func (s *Impl) Logger() *zap.Logger {
   104  	return s.logger
   105  }
   106  
   107  func (s *Impl) Key(key interface{}) (*TransformedKey, error) {
   108  	var (
   109  		trKey = &TransformedKey{}
   110  		err   error
   111  	)
   112  
   113  	if trKey.Origin, err = NormalizeKey(s.stub, key); err != nil {
   114  		return nil, errors.Wrap(err, `key normalizing`)
   115  	}
   116  
   117  	s.logger.Debug(`state KEY`, zap.String(`key`, trKey.Origin.String()))
   118  
   119  	if trKey.Parts, err = s.StateKeyTransformer(trKey.Origin); err != nil {
   120  		return nil, err
   121  	}
   122  
   123  	if trKey.String, err = KeyToString(s.stub, trKey.Parts); err != nil {
   124  		return nil, err
   125  	}
   126  
   127  	return trKey, nil
   128  }
   129  
   130  // Get data by key from state, trying to convert to target interface
   131  func (s *Impl) Get(entry interface{}, config ...interface{}) (interface{}, error) {
   132  	key, err := s.Key(entry)
   133  	if err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	//bytes from state
   138  	s.logger.Debug(`state GET`, zap.String(`key`, key.String))
   139  	bb, err := s.GetState(key.String)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  	if len(bb) == 0 {
   144  		// config[1] default value
   145  		if len(config) >= 2 {
   146  			return config[1], nil
   147  		}
   148  		return nil, errors.Errorf(`%s: %s`, ErrKeyNotFound, key.Origin)
   149  	}
   150  
   151  	// config[0] - target type
   152  	return s.StateGetTransformer(bb, config...)
   153  }
   154  
   155  func (s *Impl) GetInt(key interface{}, defaultValue int) (int, error) {
   156  	val, err := s.Get(key, convert.TypeInt, defaultValue)
   157  	if err != nil {
   158  		return 0, err
   159  	}
   160  	return val.(int), nil
   161  }
   162  
   163  // GetHistory by key from state, trying to convert to target interface
   164  func (s *Impl) GetHistory(entry interface{}, target interface{}) (HistoryEntryList, error) {
   165  	key, err := s.Key(entry)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	iter, err := s.stub.GetHistoryForKey(key.String)
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  
   175  	defer func() { _ = iter.Close() }()
   176  
   177  	results := HistoryEntryList{}
   178  
   179  	for iter.HasNext() {
   180  		state, err := iter.Next()
   181  		if err != nil {
   182  			return nil, err
   183  		}
   184  		value, err := s.StateGetTransformer(state.Value, target)
   185  		if err != nil {
   186  			return nil, err
   187  		}
   188  
   189  		entry := HistoryEntry{
   190  			TxId:      state.GetTxId(),
   191  			Timestamp: state.GetTimestamp().GetSeconds(),
   192  			IsDeleted: state.GetIsDelete(),
   193  			Value:     value,
   194  		}
   195  		results = append(results, entry)
   196  	}
   197  
   198  	return results, nil
   199  }
   200  
   201  // Exists check entry with key exists in chaincode state
   202  func (s *Impl) Exists(entry interface{}) (bool, error) {
   203  	key, err := s.Key(entry)
   204  	if err != nil {
   205  		return false, err
   206  	}
   207  
   208  	bb, err := s.GetState(key.String)
   209  	if err != nil {
   210  		return false, err
   211  	}
   212  
   213  	exists := len(bb) != 0
   214  	s.logger.Debug(`state check EXISTENCE`, zap.String(`key`, key.String), zap.Bool(`exists`, exists))
   215  	return exists, nil
   216  }
   217  
   218  // List data from state using objectType prefix in composite key, trying to convert to target interface.
   219  // Keys -  additional components of composite key
   220  func (s *Impl) List(namespace interface{}, target ...interface{}) (interface{}, error) {
   221  	stateList, err := NewStateList(target...)
   222  	if err != nil {
   223  		return nil, err
   224  	}
   225  
   226  	iter, err := s.createStateQueryIterator(namespace)
   227  	if err != nil {
   228  		return nil, errors.Wrap(err, `state iterator`)
   229  	}
   230  
   231  	defer func() { _ = iter.Close() }()
   232  
   233  	return stateList.Fill(iter, s.StateGetTransformer)
   234  }
   235  
   236  func (s *Impl) createStateQueryIterator(namespace interface{}) (shim.StateQueryIteratorInterface, error) {
   237  	n, t, err := s.normalizeAndTransformKey(namespace)
   238  	if err != nil {
   239  		return nil, err
   240  	}
   241  	s.logger.Debug(`state KEYS with composite key`,
   242  		zap.String(`key`, n.String()), zap.String(`transformed`, t.String()))
   243  
   244  	objectType, attrs := t.Parts()
   245  	if objectType == `` {
   246  		return s.stub.GetStateByRange(``, ``) // all state entries
   247  	}
   248  
   249  	return s.GetStateByPartialCompositeKey(objectType, attrs)
   250  }
   251  
   252  // normalizeAndTransformKey returns normalized and transformed key or error if occur
   253  func (s *Impl) normalizeAndTransformKey(namespace interface{}) (Key, Key, error) {
   254  	normal, err := NormalizeKey(s.stub, namespace)
   255  	if err != nil {
   256  		return nil, nil, fmt.Errorf(`list prefix: %w`, err)
   257  	}
   258  
   259  	transformed, err := s.StateKeyTransformer(normal)
   260  	if err != nil {
   261  		return nil, nil, err
   262  	}
   263  
   264  	return normal, transformed, nil
   265  }
   266  
   267  func (s *Impl) ListPaginated(
   268  	namespace interface{}, pageSize int32, bookmark string, target ...interface{}) (
   269  	interface{}, *pb.QueryResponseMetadata, error) {
   270  	stateList, err := NewStateList(target...)
   271  	if err != nil {
   272  		return nil, nil, err
   273  	}
   274  
   275  	iter, md, err := s.createStateQueryPagedIterator(namespace, pageSize, bookmark)
   276  	if err != nil {
   277  		return nil, nil, errors.Wrap(err, `state iterator`)
   278  	}
   279  
   280  	defer func() { _ = iter.Close() }()
   281  	list, err := stateList.Fill(iter, s.StateGetTransformer)
   282  
   283  	return list, md, err
   284  }
   285  
   286  func (s *Impl) createStateQueryPagedIterator(namespace interface{}, pageSize int32, bookmark string) (
   287  	shim.StateQueryIteratorInterface, *pb.QueryResponseMetadata, error) {
   288  	n, t, err := s.normalizeAndTransformKey(namespace)
   289  	if err != nil {
   290  		return nil, nil, err
   291  	}
   292  
   293  	s.logger.Debug(`state KEYS with composite key`,
   294  		zap.String(`key`, n.String()), zap.String(`transformed`, t.String()),
   295  		zap.Int32("pageSize", pageSize), zap.String("bookmark", bookmark))
   296  
   297  	objectType, attrs := t.Parts()
   298  	if objectType == `` {
   299  		return s.stub.GetStateByRangeWithPagination(``, ``, pageSize, bookmark)
   300  	}
   301  
   302  	return s.GetStateByPartialCompositeKeyWithPagination(objectType, attrs, pageSize, bookmark)
   303  }
   304  
   305  func (s *Impl) Keys(namespace interface{}) ([]string, error) {
   306  	iter, err := s.createStateQueryIterator(namespace)
   307  	if err != nil {
   308  		return nil, errors.Wrap(err, `state iterator`)
   309  	}
   310  
   311  	defer func() { _ = iter.Close() }()
   312  
   313  	var keys []string
   314  	for iter.HasNext() {
   315  		v, err := iter.Next()
   316  		if err != nil {
   317  			return nil, err
   318  		}
   319  
   320  		key, err := KeyFromComposite(s.stub, v.Key)
   321  		if err != nil {
   322  			return nil, err
   323  		}
   324  
   325  		reverseTransformedKey, err := s.StateKeyReverseTransformer(key)
   326  		if err != nil {
   327  			return nil, fmt.Errorf(`reverse transform key: %w`, err)
   328  		}
   329  
   330  		keyStr, err := KeyToString(s.stub, reverseTransformedKey)
   331  		if err != nil {
   332  			return nil, err
   333  		}
   334  
   335  		keys = append(keys, keyStr)
   336  	}
   337  
   338  	return keys, nil
   339  }
   340  
   341  func (s *Impl) argKeyValue(arg interface{}, values []interface{}) (key Key, value interface{}, err error) {
   342  	// key must be
   343  	if key, err = NormalizeKey(s.stub, arg); err != nil {
   344  		return
   345  	}
   346  
   347  	switch len(values) {
   348  	// arg is key and  value
   349  	case 0:
   350  		return key, arg, nil
   351  	case 1:
   352  		return key, values[0], nil
   353  	default:
   354  		return nil, nil, ErrAllowOnlyOneValue
   355  	}
   356  }
   357  
   358  // Put data value in state with key, trying to convert data to []byte
   359  func (s *Impl) Put(entry interface{}, values ...interface{}) error {
   360  	entryKey, value, err := s.argKeyValue(entry, values)
   361  	if err != nil {
   362  		return err
   363  	}
   364  	bb, err := s.StatePutTransformer(value)
   365  	if err != nil {
   366  		return err
   367  	}
   368  
   369  	key, err := s.Key(entryKey)
   370  	if err != nil {
   371  		return err
   372  	}
   373  
   374  	s.logger.Debug(`state PUT`, zap.String(`key`, key.String))
   375  	return s.PutState(key.String, bb)
   376  }
   377  
   378  // Insert value into chaincode state, returns error if key already exists
   379  func (s *Impl) Insert(entry interface{}, values ...interface{}) error {
   380  	if exists, err := s.Exists(entry); err != nil {
   381  		return err
   382  	} else if exists {
   383  		key, _ := s.Key(entry)
   384  		return fmt.Errorf(`%w: %s`, ErrKeyAlreadyExists, key.Origin)
   385  	}
   386  
   387  	key, value, err := s.argKeyValue(entry, values)
   388  	if err != nil {
   389  		return err
   390  	}
   391  	return s.Put(key, value)
   392  }
   393  
   394  // Delete entry from state
   395  func (s *Impl) Delete(entry interface{}) error {
   396  	key, err := s.Key(entry)
   397  	if err != nil {
   398  		return errors.Wrap(err, `deleting from state`)
   399  	}
   400  
   401  	s.logger.Debug(`state DELETE`, zap.String(`key`, key.String))
   402  	return s.DelState(key.String)
   403  }
   404  
   405  func (s *Impl) UseKeyTransformer(kt KeyTransformer) {
   406  	s.StateKeyTransformer = kt
   407  }
   408  
   409  func (s *Impl) UseKeyReverseTransformer(kt KeyTransformer) {
   410  	s.StateKeyReverseTransformer = kt
   411  }
   412  
   413  func (s *Impl) UseStateGetTransformer(fb FromBytesTransformer) {
   414  	s.StateGetTransformer = fb
   415  }
   416  
   417  func (s *Impl) UseStatePutTransformer(tb ToBytesTransformer) {
   418  	s.StatePutTransformer = tb
   419  }
   420  
   421  // GetPrivate data by key from private state, trying to convert to target interface
   422  func (s *Impl) GetPrivate(collection string, entry interface{}, config ...interface{}) (interface{}, error) {
   423  	key, err := s.Key(entry)
   424  	if err != nil {
   425  		return nil, err
   426  	}
   427  
   428  	//bytes from private state
   429  	s.logger.Debug(`private state GET`, zap.String(`key`, key.String))
   430  	bb, err := s.stub.GetPrivateData(collection, key.String)
   431  	if err != nil {
   432  		return nil, err
   433  	}
   434  	if len(bb) == 0 {
   435  		// config[1] default value
   436  		if len(config) >= 2 {
   437  			return config[1], nil
   438  		}
   439  		return nil, errors.Errorf(`%s: %s`, ErrKeyNotFound, key.Origin.String())
   440  	}
   441  
   442  	// config[0] - target type
   443  	return s.StateGetTransformer(bb, config...)
   444  }
   445  
   446  // ExistsPrivate check entry with key exists in chaincode private state
   447  func (s *Impl) ExistsPrivate(collection string, entry interface{}) (bool, error) {
   448  	key, err := s.Key(entry)
   449  	if err != nil {
   450  		return false, err
   451  	}
   452  	s.logger.Debug(`private state check EXISTENCE`, zap.String(`key`, key.String))
   453  	bb, err := s.stub.GetPrivateData(collection, key.String)
   454  	if err != nil {
   455  		return false, err
   456  	}
   457  	return len(bb) != 0, nil
   458  }
   459  
   460  // ListPrivate data from private state using objectType prefix in composite key, trying to convert to target interface.
   461  // Keys -  additional components of composite key
   462  // If usePrivateDataIterator is true, used private state for iterate over objects
   463  // if false, used public state for iterate over keys and GetPrivateData for each key
   464  func (s *Impl) ListPrivate(collection string, usePrivateDataIterator bool, namespace interface{}, target ...interface{}) (interface{}, error) {
   465  	stateList, err := NewStateList(target...)
   466  	if err != nil {
   467  		return nil, err
   468  	}
   469  	key, err := NormalizeKey(s.stub, namespace)
   470  	if err != nil {
   471  		return nil, errors.Wrap(err, `prepare list key parts`)
   472  	}
   473  	s.logger.Debug(`state LIST`, zap.String(`namespace`, key.String()))
   474  
   475  	if key, err = s.StateKeyTransformer(key); err != nil {
   476  		return nil, err
   477  	}
   478  	s.logger.Debug(`state LIST with composite key`, zap.String(`namespace`, key.String()))
   479  
   480  	if usePrivateDataIterator {
   481  		iter, err := s.stub.GetPrivateDataByPartialCompositeKey(collection, key[0], key[1:])
   482  		if err != nil {
   483  			return nil, errors.Wrap(err, `create list iterator`)
   484  		}
   485  		defer func() { _ = iter.Close() }()
   486  		return stateList.Fill(iter, s.StateGetTransformer)
   487  	}
   488  
   489  	iter, err := s.stub.GetStateByPartialCompositeKey(key[0], key[1:])
   490  	if err != nil {
   491  		return nil, errors.Wrap(err, `create list iterator`)
   492  	}
   493  	defer func() { _ = iter.Close() }()
   494  
   495  	var (
   496  		kv       *queryresult.KV
   497  		objKey   string
   498  		keyParts []string
   499  	)
   500  	for iter.HasNext() {
   501  		if kv, err = iter.Next(); err != nil {
   502  			return nil, errors.Wrap(err, `get key value`)
   503  		}
   504  		if objKey, keyParts, err = s.stub.SplitCompositeKey(kv.Key); err != nil {
   505  			return nil, err
   506  		}
   507  
   508  		object, err := s.GetPrivate(collection, append([]string{objKey}, keyParts...), target...)
   509  		if err != nil {
   510  			return nil, err
   511  		}
   512  		stateList.AddElementToList(object)
   513  	}
   514  
   515  	return stateList.Get()
   516  }
   517  
   518  // PutPrivate data value in private state with key, trying to convert data to []byte
   519  func (s *Impl) PutPrivate(collection string, entry interface{}, values ...interface{}) (err error) {
   520  	entryKey, value, err := s.argKeyValue(entry, values)
   521  	if err != nil {
   522  		return err
   523  	}
   524  	bb, err := s.StatePutTransformer(value)
   525  	if err != nil {
   526  		return err
   527  	}
   528  
   529  	key, err := s.Key(entryKey)
   530  	if err != nil {
   531  		return err
   532  	}
   533  
   534  	s.logger.Debug(`state PUT`, zap.String(`key`, key.String))
   535  	return s.stub.PutPrivateData(collection, key.String, bb)
   536  }
   537  
   538  // InsertPrivate value into chaincode private state, returns error if key already exists
   539  func (s *Impl) InsertPrivate(collection string, entry interface{}, values ...interface{}) (err error) {
   540  	if exists, err := s.ExistsPrivate(collection, entry); err != nil {
   541  		return err
   542  	} else if exists {
   543  		key, _ := s.Key(entry)
   544  		return errors.Errorf(`%s: %s`, ErrKeyAlreadyExists, key.Origin)
   545  	}
   546  
   547  	key, value, err := s.argKeyValue(entry, values)
   548  	if err != nil {
   549  		return err
   550  	}
   551  	return s.PutPrivate(collection, key, value)
   552  }
   553  
   554  // DeletePrivate entry from private state
   555  func (s *Impl) DeletePrivate(collection string, entry interface{}) error {
   556  	key, err := s.Key(entry)
   557  	if err != nil {
   558  		return errors.Wrap(err, `deleting from private state`)
   559  	}
   560  	s.logger.Debug(`private state DELETE`, zap.String(`key`, key.String))
   561  	return s.stub.DelPrivateData(collection, key.String)
   562  }