github.com/kaituanwang/hyperledger@v2.0.1+incompatible/docs/source/pluggable_endorsement_and_validation.rst (about) 1 Pluggable transaction endorsement and validation 2 ================================================ 3 4 Motivation 5 ---------- 6 7 When a transaction is validated at time of commit, the peer performs various 8 checks before applying the state changes that come with the transaction itself: 9 10 - Validating the identities that signed the transaction. 11 - Verifying the signatures of the endorsers on the transaction. 12 - Ensuring the transaction satisfies the endorsement policies of the namespaces 13 of the corresponding chaincodes. 14 15 There are use cases which demand custom transaction validation rules different 16 from the default Fabric validation rules, such as: 17 18 - **UTXO (Unspent Transaction Output):** When the validation takes into account 19 whether the transaction doesn't double spend its inputs. 20 - **Anonymous transactions:** When the endorsement doesn't contain the identity 21 of the peer, but a signature and a public key are shared that can't be linked 22 to the peer's identity. 23 24 Pluggable endorsement and validation logic 25 ------------------------------------------ 26 27 Fabric allows for the implementation and deployment of custom endorsement and 28 validation logic into the peer to be associated with chaincode handling in a 29 pluggable manner. This logic can be either compiled into the peer as built in 30 selectable logic, or compiled and deployed alongside the peer as a 31 `Golang plugin <https://golang.org/pkg/plugin/>`_. 32 33 By default, A chaincode will use the built in endorsement and validation logic. 34 However, users have the option of selecting custom endorsement and validation 35 plugins as part of the chaincode definition. An administrator can extend the 36 endorsement/validation logic available to the peer by customizing the peer's 37 local configuration. 38 39 Configuration 40 ------------- 41 42 Each peer has a local configuration (``core.yaml``) that declares a mapping 43 between the endorsement/validation logic name and the implementation that is to 44 be run. 45 46 The default logic are called ``ESCC`` (with the "E" standing for endorsement) and 47 ``VSCC`` (validation), and they can be found in the peer local configuration in 48 the ``handlers`` section: 49 50 .. code-block:: YAML 51 52 handlers: 53 endorsers: 54 escc: 55 name: DefaultEndorsement 56 validators: 57 vscc: 58 name: DefaultValidation 59 60 When the endorsement or validation implementation is compiled into the peer, the 61 ``name`` property represents the initialization function that is to be run in order 62 to obtain the factory that creates instances of the endorsement/validation logic. 63 64 The function is an instance method of the ``HandlerLibrary`` construct under 65 ``core/handlers/library/library.go`` and in order for custom endorsement or 66 validation logic to be added, this construct needs to be extended with any 67 additional methods. 68 69 Since this is cumbersome and poses a deployment challenge, one can also deploy 70 custom endorsement and validation as a Golang plugin by adding another property 71 under the ``name`` called ``library``. 72 73 For example, if we have custom endorsement and validation logic which is 74 implemented as a plugin, we would have the following entries in the configuration 75 in ``core.yaml``: 76 77 .. code-block:: YAML 78 79 handlers: 80 endorsers: 81 escc: 82 name: DefaultEndorsement 83 custom: 84 name: customEndorsement 85 library: /etc/hyperledger/fabric/plugins/customEndorsement.so 86 validators: 87 vscc: 88 name: DefaultValidation 89 custom: 90 name: customValidation 91 library: /etc/hyperledger/fabric/plugins/customValidation.so 92 93 And we'd have to place the ``.so`` plugin files in the peer's local file system. 94 95 The name of the custom plugin needs to be referenced by the chaincode definition 96 to be used by the chaincode. If you are using the peer CLI to approve the 97 chaincode definition, use the ``--escc`` and ``--vscc`` flag to select the name 98 of the custom endorsement or validation library. If you are using the 99 Fabric SDK for Node.js, visit `How to install and start your chaincode <https://hyperledger.github.io/fabric-sdk-node/master/tutorial-chaincode-lifecycle.html>`__. 100 For more information, see :doc:`chaincode4noah`. 101 102 .. note:: Hereafter, custom endorsement or validation logic implementation is 103 going to be referred to as "plugins", even if they are compiled into 104 the peer. 105 106 Endorsement plugin implementation 107 --------------------------------- 108 109 To implement an endorsement plugin, one must implement the ``Plugin`` interface 110 found in ``core/handlers/endorsement/api/endorsement.go``: 111 112 .. code-block:: Go 113 114 // Plugin endorses a proposal response 115 type Plugin interface { 116 // Endorse signs the given payload(ProposalResponsePayload bytes), and optionally mutates it. 117 // Returns: 118 // The Endorsement: A signature over the payload, and an identity that is used to verify the signature 119 // The payload that was given as input (could be modified within this function) 120 // Or error on failure 121 Endorse(payload []byte, sp *peer.SignedProposal) (*peer.Endorsement, []byte, error) 122 123 // Init injects dependencies into the instance of the Plugin 124 Init(dependencies ...Dependency) error 125 } 126 127 An endorsement plugin instance of a given plugin type (identified either by the 128 method name as an instance method of the ``HandlerLibrary`` or by the plugin ``.so`` 129 file path) is created for each channel by having the peer invoke the ``New`` 130 method in the ``PluginFactory`` interface which is also expected to be implemented 131 by the plugin developer: 132 133 .. code-block:: Go 134 135 // PluginFactory creates a new instance of a Plugin 136 type PluginFactory interface { 137 New() Plugin 138 } 139 140 141 The ``Init`` method is expected to receive as input all the dependencies declared 142 under ``core/handlers/endorsement/api/``, identified as embedding the ``Dependency`` 143 interface. 144 145 After the creation of the ``Plugin`` instance, the ``Init`` method is invoked on 146 it by the peer with the ``dependencies`` passed as parameters. 147 148 Currently Fabric comes with the following dependencies for endorsement plugins: 149 150 - ``SigningIdentityFetcher``: Returns an instance of ``SigningIdentity`` based 151 on a given signed proposal: 152 153 .. code-block:: Go 154 155 // SigningIdentity signs messages and serializes its public identity to bytes 156 type SigningIdentity interface { 157 // Serialize returns a byte representation of this identity which is used to verify 158 // messages signed by this SigningIdentity 159 Serialize() ([]byte, error) 160 161 // Sign signs the given payload and returns a signature 162 Sign([]byte) ([]byte, error) 163 } 164 165 - ``StateFetcher``: Fetches a **State** object which interacts with the world 166 state: 167 168 .. code-block:: Go 169 170 // State defines interaction with the world state 171 type State interface { 172 // GetPrivateDataMultipleKeys gets the values for the multiple private data items in a single call 173 GetPrivateDataMultipleKeys(namespace, collection string, keys []string) ([][]byte, error) 174 175 // GetStateMultipleKeys gets the values for multiple keys in a single call 176 GetStateMultipleKeys(namespace string, keys []string) ([][]byte, error) 177 178 // GetTransientByTXID gets the values private data associated with the given txID 179 GetTransientByTXID(txID string) ([]*rwset.TxPvtReadWriteSet, error) 180 181 // Done releases resources occupied by the State 182 Done() 183 } 184 185 Validation plugin implementation 186 -------------------------------- 187 188 To implement a validation plugin, one must implement the ``Plugin`` interface 189 found in ``core/handlers/validation/api/validation.go``: 190 191 .. code-block:: Go 192 193 // Plugin validates transactions 194 type Plugin interface { 195 // Validate returns nil if the action at the given position inside the transaction 196 // at the given position in the given block is valid, or an error if not. 197 Validate(block *common.Block, namespace string, txPosition int, actionPosition int, contextData ...ContextDatum) error 198 199 // Init injects dependencies into the instance of the Plugin 200 Init(dependencies ...Dependency) error 201 } 202 203 Each ``ContextDatum`` is additional runtime-derived metadata that is passed by 204 the peer to the validation plugin. Currently, the only ``ContextDatum`` that is 205 passed is one that represents the endorsement policy of the chaincode: 206 207 .. code-block:: Go 208 209 // SerializedPolicy defines a serialized policy 210 type SerializedPolicy interface { 211 validation.ContextDatum 212 213 // Bytes returns the bytes of the SerializedPolicy 214 Bytes() []byte 215 } 216 217 A validation plugin instance of a given plugin type (identified either by the 218 method name as an instance method of the ``HandlerLibrary`` or by the plugin ``.so`` 219 file path) is created for each channel by having the peer invoke the ``New`` 220 method in the ``PluginFactory`` interface which is also expected to be implemented 221 by the plugin developer: 222 223 .. code-block:: Go 224 225 // PluginFactory creates a new instance of a Plugin 226 type PluginFactory interface { 227 New() Plugin 228 } 229 230 The ``Init`` method is expected to receive as input all the dependencies declared 231 under ``core/handlers/validation/api/``, identified as embedding the ``Dependency`` 232 interface. 233 234 After the creation of the ``Plugin`` instance, the **Init** method is invoked on 235 it by the peer with the dependencies passed as parameters. 236 237 Currently Fabric comes with the following dependencies for validation plugins: 238 239 - ``IdentityDeserializer``: Converts byte representation of identities into 240 ``Identity`` objects that can be used to verify signatures signed by them, be 241 validated themselves against their corresponding MSP, and see whether they 242 satisfy a given **MSP Principal**. The full specification can be found in 243 ``core/handlers/validation/api/identities/identities.go``. 244 245 - ``PolicyEvaluator``: Evaluates whether a given policy is satisfied: 246 247 .. code-block:: Go 248 249 // PolicyEvaluator evaluates policies 250 type PolicyEvaluator interface { 251 validation.Dependency 252 253 // Evaluate takes a set of SignedData and evaluates whether this set of signatures satisfies 254 // the policy with the given bytes 255 Evaluate(policyBytes []byte, signatureSet []*common.SignedData) error 256 } 257 258 - ``StateFetcher``: Fetches a ``State`` object which interacts with the world state: 259 260 .. code-block:: Go 261 262 // State defines interaction with the world state 263 type State interface { 264 // GetStateMultipleKeys gets the values for multiple keys in a single call 265 GetStateMultipleKeys(namespace string, keys []string) ([][]byte, error) 266 267 // GetStateRangeScanIterator returns an iterator that contains all the key-values between given key ranges. 268 // startKey is included in the results and endKey is excluded. An empty startKey refers to the first available key 269 // and an empty endKey refers to the last available key. For scanning all the keys, both the startKey and the endKey 270 // can be supplied as empty strings. However, a full scan should be used judiciously for performance reasons. 271 // The returned ResultsIterator contains results of type *KV which is defined in fabric-protos/ledger/queryresult. 272 GetStateRangeScanIterator(namespace string, startKey string, endKey string) (ResultsIterator, error) 273 274 // GetStateMetadata returns the metadata for given namespace and key 275 GetStateMetadata(namespace, key string) (map[string][]byte, error) 276 277 // GetPrivateDataMetadata gets the metadata of a private data item identified by a tuple <namespace, collection, key> 278 GetPrivateDataMetadata(namespace, collection, key string) (map[string][]byte, error) 279 280 // Done releases resources occupied by the State 281 Done() 282 } 283 284 Important notes 285 --------------- 286 287 - **Validation plugin consistency across peers:** In future releases, the Fabric 288 channel infrastructure would guarantee that the same validation logic is used 289 for a given chaincode by all peers in the channel at any given blockchain 290 height in order to eliminate the chance of mis-configuration which would might 291 lead to state divergence among peers that accidentally run different 292 implementations. However, for now it is the sole responsibility of the system 293 operators and administrators to ensure this doesn't happen. 294 295 - **Validation plugin error handling:** Whenever a validation plugin can't 296 determine whether a given transaction is valid or not, because of some transient 297 execution problem like inability to access the database, it should return an 298 error of type **ExecutionFailureError** that is defined in ``core/handlers/validation/api/validation.go``. 299 Any other error that is returned, is treated as an endorsement policy error 300 and marks the transaction as invalidated by the validation logic. However, 301 if an ``ExecutionFailureError`` is returned, the chain processing halts instead 302 of marking the transaction as invalid. This is to prevent state divergence 303 between different peers. 304 305 - **Error handling for private metadata retrieval**: In case a plugin retrieves 306 metadata for private data by making use of the ``StateFetcher`` interface, 307 it is important that errors are handled as follows: ``CollConfigNotDefinedError'' 308 and ``InvalidCollNameError'', signalling that the specified collection does 309 not exist, should be handled as deterministic errors and should not lead the 310 plugin to return an ``ExecutionFailureError``. 311 312 - **Importing Fabric code into the plugin**: Importing code that belongs to Fabric 313 other than protobufs as part of the plugin is highly discouraged, and can lead 314 to issues when the Fabric code changes between releases, or can cause inoperability 315 issues when running mixed peer versions. Ideally, the plugin code should only 316 use the dependencies given to it, and should import the bare minimum other 317 than protobufs. 318 319 .. Licensed under Creative Commons Attribution 4.0 International License 320 https://creativecommons.org/licenses/by/4.0/