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

可拔插交易背书和验证

动机

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

  • 验证签名交易的标识
  • 验证交易中背书人的签名
  • 确保交易满足相应链码的命名空间的背书策略

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

  • State-based endorsemet(基于状态的背书):当背书策略取决于密钥,并不仅仅取决于命名空间。
  • UTXO(Unspent Transaction Output未花费交易输出):当验证考虑到,不论交易是否不会对输入双花。
  • Anonymous transactions(匿名交易):当背书不包含peer节点的身份,但是无法链接到peer节点身份的签名和公钥被共享。

可拔插背书与验证逻辑

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为背书插件提供了一下依赖项:

  • SigningIdentityFetcher:返回一个局域给定签名提案的SigningIdentity实例:
// SigningIdentity对消息进行签名并将其公共标识序列化为字节数据
type SigningIdentity interface {
    // Serialize 返回此标识的字节表示形式,用于验证此SigningIdentity签名的消息
    Serialize() ([]byte, error)

    // Sign 为给定有效载荷签名并返回签名
    Sign([]byte) ([]byte, error)
}
  • StateFetcher:获取与状态数据库(world state)交互的状态对象(State)。
// 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为背书插件提供了一下依赖项:

  • IdentityDeserializer:将标识身份的byte数据转换为可被用于验证由其签名的身份对象,并根据其对应的MSP进行验证,并查看他们是否满足给定的MSP Principal(见MSP服务相关源码)。完整的规范被定义在"core/handlers/validation/api/identities/identities.go"。

  • PolicyEvaluator:评估是否满足给定的策略:

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

    // Evaluate 接收一组签名数据并评估这组签名是否满足给定的字节数据的策略
    Evaluate(policyBytes []byte, signatureSet []*common.SignedData) error
}
  • StateFetcher:获取与状态数据库(world state)交互的状态对象(State)。
// 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()
}

重要注意事项

  • 所有节点验证插件的一致性:在将来的版本中,fabric通道基础设施将保证在任何给定的区块链高度,通道中的所有peer节点对给定的链码使用相同的验证逻辑,以消除可能由于在peer节点之间意外运行不同实现导致状态差异的错误配置的可能性。但是,目前系统才做元和管理员有责任确保不会发生这种情况。
  • 验证插件的错误处理:每当验证插件无法确定由于某些瞬态执行问题(例如,无法访问数据库)而无法确定给定交易是否被验证有效时,它应该返回在"core/handlers/validation/api/validation.go"中定义的ExecutionFailureError类型的错误。但是,如果返回ExecutionFailureError错误,则链处理将暂停,而不是将交易标记为无效。只是为了防止不同peer节点之间的状态分歧。
  • 将fabric代码导入插件:非常不鼓励导入除了协议之外的fabric代码作为插件的一部分,这可能在fabric发行版之间发生代码更改时导致问题,或者在运行不同版本peer节点时导致不可操作性问题。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容

  • 概要 区块链网络使用 gRPC 协议 Protocol Buffers(格式的 API) 使用的协议 gRPC P...
    简闻阅读 3,995评论 1 6
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,650评论 18 139
  • 这是对简书文档的一些勘误和丰富 参考https://hyperledger-fabric.readthedocs....
    peterSZW阅读 288评论 0 1
  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    阳明先生_X自主阅读 15,979评论 3 119
  • 本文主要讲xpath(还是以百度首页为例) 官方介绍:XPath即为XML路径语言,它是一种用来确定XML1(标准...
    敏儿最棒阅读 271评论 0 0