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