github.com/hyperledger-labs/bdls@v2.1.1+incompatible/pkg/tx/interfaces.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package tx
     8  
     9  import (
    10  	"fmt"
    11  	"io"
    12  
    13  	"github.com/hyperledger/fabric-protos-go/common"
    14  	"github.com/hyperledger/fabric-protos-go/peer"
    15  	"github.com/hyperledger/fabric/pkg/statedata"
    16  )
    17  
    18  // ProcessorCreator creates a new instance of a processor of a particular transaction type.
    19  // In addition, this function also returns zero or more simulated readwrite sets that may
    20  // be present in the transaction if the transaction type supports enclosing of these.
    21  // There is expected to be one to one mapping between a supported transaction type and the
    22  // corresponding implementation of this interface. The transaction envelope passed to the
    23  // function `NewProcessor` is guaranteed to be of the associated transaction type.
    24  // If the ProcessCreator finds the transaction envelop to be invalid the err returned by
    25  // this function should be of type `InvalidErr`
    26  type ProcessorCreator interface {
    27  	NewProcessor(txenv *Envelope) (processor Processor, simulatedRWSet [][]byte, err error)
    28  }
    29  
    30  // Processor contains logic for processing a transaction on the committing peer.
    31  // One instance of a Processor is created for each transaction via `NewProcessor` function on the
    32  // corresponding `ProcessorCreator`.
    33  //
    34  // On a Processor, the first a `Preprocess` function is invoked and then the `Process` function is invoked.
    35  // The `Preprocess` function is invoked exactly once however, this may be invoked in parallel on different instances of Processors.
    36  // The function `Process` is invoked one by one on the `Processors` in the order in which the associated transactions
    37  // appear in the block. The `State` passed to the `Process` function represents the world state for the channel as of preceding valid
    38  // transaction in the block. For the purpose of efficiency (e.g., speculative execution), this function can be invoked more
    39  // than once and hence this function should not preserve anything in the form of instance variables.
    40  // Eventually, the function `Done` is invoked when the `Processor` has been used so as to indicate that the `Processor` can
    41  // release any resources held. This invocation could be because of a successful invocation to the `Process` function or
    42  // because the associated transaction is found to be invalid at any stage during the process
    43  // (e.g., concurrency conflict with other transactions). If the `Processor` finds the transaction to be invalid at any stage,
    44  // the error returned by the functions `PreProcess` and `Process` should be of type `InvalidErr`
    45  //
    46  // The intent is to support different transaction types via interface Processor such as pure endorser transactions,
    47  // pure post-order transactions, and a mixed transaction - e.g., a transaction that combines an endorser transaction and
    48  // and a post-order transaction (say, a token transaction).
    49  //
    50  // Below is the detail description of the semantics of the function `Process`
    51  // In order to process a transaction on a committing peer, we first evaluate the simulated readwrite set of the transaction
    52  //(returned by the function `NewProcessor` on the corresponding `ProcessorCreator`).
    53  // If the simulated part is found to have a concurrency conflict with one or more preceding valid transactions
    54  // (either a preceding transaction in the same block or in a preceding block), we mark the transaction invalid.
    55  // However, if simulated part of the transaction is found to be conflict free,
    56  // this is assumed that the transaction has logically started executing during commit time and has produced the
    57  // writes present in the simulated part of the transaction. In this case, the transaction processing is
    58  // continued from this point on and the `Process` function gives a chance to the `Processor` to complete the
    59  // transaction processing. Via the `Process` function, the transaction processor can perform reads/writes to the
    60  // state passed to this function.
    61  //
    62  // Following is an illustration how the Processor is potentially expected be implemented for the transaction type "ENDORSER_TRANSACTION".
    63  // 1) Preprocess function - Verifies the signatures and keeps the identities in internal state
    64  // 2) Process function - Reads and evaluates endorsement policies that are applicable to the transactions writes.
    65  //    The parameter "proposedWrites" to the Process function, contains the data items are intended writes by the processing of
    66  //    the simulatedRWSet. The endorser transaction processor can load the applicable endorsement policies (such as chaincode or key-based)
    67  //    and returns an error of type InvalidErr if the endorsement policy is not satisfied.
    68  //
    69  type Processor interface {
    70  	Preprocess(latestChannelConfig *ChannelConfig) error
    71  	Process(state *State, proposedWrites *statedata.ProposedWrites) error
    72  	Done()
    73  }
    74  
    75  // InvalidErr is intended to be used by a ProcessorCreator or a Processor to indicate that the transaction is found to be invalid
    76  type InvalidErr struct {
    77  	ActualErr      error
    78  	ValidationCode peer.TxValidationCode
    79  }
    80  
    81  func (e *InvalidErr) msgWithoutStack() string {
    82  	return fmt.Sprintf("ValidationCode = %s, ActualErr = %s", e.ValidationCode.String(), e.ActualErr)
    83  }
    84  
    85  func (e *InvalidErr) msgWithStack() string {
    86  	return fmt.Sprintf("ValidationCode = %s, ActualErr = %+v", e.ValidationCode.String(), e.ActualErr)
    87  }
    88  
    89  func (e *InvalidErr) Error() string {
    90  	return e.msgWithoutStack()
    91  }
    92  
    93  // Format implements interface fmt.Formatter
    94  func (e *InvalidErr) Format(s fmt.State, verb rune) {
    95  	switch verb {
    96  	case 'v':
    97  		if s.Flag('+') {
    98  			io.WriteString(s, e.msgWithStack())
    99  			return
   100  		}
   101  		fallthrough
   102  	case 's':
   103  		io.WriteString(s, e.msgWithoutStack())
   104  	case 'q':
   105  		fmt.Fprintf(s, "%q", e.msgWithoutStack())
   106  	}
   107  }
   108  
   109  // ReadHinter is an optional interface that a `Processor` implementation is encouraged to
   110  // implement if the `Processor` can give any hints about what data items it would potentially read
   111  // during its processing. This helps in pre-fetching/bulkloading the data in order to boost the performance
   112  // For instance, the `Processor` implementation for the endorser transactions is expected to give hint
   113  // about the endorsement policies based on the chaincode/collection/keys present in the "potentialWrites" parameter
   114  // (which in turn are derived from the simulated readwrite set present in the transaction envelope)
   115  // If a `Processor` implements this interface, the function `ReadHint` also gets the same treatment as the function `PreProcess`
   116  // i.e., this is invoked before invoking function `Process` and exactly once and may be invoked in parallel on different
   117  // instances of Processors. Note that the Preprocess and ReadHint functions on a Processor can get invoked in parallel
   118  type ReadHinter interface {
   119  	ReadHint(potentialWrites *statedata.WriteHint) *statedata.ReadHint
   120  }
   121  
   122  // Reprocessor is an optional interface that a `Processor` is encouraged to implement if a
   123  // a significant large number of transactions of the corresponding type are expected to be present and
   124  // validation of the transaction is significantly resource consuming (e.g., signature matching/crypto operations)
   125  // as compare to manipulating the state.
   126  // The main context in which the function in this interface is to be invoked is to rebuild the ledger constructs such as
   127  // statedb and historydb from the blocks that has already been processed in the past.
   128  // For instance, if the statedb is dropped and it is to be rebuilt, fabric will only use function in this interface (if implemented)
   129  // instead of the function in the Processor interface.
   130  // The function in this interface can safely assume that only transaction that are processed using this
   131  // were found to be valid earlier (when Processor interface was used for processing the transaction for the first time)
   132  // and hence, this function can skip any validation step and can just manipulate the state. However, if there is
   133  // no significant difference in the resource consumption, there is no value in implementing this interface and
   134  // the regular functions in the Processor interface would be invoked
   135  type Reprocessor interface {
   136  	Reprocess(state *State, latestChannelConfig *ChannelConfig, proposedWrites *statedata.ProposedWrites)
   137  }
   138  
   139  // ReprocessReadHinter is an optional interface that a `Processor` may choose to implement if it implements Reprocessor.
   140  // This is similar to as a processor may implement the ReadHinter interface albiet this gets invoked only if Reprocessor
   141  // is used for processing the transaction
   142  type ReprocessReadHinter interface {
   143  	ReprocessReadHint(potentialWrites *statedata.WriteHint) *statedata.ReadHint
   144  }
   145  
   146  // PvtdataSourceHinter is an optional interface that a `Processor` implements to return the peers
   147  // (identity bytes, e.g., certs) that could be the potential source for the private data associated
   148  // with the transaction
   149  type PvtdataSourceHinter interface {
   150  	PvtdataSource() [][]byte
   151  }
   152  
   153  // ChannelConfig gives handle to the channel config
   154  type ChannelConfig struct {
   155  }
   156  
   157  // State exposes functions that helps a `Processor` in retrieving the latest state
   158  // The `State` passed to the `Process` function represents the world state for the channel as of
   159  // commit of the preceding valid transaction in the block
   160  type State struct {
   161  	BackingState state
   162  }
   163  
   164  // GetState returns value associated with a tuple <namespace, key>
   165  func (s *State) GetState(ns, key string) ([]byte, error) {
   166  	return s.BackingState.GetState(ns, key)
   167  }
   168  
   169  // GetStateMetadata returns a map containing the metadata associated with a tuple <namespace, key>
   170  func (s *State) GetStateMetadata(ns, key string) (map[string][]byte, error) {
   171  	return s.BackingState.GetStateMetadata(ns, key)
   172  }
   173  
   174  // GetStateRangeScanIterator returns an iterator that can be used to iterate over all the keys
   175  // present in the range startKey (inclusive) and endKey (exclusive) for the a namespace.
   176  func (s *State) GetStateRangeScanIterator(ns, startKey, endKey string) (*KeyValueItr, error) {
   177  	itr, err := s.BackingState.GetStateRangeScanIterator(ns, startKey, endKey)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	return &KeyValueItr{
   182  		BackingItr: itr,
   183  	}, nil
   184  }
   185  
   186  // SetState sets the value associated with a tuple <namespace, key>
   187  // A nil value implies the delete of the key
   188  func (s *State) SetState(ns, key string, value []byte) error {
   189  	return s.BackingState.SetState(ns, key, value)
   190  }
   191  
   192  // SetStateMetadata sets the metadata associated with a tuple <namespace, key> for an existing key
   193  // This function is a noop for a non existing key. A nil metadata implied the delete of the metadata
   194  func (s *State) SetStateMetadata(ns, key string, metadata map[string][]byte) error {
   195  	return s.BackingState.SetStateMetadata(ns, key, metadata)
   196  }
   197  
   198  // GetPrivateDataMetadataByHash returns the metadata associated with a tuple <namespace, collection, keyhash>
   199  func (s *State) GetPrivateDataMetadataByHash(ns, coll string, keyHash []byte) (map[string][]byte, error) {
   200  	return s.BackingState.GetPrivateDataMetadataByHash(ns, coll, keyHash)
   201  }
   202  
   203  // KeyValueItr helps iterates over the results of a range scan query
   204  type KeyValueItr struct {
   205  	BackingItr keyValueItr
   206  }
   207  
   208  // Next returns the next result. A nil in the return value implies that no more results are available
   209  func (i *KeyValueItr) Next() (*statedata.KeyValue, error) {
   210  	return i.BackingItr.Next()
   211  }
   212  
   213  // Close closes the iterator
   214  func (i *KeyValueItr) Close() {
   215  	i.BackingItr.Close()
   216  }
   217  
   218  // Envelope contains data of the common.Envelope; some byte fields are already
   219  // unmarshalled to structs and we preserve the unmarshalled version so as to not
   220  // duplicate the unmarshalling work. Still, given the non-deterministic nature of
   221  // protobufs, we preserve their original byte representation so that the tx processor
   222  // may for instance verify signatures or perform bitwise operations on their original
   223  // representation.
   224  type Envelope struct {
   225  	// SignedBytes contains the marshalled common.Payload in the envelope
   226  	SignedBytes []byte
   227  	// Signature contains the creator's signature over the SignedBytes
   228  	Signature []byte
   229  	// Data contains the opaque Data bytes in the common.Payload
   230  	Data []byte
   231  	// ChannelHeaderBytes contains the marshalled ChannelHeader of the common.Header
   232  	ChannelHeaderBytes []byte
   233  	// ChannelHeaderBytes contains the marshalled SignatureHeader of the common.Header
   234  	SignatureHeaderBytes []byte
   235  	// ChannelHeader contains the ChannelHeader of this envelope
   236  	ChannelHeader *common.ChannelHeader
   237  	// SignatureHeader contains the SignatureHeader of this envelope
   238  	SignatureHeader *common.SignatureHeader
   239  }
   240  
   241  //**********************    Unexported types ***********************************************//
   242  // state represents the latest state that is passed to the "Process" function of the TxProcessor
   243  type state interface {
   244  	GetState(ns, key string) ([]byte, error)
   245  	GetStateMetadata(ns, key string) (map[string][]byte, error)
   246  	GetStateRangeScanIterator(ns, startKey, endKey string) (keyValueItr, error)
   247  	SetState(ns, key string, value []byte) error
   248  	SetStateMetadata(ns, key string, metadata map[string][]byte) error
   249  	GetPrivateDataMetadataByHash(ns, coll string, keyHash []byte) (map[string][]byte, error)
   250  }
   251  
   252  // keyValueItr iterates over a range of key-values
   253  type keyValueItr interface {
   254  	Next() (*statedata.KeyValue, error)
   255  	Close()
   256  }