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