What should be some of the best practices to follow to avoid bugs and write efficient Hyperledger Fabric Chaincode?
General Guidelines for writing Hyperledger Fabric Chaincodes.
Refer to the below link for a detailed description on the same:
https://gist.github.com/arnabkaycee/d4c10a7f5c01f349632b42b67cee46db
Some steps are concisely mentioned below:
Using logging is simple and easy. Use Fabric's inbuilt logger. Fabric provides logging mechanism as follows:
For Golang: https://godoc.org/github.com/hyperledger/fabric/core/chaincode/shim#ChaincodeLogger
For NodeJS: https://fabric-shim.github.io/Shim.html#.newLogger__anchor
For Java: You can use any standard logging framework like Log4J
Avoid using Global Keys - Hyperledger Fabric uses an Optimistic Locking Model while committing transactions. In the two-stage process of endorsement & committment, if some versions of the keys that you had read in the Endorsement has changed till your transactions reach the committing stage, you get an MVCC_READ_CONFLICT error. This often is a probability when one or more concurrent transactions are updating the same key.
Use Couch DB Queries wisely
Couch DB Queries DO NOT alter the READ SET of a transaction - Mongo Queries are for querying the Key Value store aka StateDB only. It does not alter the read set of a transaction. This might lead to phantom reads in the transaction.
Only the DATA that you have stored in the couchDB is searchable - Do not be tempted to search for a key by its name using the MangoQuery. Although you can access the Fauxton console of the CouchDB, you cannot access a key by querying a key by which it is stored in the database. Example : Querying by channelName\0000KeyName is not allowed. It is better to store your key as a property in your data itself.
Write Deterministic Chaincode - Never write chaincode that is not deterministic. It means that if I execute the chaincode in 2 or more different environments at different times, result should always be the same, like setting the value as the current time or setting a random number. For example: Avoid statements like calling rand.New(...)
, t := time.Now()
or even relying on a global variable (check ) that is not persisted to the ledger.
This is because, that if the read write sets generated are not the same, the Validation System chaincode might reject it and throw an ENDORSEMENT_POLICY_FAILURE.
Be cautions when calling Other Chaincodes from your chaincode. - Invoking a chaincode from another is okay when both chaincodes are on the same channel. But be aware that if it is on the other channel then you get only what the chaincode function returns (only if the current invoker has rights to access data on that channel). NO data will be committed in the other channel, even if it attempts to write some. Currently, cross channel chaincode chaincode invocation does not alter data (change writesets) on the other channel. So, it is only possible to write to one channel at a time per transaction.
Remember to Set Chaincode Execution Timeout - Often it might so happen that during high load your chaincode might not complete its execution under 30s. It is a good practice to custom set your timeout as per your needs. This is goverened by the parameter in the core.yaml of the peer. You can override it by setting the environment variable in your docker compose file :
Example: CORE_CHAINCODE_EXECUTETIMEOUT=60s
Refrain from Accessing External Resources - Accessing external resources (http) might expose vulnerability and security threats to your chaincode. You do not want malicous code from external sources to influence your chaincode logic in any way. So keep away from external calls as much as possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With