Uploaded image for project: 'Fabric'
  1. Fabric
  2. FAB-5556

Capability Framework - I want to support a mix of Fabric release levels in the network. I should be able to enable new (incompatible) capabilities on the channel when I am ready (older incompatible peers/orderers should drop out of channel)



    • Story
    • Status: Closed
    • Highest
    • Resolution: Done
    • v1.0.0
    • v1.1.0
    • fabric-release
    • None


      As a Fabric network provider, I might have multiple versions of Fabric components running together on the same blockchain network. For example, 1 possible combination Orderer v1.0, Peer v1.1, SDK v1.1, and CA v1.0. There are potentially many different combinations with each participating org.

      Compatibility generally, is assured by the usage of protobufs and general good practice of not making breaking API/ABI changes. Although all changes should strive to be backwards compatible, some changes necessarily are not. Consider for instance the change in the chaincode shim for to require mutual TLS for chaincode execution. This change breaks existing deployed chaincodes, but is a good requirement for security reasons. For the mutual TLS change, and others like it, the implication is that something in the system stops working, but there is no potential that the system becomes 'incorrect'. For these sorts of changes, the change should be linked to -FAB-6000- a sub-task of this issue, so that they can be noted and documented.

      There is a second class of non-backwards compatible changes which have the ability not only to make the system stop working, but also to make the system incorrect. Consider for instance the new MSP roles of Peer, Orderer, and Client. A v1.0 peer does not understand these roles, so would always evaluate policies involving them to false, while a v1.1 peer might evaluate them to true. This could cause a fork in the state database, which could be used to facilitate a double spending attack. For this feature, and others like it, they should be linked to -FAB-5999- to ensure that all parts of the system choose to use either the same legacy v1.0 behavior, or, that all parts of the system choose to use the new v1.1 behavior (precluding the ability for v1.0 code to participate.)

      Capabilties Framework

      This issue is focused on this second class of non-backwards compatible and potentially non-deterministic changes, and is resolved through the new 'Capabilities Framework'.

      The 'Capabilities Framework' is a rather grand sounding term for a very simple idea. The channel config already declares the rules which allow deterministic validation of transactions (the MSP definitions and policies), so it is natural to extend this config to also specify what code levels are required to correctly parse a channel. The extension is accomplished by adding a new config value which defines a capabilities map. This map contains string keys corresponding to features required to properly participate in the channel. If a binary does not support these features, then it cannot participate in the channel.

      For simplicity, in v1.1 if a binary cannot participate in a channel, it should simply crash. Although this is perhaps inelegant, it is obviously correct from a data integrity/safety perspective, and gives a clear sign to administrators that something is going wrong. In the future we may wish to introduce a more graceful mechanism, but it is not a requirement for v1.1.

      You may have noticed that the above paragraphs are deliberately vague about 'the binary', because not all binaries must necessarily support all capabilities. Consider a v1.2 peer built with side DB support. Because the side DB usage changes nothing about the peer's interaction with the orderer, it should be possible to require that the peer network be at v1.2, without requiring that the ordering network be at v1.2 as well. Because of this, in the channel config, the capabilties are split into three maps. One at the root channel level which indicates capabilities that both the orderer and peer must support (for instance signature algorithms, or policy types), one at the application level which indicates capabilities that the peer must support (for example, side DB), and one at the orderer which indicates capabilities the orderer must support (for example, SBFT). These three maps have no direct relation to eachother, but an orderer must support the orderer and channel capabilities, while the peer must support the peer and channel capabiltieis.

      For v1.1, and in general, we should strive not to proliferate capabilities. To avoid this proliferation (and the corresponding nightmare of support matrices) we introduce only a single capability at each of the three capabilities maps for v1.1. This capability is the "V1.1" capability, and all non-compatible changes will be encapsulated by it. The intention is that for v1.2, there will be a new "V1.2" capability flag which will imply a superset of the "V1.1" capabilities flags. Until we discover a pressing need for a capability which is not tied to version, capabilities can be thought of merely as a way to specify operational version of a channel. However, for the future, the ability for more complex capabilities schemes is possible.

      Upgrade in operation

      For a typical upgrade scenario, first, all binaries in the network should be upgraded to v1.1. This may be done in a rolling incremental fashion, and the network should continue to operate normally during this time. Once the entire network has been upgraded, the admins send a reconfiguration transaction to every channel in the network (including the ordering system channel) which sets the v1.1 capability in each of the three maps. This may also be done in a rolling way across channels. As each reconfiguration commits, that channel will now begin validating transactions according to the new v1.1 semantics, and any rogue peers which were not upgraded to v1.1 will crash.

      Note, it is important that all orderers are upgraded to v1.1 before enabling capabilities. Failing to do so will result in a fork of the blockchain. The v1.1 orderers will enforce that capabilties are turned on at the orderer group prior to allowing the application group to enable them to prevent the application admins from accidentally creating this fork. Note, this is only a requirement for the initial upgrade to v1.1, in the v1.2 upgrade scenario, the down-leveled orderers would simply crash on reconfiguration, rather than fork.

      Using capabilities

      https://gerrit.hyperledger.org/r/#/c/14267/ <- Example /Channel/Application capability
      https://gerrit.hyperledger.org/r/#/c/14265/ <- Example /Channel capability
      https://gerrit.hyperledger.org/r/#/c/13263/ <- Example /Channe/Orderer capability

      The above examples are probably the best way to understand how to use capabilities, but there is some documentation below which will hopefully clarify the process for anyone making a change requiring the capabilities framework. The process is as follows:

      1.Verify that the change is not backwards compatible and causes non-determinism in a transaction validation path (usually either for the orderers transaction-filtering, or for the peers VSCC transaction validation in the commit phase).
      2. Identify whether this behavior affects only the orderer, the peer, or both. The capability must then be defined as an orderer, application, or channel capability respectively. Refer to this as the <component> hereafter.
      3. Modify the <component>Capabilities interface in fabric/common/channelconfig/api.go to define a switch for the new behavior. This should be sensibly named so that the calling code reads naturally. For instance, fixing a bug in the orderer channel creation code was named SetChannelModPolicyDuringCreate() bool. This separates knowledge of the capabilities implementation from the consuming component and allows for modification of the capabilities framework without disturbing other code.
      4. Pick a new, or more often existing capability string defined in fabric/common/capabilities/<component>.go and have whether it is set control the return of the method defined in (3). Usually, capabilities are tied to version, so, for instance the "V1.1" capability for the orderer will cause SetChannelModPolicyDuringCreate() to return true. For v1.2, the capabilities framework will also make the "V1.2" capability cause SetChannelModPolicyDuringCreate() to return true. In this way, the consumer of SetChannelModPolicyDuringCreate does not need to perform version based logic for its behavior.

      Original design doc: https://docs.google.com/document/d/1CbB8dR0GNnHi7UekIDpsySCBXkPTtKk0m53CIzJbU-A/edit?usp=sharing



        Issue Links



              jyellick Jason Yellick
              binhn Binh Nguyen
              9 Vote for this issue
              19 Start watching this issue