区块链hyperledger fabric

(翻译)fabric1.2.1新特性-可拔插交易背书和验证

2018-07-31  本文已影响68人  还是小把戏

可拔插交易背书和验证

动机

当交易在提交被验证时,peer节点在交易本身的状态改变之前执行各种检查:

有些用例要求与fabric验证规则不同的自定义交易验证规则,例如:

可拔插背书与验证逻辑

fabric运行将定制的背书和验证逻辑实现和部署在peer节点中,以可插拔的方式与链码处理相关联。这个逻辑不仅可以编译到peer节点中,内置于可选逻辑中,也可以作为Golang插件与peer节点一起编译和部署。
回想一下,在链码实例化时,每个链码都与其自己的背书和验证逻辑相关联。如果用户未选择一个,则隐式选择默认的内置逻辑。peer节点管理员通过在peer节点启动时加载并且应用定制的背书/验证逻辑来改变通过扩展peer节点本地配置而选择的背书/验证逻辑。

配置

每一个peer节点都有一个本地配置文件(core.yaml),它声明了背书/验证逻辑名称和要运行的实现之间的映射关系。
默认的背书逻辑叫做ESCC,默认的验证逻辑叫做VSCC,他们的定义可以在本地配置文件的"handlers"部分找到:

handlers:
    endorsers:
      escc:
        name: DefaultEndorsement
    validators:
      vscc:
        name: DefaultValidation

当背书或者验证实现被编译到peer节点中时,"name"属性标识要运行的初始化函数,以便获得创建背书/验证逻辑实例的工程。
该函数是在"core/handlers/library/library.go"路径下的HandlerLibrary构造的实例方法,为了添加自定义背书/验证逻辑,需要使用任何额外的方法扩展此构造。
由于这很复杂并且较难于部署,因此可以以Golang插件的形式通过在名为"library"属性名称下添加另一个属性来部署自定义的背书/验证模块。
举个例子,如果我们以插件的形式实现了自定义的背书和验证逻辑模块作为基于状态的背书,我们可以在core.yaml配置文件中以如下形式定义:

handlers:
    endorsers:
      escc:
        name: DefaultEndorsement
      statebased:
        name: state_based
        library: /etc/hyperledger/fabric/plugins/state_based_endorsement.so
    validators:
      vscc:
        name: DefaultValidation
      statebased:
        name: state_based
        library: /etc/hyperledger/fabric/plugins/state_based_validation.so

我们必须将.so插件文件放在peer节点本地文件系统中。

此后,自定义背书或者验证逻辑实现将被称为"插件",即使它们被编译到peer节点中。

背书插件实现

为了实现背书插件,必须实现在"core/handlers/endorsement/api/endorsement.go"文件中相应的插件接口:

// 背书插件提案回复
type Plugin interface {
    //为给定的有效载荷(ProposalResponsePayload字节)背书签名,并且可以选择改变它
    // 返回:
    // 背书:有效载荷上签名,以及用于验证签名的标识。
    // 作为输入提供的有效载荷(可在此功能中修改)
    // 或者失败时出错
    Endorse(payload []byte, sp *peer.SignedProposal) (*peer.Endorsement, []byte, error)

    // 初始化将依赖注入插件的实例
    Init(dependencies ...Dependency) error
}

通过让peer节点调用PluginFactory接口中的New方法为每个通道创建给定插件类型(通过方法名称识别为HandlerLibrary的实例方法或者.so插件文件路径)的背书插件实例,该方法期望由插件开发人员实现:

// PluginFactory 创建一个新的插件实例
type PluginFactory interface {
    New() Plugin
}

初始化方法被希望接收在"core/handlers/endorsement/api/"路径下声明的,识别为嵌入Dependency接口的所有依赖项作为输入。

在创建插件实例之后,peer节点将依赖关系作为传递参数调用初始化方法(Init)。

目前,fabric为背书插件提供了一下依赖项:

// SigningIdentity对消息进行签名并将其公共标识序列化为字节数据
type SigningIdentity interface {
    // Serialize 返回此标识的字节表示形式,用于验证此SigningIdentity签名的消息
    Serialize() ([]byte, error)

    // Sign 为给定有效载荷签名并返回签名
    Sign([]byte) ([]byte, error)
}
// State 定义与状态数据的交互方式
type State interface {
    // GetPrivateDataMultipleKeys 在一次调用中获取多个私有数据项的值
    GetPrivateDataMultipleKeys(namespace, collection string, keys []string) ([][]byte, error)

    // GetStateMultipleKeys 在一次调用中获取多个键的值
    GetStateMultipleKeys(namespace string, keys []string) ([][]byte, error)

    // GetTransientByTXID 获取与给定txID关联的私有数据值
    GetTransientByTXID(txID string) ([]*rwset.TxPvtReadWriteSet, error)

    // Done 释放状态数据占用的资源
    Done()
 }

验证插件的实现

为了实现验证插件,必须实现在路径"core/handlers/validation/api/validation.go"下的插件接口:

// 验证交易插件
type Plugin interface {
    // 如果在给定块中给定位置的交易内给定位置的动作是有效的Validate函数返回nil,否则返回一个error错误
    Validate(block *common.Block, namespace string, txPosition int, actionPosition int, contextData ...ContextDatum) error

    // 初始化将依赖注入插件的实例
    Init(dependencies ...Dependency) error
}

每个ContextDatum都是由peer节点传递给验证插件的额外的运行时派生的元数据。目前,唯一传递的ContextDatum是代表链码的背书策略:

 // SerializedPolicy 定义一个序列化策略
type SerializedPolicy interface {
      validation.ContextDatum

      // Bytes 返回SerializedPolicy字节形式数据
      Bytes() []byte
 }

通过让peer节点调用PluginFactory接口中的New方法为每个通道创建给定插件类型(通过方法名称识别为HandlerLibrary的实例方法或者.so插件文件路径)的验证插件实例,该方法期望由插件开发人员实现:

// PluginFactory 创建一个新的插件实例
type PluginFactory interface {
    New() Plugin
}

初始化方法被希望接收在"core/handlers/validation/api/"路径下声明的,识别为嵌入Dependency接口的所有依赖项作为输入。

在创建插件实例之后,peer节点将依赖关系作为传递参数调用初始化方法(Init)。

目前,fabric为背书插件提供了一下依赖项:

// PolicyEvaluator 评估策略
type PolicyEvaluator interface {
    validation.Dependency

    // Evaluate 接收一组签名数据并评估这组签名是否满足给定的字节数据的策略
    Evaluate(policyBytes []byte, signatureSet []*common.SignedData) error
}
// State 定义与状态数据的交互方式
type State interface {
    // GetStateMultipleKeys 在一次调用中获取多个键的值
    GetStateMultipleKeys(namespace string, keys []string) ([][]byte, error)

    // GetStateRangeScanIterator 返回一个包含给定键范围的所有键值集合的迭代器。startKey被包含在结果中,并且排除了endKey。空的startKey引用第一个可用键,空的endKey引用最后一个可用键。为了扫描所有键,startKey和endKey都可以作为空字符串提供。但是,出于性能原因,应谨慎使用完整扫描。返回的ResultsIterator包含类型为*KV的结果,该结果定义在"protos/ledger/queryresult"
    GetStateRangeScanIterator(namespace string, startKey string, endKey string) (ResultsIterator, error)

    // Done 释放状态数据占用的资源
    Done()
}

重要注意事项

上一篇 下一篇

猜你喜欢

热点阅读