介绍 (Introduction)

In this article, we introduce the fabric-config library and show how it can be used for channel configuration updates. Specifically, we will provide an example program that leverages the fabric-config library to make changes to block cutting parameters. You will find in this article explicit guidance on how to get started with the library and functions that you can include in your program so you can start using this library seamlessly in your next project.

在本文中,我们介绍了fabric-config库,并展示了如何将其用于通道配置更新。 具体来说,我们将提供一个示例程序,该程序利用fabric-config库更改块切割参数。 在本文中,您将找到有关如何开始使用可包含在程序中的库和函数的明确指导,以便可以在下一个项目中无缝使用该库。

通道配置概述 (Overview of channel configurations)

A Hyperledger Fabric network is made up of structures and processes that define how these structures interact with the blockchain network. In this context, structures include artifacts such as organizations, peers, identity credentials, ordering nodes, and certificate authorities among others.

Hyperledger Fabric网络由定义这些结构如何与区块链网络交互的结构和过程组成。 在这种情况下,结构包括工件,例如组织,对等方,身份凭证,订购节点和证书颁发机构等。

The data that identifies the structures and their corresponding processes (i.e. governing instructions for network interactions) are contained in channel configurations. These configurations are, in turn, found in blocks that have been committed to the ledger of a channel. Therefore, the process for modifying a channel configuration is referred to as a configuration update transaction. Concrete examples of channel configuration updates include some of the following common scenarios:

标识结构及其相应过程(即,用于网络交互的管理指令)的数据包含在通道配置中。 这些配置又可以在已提交给通道分类帐的块中找到。 因此,用于修改通道配置的过程称为配置更新事务。 通道配置更新的具体示例包括以下一些常见方案:

  • Updating the maximum number of transactions that should appear within a block.
    更新应该在一个区块中出现的最大事务数。
  • Updating the amount of time to wait for additional transactions after the first transaction arrives before cutting a block.
    在第一个交易到达之后,在切割区块之前,更新等待更多交易的时间。
  • Updating the Raft ordering service parameters.
    更新筏订购服务参数。
  • Updating the signature requirements for a block to be considered valid.
    更新被视为有效的块的签名要求。
  • Adding a new organization to an existing channel.
    将新组织添加到现有渠道。
  • Adding a new organization to the consortium.
    将新组织添加到联盟。

更新频道配置 (Updating channel configurations)

Until recently, the recommended approach for updating a channel configuration involved using the configtxlator and jq tools. The steps for using these tools when updating a channel configuration can be summarized as follows:

直到最近,使用configtxlator和jq工具进行更新通道配置的推荐方法。 在更新通道配置时使用这些工具的步骤可以概括如下:

1) Fetch the latest configuration block of a channel.

1)获取通道的最新配置块。

2) Decode the latest configuration block from protobuf format into JSON.

2)将最新的配置块从protobuf格式解码为JSON。

3) Remove unnecessary metadata from the JSON configuration block using jq.

3)使用jq从JSON配置块中删除不必要的元数据。

4) Create a copy of the JSON configuration block.

4)创建JSON配置块的副本。

5) Make the corresponding updates to the copied JSON configuration block (e.g. update the maximum number of transactions in a block).

5)对复制的JSON配置块进行相应的更新(例如,更新一个块中的最大事务数)。

6) Encode the JSON updated configuration block back to protobuf.

6)将JSON更新的配置块编码回protobuf。

7) Compute the difference between the two configuration protobufs (i.e. original configuration block and the updated configuration block). This results in a new config update protobuf which contains the delta.

7)计算两个配置协议(即原始配置块和更新后的配置块)之间的差异。 这将导致包含该增量的新配置更新协议。

8) Decode delta back into JSON.

8)将增量解码回JSON。

9) Add necessary header to JSON delta so it is wrapped in an envelope message using jq.

9)将必要的标头添加到JSON增量中,以便使用jq将其包装在信封消息中。

10) Encode JSON delta to protobuf.

10)将JSON增量编码为protobuf。

11) Sign the config update transaction.

11)签署配置更新事务。

12) Submit the config update transaction to the ordering service via a peer.

12)通过对等方将配置更新事务提交给订购服务。

Though the above approach works, it is quite tedious and error-prone. For instance, it is quite easy to forget to strip out the header (step 3) after decoding the latest configuration block or to add the header to the delta block (step 9). Also, step 5 is quite easy to mess up. While editing the JSON block either manually with a text editor [such as Visual Studio or Atom] or using jq, you could make the changes in the wrong section of the JSON document and/or introduce one or more typos. Also, while ideally, you should have a thorough understanding of the JSON schema before making any changes to the JSON block, the reality is that not everyone possesses this knowledge. Therefore, a different mechanism that is not error-prone and simplifies the process for updating a channel configuration is preferred. A much better approach would be one that allows you to use a type-safe and compiled language such as Go. In the next section, we introduce this new mechanism.

尽管上述方法可行,但它非常繁琐且容易出错。 例如,很容易忘记在解码最新的配置块后剥离标题(步骤3)或将标题添加到增量块(步骤9)。 而且,第5步很容易搞砸。 在使用文本编辑器(例如Visual Studio或Atom)或使用jq手动编辑JSON块时,可以在JSON文档的错误部分进行更改和/或引入一个或多个输入错误。 另外,理想情况下,在对JSON块进行任何更改之前,您应该对JSON模式有透彻的了解,但现实情况是,并不是每个人都拥有这一知识。 因此,优选不易出错并且简化用于更新信道配置的过程的不同机制。 一种更好的方法是允许您使用类型安全的 编译语言(例如Go)。 在下一节中,我们将介绍这种新机制。

It is also worth mentioning that the configtxlator tool should eventually be deprecated and later removed at some point in the future as consumers are encouraged to develop their own tooling utilizing the config update process detailed below. This is also another reason why you should start getting familiar with the newest mechanism for updating channel configurations.

还值得一提的是,由于鼓励消费者使用下面详细介绍的config update过程开发自己的工具,因此最终应弃用configtxlator工具,以后再将其删除。 这也是为什么您应该开始熟悉用于更新通道配置的最新机制的另一个原因。

Note: It is beyond the scope of this article to provide the low level details and instructions for using the configtxlator and jq tools. For complete details on this, see Updating a channel configuration.

注意 :提供使用configtxlator和jq工具的低级详细信息和说明超出了本文的范围。 有关此操作的完整详细信息,请参见更新通道配置 。

使用fabric-config库编辑通道配置 (Using the fabric-config library for editing channel configurations)

引入fabric-config (Introducing fabric-config)

The Hyperledger fabric-config library introduces an alternative method for producing configuration transaction updates that eliminates many of the tedious and error-prone steps required in the manual JSON parsing process described in the previous section. The fabric-config library is designed as a standalone library that supports generating configuration envelopes for operations such as application and system channel creation, channel configuration updates, and attaching endorsing signatures to transaction envelopes. The library is written in Go and provides a rich API for modifying configuration values on a provided configuration transaction by wrapping functionality for modifying the underlying transaction protobuf, as well as computation of deltas between the existing configuration and the desired update (similar to what the configtxlator tool was used for).

Hyperledger fabric-config库引入了一种用于生成配置事务更新的替代方法,该方法消除了上一部分中描述的手动JSON解析过程中所需的许多繁琐且容易出错的步骤。 fabric-config库被设计为一个独立的库,它支持生成配置包络以进行操作,例如应用程序和系统通道创建,通道配置更新以及将签名签名附加到事务包络。 该库使用Go语言编写,并提供了丰富的API,用于通过包装用于修改基础事务协议的功能来修改所提供的配置事务上的配置值,以及计算现有配置和所需更新之间的增量(类似于configtxlator工具用于)。

使用fabric-config更新通道配置 (Channel configuration updates with fabric-config)

Note that the fabric-config library does not fetch configuration blocks. Instead, it is totally up to you to decide how to fetch configuration blocks and how to submit configuration update transactions to the network. For instance, you could choose to fetch the latest configuration block from a channel using the Fabric peer CLI, which is part of the Hyperledger Fabric binaries. If you are leveraging the IBM Blockchain Platform, you can also take advantage of the IBM Blockchain Platform collection for Ansible for fetching the latest configuration block from a channel.

请注意,fabric-config库不会获取配置块。 取而代之的是,完全由您决定如何获取配置块以及如何向网络提交配置更新事务。 例如,您可以选择使用Fabric对等CLI(它是Hyperledger Fabric二进制文件的一部分)从通道中获取最新的配置块。 如果您正在利用IBM区块链平台,那么您还可以利用Ansible的IBM区块链平台集合从通道中获取最新的配置块。

Once you have fetched the latest configuration block from the corresponding channel, you can use a function written in Go similar to the next one to read that configuration block into memory:

从相应的通道中获取最新的配置块后,可以使用用Go语言编写的类似于下一个函数的功能,将该配置块读入内存:

import (...    cb "github.com/hyperledger/fabric-protos-go/common"...)func getConfigFromBlock(blockPath string) *cb.Config {    blockBin, err := ioutil.ReadFile(blockPath)    if err != nil {        panic(err)    }    block := &cb.Block {}        err = proto.Unmarshal(blockBin, block)        if err != nil {            panic(err)        }    blockDataEnvelope := &cb.Envelope {}        err = proto.Unmarshal(block.Data.Data[0], blockDataEnvelope)        if err != nil {            panic(err)        }    blockDataPayload := &cb.Payload {}    err = proto.Unmarshal(blockDataEnvelope.Payload, blockDataPayload)    if err != nil {        panic(err)    }    config := &cb.ConfigEnvelope {}        err = proto.Unmarshal(blockDataPayload.Data, config)        if err != nil {            panic(err)        }    return config.Config}

The getConfigFromBlock() function reads from the specified path the block you had previously fetched and returns a pointer to an instance of the Config structure. The above function is completely generic, which means you can use this function in your code for reading a configuration block no matter the configuration updates you intend to make. Notice that the Config instance encapsulates the data contained in the configuration block, structured as a configuration transaction protobuf. Also, note that Config is not a structure defined within the fabric-config library. Instead, the Config protobuf is defined within the fabric-protos-go module.

getConfigFromBlock()函数从指定的路径读取您先前获取的块,并返回一个指向Config结构实例的指针。 上面的函数是完全通用的,这意味着无论您打算进行什么配置更新,都可以在代码中使用此函数来读取配置块。 注意, Config实例封装了包含在配置块中的数据,该数据结构化为配置事务协议。 另外,请注意, Config不是在fabric-config库中定义的结构。 相反, Config protobuf是在fabric-protos-go模块中定义的。

After reading the configuration block into memory, you should then create a ConfigTx instance as shown next:

将配置块读入内存后,您应该创建一个ConfigTx实例,如下所示:

import (...    "github.com/hyperledger/fabric-config/configtx"...)...    baseConfig := getConfigFromBlock(blockPath)    configTx := configtx.New(baseConfig)...

The configtx.New() function shown above returns an instance of the ConfigTx structure, which is defined in the fabric-config library. This instance is the main entry point that your application code should use to make the necessary updates to a configuration block. Note that to get an instance of ConfigTx, you need to provide as an argument the configuration transaction protobuf that was read using the getConfigFromBlock() method.

上面显示的configtx.New()函数返回ConfigTx结构的实例,该实例在fabric-config库中定义。 该实例是应用程序代码用于对配置块进行必要更新的主要入口点。 请注意,要获取ConfigTx的实例,您需要提供使用getConfigFromBlock()方法读取的配置事务协议protobuf作为参数。

Let’s now show how to make a few updates to a configuration block by leveraging the ConfigTx structure. Specifically, we will make changes to the following block cutting parameters:

现在让我们展示如何利用ConfigTx结构对配置块进行一些更新。 具体来说,我们将更改以下块切割参数:

· absolute_max_bytes — The maximum size in bytes that a block should have (i.e. no block will appear larger than absolute_max_bytes).

· absolute_max_bytes块应具有的最大大小(以字节为单位)(即,任何块看上去都不会大于absolute_max_bytes)。

· max_message_count — The maximum number of transactions that a block should have (i.e. no block will appear with more than max_message_count transactions in it).

· max_message_count块应具有的最大事务数(即,没有块出现的事务数超过max_message_count个事务)。

· preferred_max_bytes — The preferred size for a block (i.e. if it’s possible to construct a block under preferred_max_bytes, then a block will be cut prematurely, and transactions larger than this size will appear in a different block).

· preferred_max_bytes块的首选大小(即,如果可以在preferred_max_bytes下构造一个块,则将过早地切割该块,并且大于该大小的事务将出现在另一个块中)。

· batch_timeout — The amount of time to wait for additional transactions after the first transaction arrives before cutting a block.

· batch_timeout在第一个事务到达之后,在切割一个块之前等待其他事务的时间。

Note: If you’d like more details regarding the block cutting parameters described above, see Updating a channel configuration section in the Hyperledger Fabric official documentation.

注意 :如果需要有关上述块切割参数的更多详细信息,请参阅Hyperledger Fabric官方文档中的“ 更新通道配置”部分。

Let’s now define a set of variables to capture the above parameters:

现在让我们定义一组变量来捕获上述参数:

var (    batchSizeMaxMessage uint32    batchSizeAbsoluteMax uint32    batchSizePreferredMax uint32    batchTimeout uint32)

In your code, you can assign values to these variables accordingly. For instance, you could read them from a properties file or you could pass these values as runtime arguments to your program. Regardless of how you provide such values to your application, once you have read them, you can assign them to these variables:

在代码中,您可以为这些变量相应地赋值。 例如,您可以从属性文件中读取它们,也可以将这些值作为运行时参数传递给程序。 无论如何向应用程序提供此类值,一旦阅读它们,就可以将它们分配给以下变量:

batchSizeMaxMessage = ...batchSizeAbsoluteMax = ...batchSizePreferredMax = ...batchTimeout = ...

After having done this, you can proceed to update the configuration block using the following API methods from the fabric-config library:

完成此操作后,您可以继续使用fabric-config库中的以下API方法来更新配置块:

// Obtain OrdererGroup instance from ConfigTx instanceordererGrp := configTx.Orderer()// Use setter methods in the OrdererGroup instance to make configuration changesordererGrp.SetBatchTimeout(time.Second * time.Duration(batchTimeout))ordererGrp.BatchSize().SetAbsoluteMaxBytes(batchSizeAbsoluteMax)ordererGrp.BatchSize().SetMaxMessageCount(batchSizeMaxMessage)ordererGrp.BatchSize().SetPreferredMaxBytes(batchSizePreferredMax)

Once you have made the configuration updates to the block, you then compute the delta for these changes:

对块进行配置更新后,即可计算这些更改的增量:

var (    channelName string)...configUpdateBytes, err := configTx.ComputeMarshaledUpdate(channelName)...

After computing the delta, the next step is to optionally sign the updates that were made to the block. Before doing so, let’s introduce a getSigningIdentity() method for parsing identity information from a local Membership Service Provider (MSP):

在计算完增量之后,下一步是可以选择对块进行的更新签名。 在这样做之前,让我们介绍一个getSigningIdentity()方法,用于解析来自本地成员资格服务提供商(MSP)的身份信息:

func getSigningIdentity(sigIDPath string) *configtx.SigningIdentity {    // Read certificate, private key and MSP ID from sigIDPath    var (        certificate *x509.Certificate        privKey     crypto.PrivateKey        mspID       string        err         error    )    mspUser := filepath.Base(sigIDPath)    certificate, err = readCertificate(filepath.Join(sigIDPath, "msp", "signcerts", fmt.Sprintf("%s-cert.pem", mspUser)))    if err != nil {        panic(err)    }    privKey, err = readPrivKey(filepath.Join(sigIDPath, "msp", "keystore", "priv_sk"))    if err != nil {        panic(err)    }    mspID = strings.Split(mspUser, "@")[1]    return &configtx.SigningIdentity{        Certificate: certificate,        PrivateKey: privKey,        MSPID: mspID,    }}

Following below are the helper methods used in the above function. First, let’s define the readCertificate() method:

以下是上述功能中使用的辅助方法。 首先,让我们定义readCertificate()方法:

func readCertificate(certPath string) (*x509.Certificate, error) {    certBytes, err := ioutil.ReadFile(certPath)    if err != nil {        return nil, err    }    pemBlock, _ := pem.Decode(certBytes)    if pemBlock == nil {        return nil, fmt.Errorf("no PEM data found in cert[% x]", certBytes)    }    return x509.ParseCertificate(pemBlock.Bytes)}

And here’s the readPrivKey() method:

这是readPrivKey()方法:

func readPrivKey(keyPath string) (crypto.PrivateKey, error) {    privKeyBytes, err := ioutil.ReadFile(keyPath)    if err != nil {        return nil, err    }pemBlock, _ := pem.Decode(privKeyBytes)    if pemBlock == nil {        return nil, fmt.Errorf("no PEM data found in private key[% x]", privKeyBytes)    }    return x509.ParsePKCS8PrivateKey(pemBlock.Bytes)}

Just like the getConfigFromBlock() method, the getSigningIdentity() can also be used for any type of scenario. Thus, you can add the getSigningIdentity() function to your application code and use it regardless of the configuration updates you need to make. The getSigningIdentity() method takes as its sole parameter the path to a root MSP folder that should have a set of subfolders with the corresponding certificates and keys for an MSP organization user or administrator. The name of this root folder should follow the following naming convention: <enrollment_id>@<MSP ID>. For instance, the identity materials of the Admin user for the Orderer organization identified by OrdererMSP should reside under a folder named Admin@OrdererMSP. The names for the certificates and keys found under the subfolders should be as follows:

就像getConfigFromBlock()方法一样, getSigningIdentity()也可以用于任何类型的方案。 因此,您可以将getSigningIdentity()函数添加到应用程序代码中,并使用它,而无需进行任何配置更新。 getSigningIdentity()方法将其根MSP文件夹的路径作为其唯一参数,该路径应具有一组子文件夹,其中包含MSP组织用户或管理员的相应证书和密钥。 该根文件夹的名称应遵循以下命名约定: <enrollment_id>@<MSP ID> 。 例如,由OrdererMSP标识的Orderer组织的Admin用户的身份材料应位于名为Admin@OrdererMSP的文件夹下。 在子文件夹下找到的证书和密钥的名称应如下:

<enrollment_id>@<MSP ID>└── msp       ├──    │   │   // The public cert for the org administrator    │   └─    ├─    │   │   // The public cert for the root CA    │   └─    ├─    │   │   // The public cert for the root TLS CA    │   └─    ├─    │   │   // The private key for the identity    │   └─    └─        │   // The public cert for the identity        └─

Note: If you have used the cryptogen tool, the folder structure shown above should be familiar to you.

注意:如果您使用了加密原工具,那么上面显示的文件夹结构应该很熟悉 。

Note that the getSigningIdentity() method returns a pointer to an instance of the configtx.SigningIdentity structure, which is also defined in the fabric-config library.

请注意, getSigningIdentity()方法返回一个指向configtx.SigningIdentity结构实例的指针,该实例也在fabric-config库中定义。

For each identity that should sign the channel configuration updates, you should invoke the getSigningIdentity() method (you can store each identity returned from invoking this method in an array). Once you have all required identities for signing the configuration updates, you use the CreateConfigSignature method in the configtx.SigningIdentity structure to create a corresponding signature:

对于应该对通道配置更新进行签名的每个标识,您应该调用getSigningIdentity()方法(您可以将调用此方法返回的每个标识存储在数组中)。 获得用于签名配置更新的所有必需身份之后,可在configtx.SigningIdentity结构中使用CreateConfigSignature方法创建相应的签名:

configSignatures := []*cb.ConfigSignature{}...signingIdentity := getSigningIdentity(pathToSigningIdentity)...configSignature, err := signingIdentity.CreateConfigSignature(configUpdateBytes)...configSignatures = append(configSignatures, configSignature)

The CreateConfigSignature method takes as its argument the delta that we computed earlier by invoking the ComputeMarshaledUpdate() function, configUpdateBytes.

CreateConfigSignature方法将我们先前通过调用ComputeMarshaledUpdate()函数configUpdateBytes.计算出的增量作为参数configUpdateBytes.

After generating the necessary signatures, you use the following method for creating the envelope, which contains the configuration changes along with the signatures:

生成必要的签名后,您可以使用以下方法创建信封,其中包含配置更改以及签名:

env, err := configtx.NewEnvelope(configUpdateBytes, configSignatures...)

As it was the case with CreateConfigSignature, configUpdateBytes is the configuration delta returned from the invocation of the ComputeMarshaledUpdate() function, while configSignatures is an array that contains all necessary signatures (i.e. pointers to instances of the ConfigSignature structure). For the example case we are discussing in this article (i.e. block cutting parameters changes), we only need the signature of the administrator of the ordering service organization.

CreateConfigSignature,的情况一样CreateConfigSignature, configUpdateBytes是从ComputeMarshaledUpdate()函数的调用返回的配置增量,而configSignatures是一个包含所有必要签名(即,指向ConfigSignature结构实例的指针)的ConfigSignature 。 对于我们在本文中讨论的示例案例(即,切割参数的更改),我们仅需要订购服务组织的管理员的签名。

You may also wish to sign the envelope returned from the NewEvelope() function using the identity that will submit the transaction to one of the ordering service nodes. In our example case, this identity is also the administrator of the ordering service organization. You obtain this identity instance by also invoking the getSigningIdentity() method, which as we already mentioned, returns an instance of the configtx.SigningIdentity structure:

您可能还希望使用将事务提交到订购服务节点之一的身份对从NewEvelope()函数返回的信封进行签名。 在我们的示例案例中,此身份也是订购服务组织的管理员。 您还可以通过调用getSigningIdentity()方法来获得此身份实例,正如我们已经提到的,该方法返回configtx.SigningIdentity结构的实例:

envelopeSigningIdentity := getSigningIdentity(pathToEnvelopeSigningIdentity)err = envelopeSigningIdentity.SignEnvelope(env)

Finally, we write the signed envelope to the file system:

最后,我们将签名的信封写入文件系统:

envelopeBytes, err := proto.Marshal(env)if err != nil {    panic(err)}err = ioutil.WriteFile(outputPath, envelopeBytes, 0640)

You now have a configuration update transaction with the changes and [signatures] that can be submitted to the network for processing! As reference, here’s the complete source code for the example program:

现在,您将拥有一个配置更新事务,其中包含更改和[签名],可以将其提交给网络进行处理! 作为参考,下面是示例程序的完整源代码:

package mainimport ("crypto""crypto/x509""encoding/pem""fmt""io/ioutil""path/filepath""strings""time""github.com/golang/protobuf/proto""github.com/hyperledger/fabric-config/configtx"cb "github.com/hyperledger/fabric-protos-go/common"
)func main() {var (batchSizeMaxMessage           uint32batchSizeAbsoluteMax          uint32batchSizePreferredMax         uint32batchTimeout                  uint32blockPath                     stringchannelName                   stringpathToSigningIdentity         stringpathToEnvelopeSigningIdentity stringoutputPath                    string)// Update variables as needed for your use casebatchSizeMaxMessage = 10batchSizeAbsoluteMax = 103809024batchSizePreferredMax = 524288batchTimeout = 4blockPath = "<blockPath>"channelName = "<channelName>"pathToSigningIdentity = "<pathToSigningIdentity>"pathToEnvelopeSigningIdentity = "<pathToEnvelopeSigningIdentity>"outputPath = "<outputPath>"// Read configuration block into memorybaseConfig := getConfigFromBlock(blockPath)configTx := configtx.New(baseConfig)// Obtain OrdererGroup instance from ConfigTx instanceordererGrp := configTx.Orderer()// Use setter methods in the OrdererGroup instance to make configuration changesordererGrp.SetBatchTimeout(time.Second * time.Duration(batchTimeout))ordererGrp.BatchSize().SetAbsoluteMaxBytes(batchSizeAbsoluteMax)ordererGrp.BatchSize().SetMaxMessageCount(batchSizeMaxMessage)ordererGrp.BatchSize().SetPreferredMaxBytes(batchSizePreferredMax)// Compute deltaconfigUpdateBytes, err := configTx.ComputeMarshaledUpdate(channelName)if err != nil {panic(err)}// Attach signaturesigningIdentity := getSigningIdentity(pathToSigningIdentity)configSignature, err := signingIdentity.CreateConfigSignature(configUpdateBytes)if err != nil {panic(err)}// Create envelopeenv, err := configtx.NewEnvelope(configUpdateBytes, configSignature)// Sign envelopeenvelopeSigningIdentity := getSigningIdentity(pathToEnvelopeSigningIdentity)err = envelopeSigningIdentity.SignEnvelope(env)envelopeBytes, err := proto.Marshal(env)if err != nil {panic(err)}// Write envelope to file systemerr = ioutil.WriteFile(outputPath, envelopeBytes, 0640)
}func getConfigFromBlock(blockPath string) *cb.Config {blockBin, err := ioutil.ReadFile(blockPath)if err != nil {panic(err)}block := &cb.Block{}err = proto.Unmarshal(blockBin, block)if err != nil {panic(err)}blockDataEnvelope := &cb.Envelope{}err = proto.Unmarshal(block.Data.Data[0], blockDataEnvelope)if err != nil {panic(err)}blockDataPayload := &cb.Payload{}err = proto.Unmarshal(blockDataEnvelope.Payload, blockDataPayload)if err != nil {panic(err)}config := &cb.ConfigEnvelope{}err = proto.Unmarshal(blockDataPayload.Data, config)if err != nil {panic(err)}return config.Config
}func getSigningIdentity(sigIDPath string) *configtx.SigningIdentity {// Read certificate, private key and MSP ID from sigIDPathvar (certificate *x509.CertificateprivKey     crypto.PrivateKeymspID       stringerr         error)mspUser := filepath.Base(sigIDPath)certificate, err = readCertificate(filepath.Join(sigIDPath, "msp", "signcerts", fmt.Sprintf("%s-cert.pem", mspUser)))if err != nil {panic(err)}privKey, err = readPrivKey(filepath.Join(sigIDPath, "msp", "keystore", "priv_sk"))if err != nil {panic(err)}mspID = strings.Split(mspUser, "@")[1]return &configtx.SigningIdentity{Certificate: certificate,PrivateKey:  privKey,MSPID:       mspID,}
}func readCertificate(certPath string) (*x509.Certificate, error) {certBytes, err := ioutil.ReadFile(certPath)if err != nil {return nil, err}pemBlock, _ := pem.Decode(certBytes)if pemBlock == nil {return nil, fmt.Errorf("no PEM data found in cert[% x]", certBytes)}return x509.ParseCertificate(pemBlock.Bytes)
}func readPrivKey(keyPath string) (crypto.PrivateKey, error) {privKeyBytes, err := ioutil.ReadFile(keyPath)if err != nil {return nil, err}pemBlock, _ := pem.Decode(privKeyBytes)if pemBlock == nil {return nil, fmt.Errorf("no PEM data found in private key[% x]", privKeyBytes)}return x509.ParsePKCS8PrivateKey(pemBlock.Bytes)
}

注意事项 (Considerations)

Although the fabric-config library supports a significantly improved process for updating channel configuration, there are still some considerations to take into account.

尽管fabric-config库支持显着改进的更新通道配置的过程,但是仍然需要考虑一些注意事项。

Though you could use the library to update channel configurations for any version of Hyperledger Fabric, it is highly recommended that you use it for updating Hyperledger Fabric v2 channels or for migrations to Hyperledger Fabric v2 as some deprecated fields are not supported.

尽管您可以使用该库来更新任何版本的Hyperledger Fabric的通道配置,但由于不支持某些不赞成使用的字段,因此强烈建议您使用它来更新Hyperledger Fabric v2通道或迁移到Hyperledger Fabric v2。

As it’s written in Go, the library can only be utilized by consumers writing tooling in Go. This can be circumvented by creating general purpose tooling (such as command line interfaces) that aren’t embedded directly in a target application. Such an approach would allow using the library externally for generating configuration update transactions. Alternatively, one could set up a server written in Go that serves endpoints on which configuration transaction updates can be generated from input configuration blocks.

正如用Go语言编写的那样,该库只能由使用Go语言编写工具的消费者使用。 可以通过创建通用工具(例如命令行界面)来避免这种情况,这些工具没有直接嵌入目标应用程序中。 这种方法将允许在外部使用该库来生成配置更新事务。 或者,可以设置用Go语言编写的服务器,该服务器用于可从输入配置块生成配置事务更新的端点。

Existing users of Hyperledger Fabric may already have a stable method for updating configuration transactions; thus, they may not be open to making amendments to their existing automation and processes to consume this library. However, eventually it will become too onerous to maintain current workarounds for channel configuration management as new features are added around channel configuration. Rather than having to manually update bits and pieces of workaround code, consumption of this library will become a consistent method for adopting new features via simple extensions.

Hyperledger Fabric的现有用户可能已经拥有一种稳定的方法来更新配置事务。 因此,他们可能不愿意修改现有的自动化和使用该库的过程。 但是,随着在通道配置周围添加新功能,最终难以维护当前的通道配置管理变通方法。 无需手动更新零散的解决方法代码,使用此库将成为通过简单扩展来采用新功能的一致方法。

结论 (Conclusion)

As shown in this article, The Hyperledger fabric-config library provides a sound mechanism for producing configuration transaction updates while at the same time eliminating the mechanical and error-prone steps that are present when making such changes manually. Therefore, the fabric-config library gives you the capability to automate configuration transaction updates in a reliable and consistent fashion.

如本文所示,Hyperledger fabric-config库提供了一种可靠的机制来生成配置事务更新,同时消除了手动进行此类更改时出现的机械步骤和易于出错的步骤。 因此,fabric-config库使您能够以可靠且一致的方式自动执行配置事务更新。

Although not shown in this post, the fabric-config library also supports generating configuration envelopes for application and system channel creation as well as modifying application and channel capabilities. This library, being written in Go, provides a type-safe and compiled option for such operations.

尽管未在本文中显示,fabric-config库还支持生成用于应用程序和系统通道创建的配置包络以及修改应用程序和通道功能 。 用Go语言编写的该库为此类操作提供了类型安全且经过编译的选项。

We certainly encourage you to take a look at the official GoDoc documentation for the fabric-config library so you can familiarize yourself with its intuitive and easy to use API, as well as to see additional examples and code snippets. With the guidance and functions shared in this article, you can start leveraging the fabric-config library right away in your next project!

我们当然鼓励您查看fabric-config库的官方GoDoc 文档 ,以便熟悉其直观且易于使用的API,并查看其他示例和代码段。 利用本文中共享的指导和功能,您可以立即在下一个项目中利用fabric-config库!

致谢 (Acknowledgements)

We’d like to offer our special thanks to Jorge D. Rodriguez for a thorough and comprehensive review of this article!

我们要特别感谢Jorge D. Rodriguez对本文进行全面而全面的评论!

翻译自: https://medium.com/enterprise-blockchain-labs/leveraging-the-hyperledger-fabric-config-library-for-channel-configuration-updates-7642e6d9eef9

http://www.taodudu.cc/news/show-4427296.html

相关文章:

  • G6信息门户连接不上服务器,G6客户端提示找不到服务器怎么回事 网是通 的
  • 用友通10.1禁止安装在SQL2005
  • 通道结构体_超账结构中系统通道和应用程序通道上的配置更新
  • 区块链超级记帐本架构概览
  • python身份证识别
  • PaddleHub一键OCR中文识别 身份证识别
  • 百度身份证识别
  • Python实现AI图像识别-身份证识别
  • Android 集成百度身份证识别
  • Android OpenCV 身份证识别实战
  • OpenCV-Python身份证信息识别
  • 斯柯达支持Android auto吗,斯柯达在SUV的布局输了吗?看柯米克和柯珞克的现状就知道...
  • 苹果教你如何开发iOS应用
  • 模拟器启动不起来怎么解决
  • 被企业微信吓到了吗?离做到极致还早
  • 买车?
  • 使用spark TF-IDF特征计算文章间相似度
  • 新鲜出炉2018年上半年(低、中、高价位)SUV车型销量排行榜
  • 万字报告!一文看懂全球车厂的技术家底模块化平台
  • 哪些便宜车值得购买
  • 15万甚至30万以内的SUV值不值得买?
  • 主流车品牌魅力指数榜别克、东风日产、一汽丰田列前三
  • 大众中国纯电动战略“水土不服”?理想ONE冲击月销过万目标
  • Java异常处理——日志打印
  • 国内CRM竞品分析【纷享销客 VS 销售易 VS 用友】
  • 纷享销客显示无法连接服务器,纷享销客
  • 达梦客户端工具的使用
  • 微信支付(销客多)配置
  • 01 JDK8安装教程
  • [读书笔记]结绳记事

利用Hyperledger fabric-config库进行通道配置更新相关推荐

  1. 利用Hyperledger Fabric开发你的第一个区块链应用

    利用Hyperledger Fabric开发你的第一个区块链应用 本文示例源于fabric-samples中的fabcar https://github.com/hyperledger/fabric- ...

  2. 利用Hyperledger Fabric开发第一个区块链应用

    利用Hyperledger Fabric开发第一个区块链应用 Fabric入门 Fabric 我们通过一个简单的示例程序来了解Fabric应用是如何运行的.在这个例子中使用的应用程序和智能合约(链码) ...

  3. Fabric 1.0源代码分析(27) Orderer #configupdate(处理通道配置更新)

    # Fabric 1.0源代码笔记 之 Orderer #configupdate(处理通道配置更新) ## 1.configupdate概述 configupdate,用于接收配置交易,并处理通道配 ...

  4. 兄弟连区块链教程Fabric1.0源代码分析configupdate处理通道配置更新

    区块链教程Fabric1.0源代码分析configupdate处理通道配置更新,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁.回归理性,表面上看相关人才需求与身价似乎正在回落.但事实上,正是初 ...

  5. Hyperledger Fabric区块链工具configtxgen配置configtx.yaml

    configtx.yaml是Hyperledger Fabric区块链网络运维工具configtxgen用于生成通道创世块或通道交易的配置文件,configtx.yaml的内容直接决定了所生成的创世区 ...

  6. [求助]hyperledger fabric在创建peer通道时出现this policy requires 1 of the 'Writers' sub-policies to be……

    毕业设计打算做区块链有关的内容,目前买了本机械工业出版社出版的<区块链开发实战 hyperledger Fabric关键技术与案例分析>这本书来学习,可能由于版本问题,在使用书上的配置文件 ...

  7. Hyperledger Fabric2中文文档-修改通道配置

    翻译:https://hyperledger-fabric.readthedocs.io/en/latest/config_update.html 观看者:网络管理员,节点管理员 什么是通道配置? 像 ...

  8. 区块链:Hyperledger Fabric环境配置及fabric-sample测试运行

    环境准备 安装go1.11 以及以上版本 安装docker 17.06.2-ce 以及以上版本 安装docker-compose 1.14.0 以及以上版本 git 拉下 fabric-sample ...

  9. Hyperledger Fabric 2.0 官方文档中文版 第6章 教程(下)

    Hyperledger Fabric 2.0 官方文档中文版 第6章 教程下 总目录 6.教程(下) 使用CouchDB 为什么使用CouchDB? 在Hyperledger Fabric中启用Cou ...

最新文章

  1. 在Ubuntu中打开pycharm步骤:
  2. BCI competition IV 2b简介
  3. c语言 sizeof size_t,C/C++中的sizeof运算符和size_t类型的详解
  4. MPI 集合通信函数 MPI_Reduce(),MPI_Allreduce(),MPI_Bcast(),MPI_Scatter(),MPI_Gather(),MPI_Allgather(),MPI_S
  5. 口罩告急,全民互助!“口罩互助”小程序重磅上线!
  6. 有高级计算机证可以入户东莞吗,本科有学位或有高级职称,2019年可以入户东莞吗?...
  7. 探究Java File类中list()、listFiles()的使用及区别,认识和使用匿名内部类
  8. Python 第三方模块之 psutil - 获取系统运行的进程和系统利用率信息
  9. 前端每日值得花时间看的博客
  10. CA与数字证书的自结
  11. 如何在Spyder中使用远程服务器的python来调试代码
  12. java hashmap用法_备战金九银十:Java核心技术面试题100+,助你搞定面试官
  13. linux 内核 介绍,Linux内核详细介绍
  14. 开元酒店在中国的签约及在营酒店规模正式超过600家
  15. oracle-j2sdk1.8,cloudera-manager – 没有包oracle-j2sdk1.7可用?
  16. 运行JavaScript代码片段的19种工具
  17. 如何启用计算机的无线功能,笔记本电脑怎么开WiFi_笔记本电脑如何打开WIFI功能-win7之家...
  18. 【python做简单的数据分析、绘图】
  19. Lottie 免费动画、在线预览
  20. Deep Learning 最优化方法

热门文章

  1. win7无法连接打印机拒绝访问_win7共享打印机无法连接怎么办?win7连不上共享打印机解决方法...
  2. 什么是父子流程,与分合流有什么不同
  3. 计算机图形学中消隐的相关概念及算法
  4. 【Scratch考级99图】图20-等级考试scratch绘制复杂图形5个正方形 少儿编程 scratch画图案例教学
  5. matlab识别中国象棋棋盘,一种基于图像处理的中国象棋识别系统及方法与流程
  6. 面对不同种类的处理结果——result type=
  7. 通讯录vcf生成工具
  8. oschina使用方法
  9. Ubuntu 18.04 安装搜狗输入法
  10. 北京车辆从4S店提车以后自己上牌怎么操作