Hyperledger Fabric Chaincode开发详解(实例说明)

超级账本hyperledger fabric第十三集:hyperledger fabric终极案例 一.fabric开发流程: 让什么数据上链:所有节点备份数据耗费空间,视频等不要上链 如何交互:-c “Args”[“方法名”,参数] 编写合约 Init Invoke 拖到linux运行,基于配置好的网络去部署运行(安装和实例化) 合约交互 SDK调用(页面点击或输入信息) 二.需求分析: 1.开发转让资产 2.功能 用户开户和销户 资产登记,资产上链,与具体的用户... 阅读详情
  1. 导言

目前fabric开发主要分两大块,一是chaincode链上代码的开发,二是基于SDK的application开发;

本文主要是介绍fabric chaincode api,对api的功能和参数进行说明,同时针对每个主要api都给出了

使用例子。

  1. 目标:
  1. 熟悉fabric chaincode常用api的功能和使用方法;
  2. 熟悉fabric chaincode的开发流程以及能够编写chaincode;
  1. 入门实例

Go语言开发Chaincode链码

Chaincode的go代码首先需要一定结构体struct,然后在struct结构体上定义两个函数Init和Invoke,最后定义main函数作为chaincode的入口,模板如下:

package main

import (

   "github.com/hyperledger/fabric/core/chaincode/shim"

   pb "github.com/hyperledger/fabric/protos/peer"

   "fmt"

)

 

type SimpleChaincode struct {

}

 

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {

   _,args := stub.GetFunctionAndParameters()

   var A, B string  //entities

   var Aval, Bval int // asset holdings

   if len(args) != 4 {

       return shim.Error("Incorrect number of arguments. Expecting 4")

   }

   // TODO…

   return shim.Success(nil)

}

 

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {

   function, args := stub.GetFunctionAndParameters()

   fmt.Println("invoke is running " + function)

   if function == "add" {       //自定义函数名称

      return t.add (stub, args) //定义调用的函数

   }

   else if function == "delete"{

}

   return shim.Error("Received unknown function invocation")

}

func main() {

   err := shim.Start(new(SimpleChaincode))

   if err != nil {

      fmt.Printf("Error starting Simple chaincode: %s", err)

   }

}

 

4. Chaincode API

4.1 初始化接口

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response

Init(初始化)方法会在chaincode接收到instantiate(实例化)或者upgrade(升级)交易时被调用,进而使得chaincode顺利执行必要的初始化操作,包括初始化应用的状态;

说明

名称

类型

函数名

Init

自定义结构体

入参

stub

shim.ChaincodeStubInterface

返回值

Peer返回值

pb.Response

 

4.2 Invoke接口

func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response

Invoke(调用)方法会在响应invoke(调用)交易时被调用以执行交易。根据传入的参数不同判断调用不同的函数,完成不同的功能。

说明

名称

类型

函数名

invoke

自定义结构体

入参

stub

shim.ChaincodeStubInterface

入参

args

[]string

返回值

Peer返回值

pb.Response

 

4.3 参数获取接口(shim.ChaincodeStubInterface)

4.3.1 GetArgs() [][]byte 

以byte数组的数组的形式获得传入的参数列表

说明

名称

类型

函数名

GetArgs

 

返回值

传入参数列表

[][]byte 

4.3.2 GetStringArgs() []string

以字符串数组的形式获得传入的参数列表

说明

名称

类型

函数名

GetStringArgs

 

返回值

传入参数列表

[]string

4.3.3 GetFunctionAndParameters() (string, []string)

将字符串数组的参数分为两部分,数组第一个字是Function,剩下的都是Parameter

说明

名称

类型

函数名

GetFunctionAndParameters

 

返回值

Function name

string

返回值

参数列表

[]string

4.3.4 GetArgsSlice() ([]byte, error) 

以byte切片的形式获得参数列表

说明

名称

类型

函数名

GetArgsSlice

 

返回值

参数列表

[]byte

返回值

错误码

error

4.4 增删改查State DB

4.4.1增改数据PutState(key string, value []byte) error

对于State DB来说,增加和修改数据是统一的操作,因为State DB是一个Key Value数据库,如果我们指定的Key在数据库中已经存在,那么就是修改操作,如果Key不存在,那么就是插入操作。对于实际的系统来说,我们的Key可能是单据编号,或者系统分配的自增ID+实体类型作为前缀,而Value则是一个对象经过JSON序列号后的字符串。

说明

名称

类型

函数名

PutState

 

传入值

Key

String

传入值

Value

[]byte

返回值

Error

Error

比如说我们定义一个Student的Struct,然后插入一个学生数据,对于的代码应该是这样的:

type Student struct {
   Id int
   Name string
}
func (t *SimpleChaincode) testStateOp(stub shim.ChaincodeStubInterface, args []string) pb.Response{
   student1:=Student{1,"Devin Zeng"}
   key:="Student:"+strconv.Itoa(student1.Id)//Key格式为 Student:{Id}
   studentJsonBytes, err := json.Marshal(student1)//Json序列号
   if err != nil {
      return shim.Error(err.Error())
   }
   err= stub.PutState(key,studentJsonBytes)
   if(err!=nil){
      return shim.Error(err.Error())
   }
   return shim.Success([]byte("Saved Student!"))
}


根据Key删除State DB的数据。如果根据Key找不到对于的数据,删除失败。4.4.2删除数据DelState(key string) error

说明

名称

类型

函数名

DelState

 

传入值

Key

String

返回值

Error

Error

4.4.3查询数据GetState(key string) ([]byte, error)

根据Key来对数据库进行查询。返回的数据是byte数组,我们需要转换为string,然后再Json反序列化,可以得到我们想要的对象。

说明

名称

类型

函数名

GetState

 

传入值

Key

String

返回值

Key对应的value值

[]byte

返回值

Error

Error

例:


dbStudentBytes,err:= stub.GetState(key)
var dbStudent Student;
err=json.Unmarshal(dbStudentBytes,&dbStudent)//反序列化
if err != nil {
   return shim.Error("{\"Error\":\"Failed to decode JSON of: " + string(dbStudentBytes)+ "\" to Student}")
}
fmt.Println("Read Student from DB, name:"+dbStudent.Name)

4.5 复合键

4.5.1 生成复合键

CreateCompositeKey(objectType string, attributes []string) (string, error)

在进行数据库的增删改查的时候,都需要用到Key,而我们使用的是我们自己定义的Key格式:{StructName}:{Id},这是有单主键Id还比较简单,如果我们有多个列做联合主键怎么办?实际上,ChainCode也为我们提供了生成Key的方法CreateCompositeKey,通过这个方法,我们可以将联合主键涉及到的属性都传进去,并声明了对象的类型即可。

说明

名称

类型

函数名

CreateCompositeKey

 

传入值

目标类型objectType

String

传入值

用来创建key的属性值

[]string

返回值

组合后的key值

string

返回值

error

error

使用:

type ChooseCourse struct {
   CourseNumber string //开课编号
   StudentId int //学生ID
   Confirm bool //是否确认
}
//其中CourseNumber+StudentId构成了这个对象的联合主键,我们要获得生成的复核主键,那么可写为:

cc:=ChooseCourse{"CS101",123,true} 
var key1,_= stub.CreateCompositeKey("ChooseCourse",[]string{cc.CourseNumber,strconv.Itoa(cc.StudentId)})
fmt.Println(key1)

4.5.2 拆分复合键

SplitCompositeKey(compositeKey string) (string, []string, error)

当我们从数据库中获得了一个复合键的Key之后,怎么知道其具体是由哪些字段组成的呢。其实就是用U+0000把这个复合键再Split开,得到结果中第一个是objectType,剩下的就是复合键用到的列的值。

说明

名称

类型

函数名

SplitCompositeKey

 

传入值

组合key:compositeKey

String

传入值

目标变量的类型

string

返回值

对象类型

objectType

返回值

组合key的组成成分

[]string

返回值

error

error

使用:

type Car struct {
    ID         string `json:"ID"`  // key
    Color      string `json:"Color"`
    Price      string `json:"Price"`
    LaunchDate string `json:"LaunchDate"`
}

// get the color, Price and name from composite key

objectType, compositeKeyParts, err := stub.SplitCompositeKey(responseRange.Key)

if err != nil {

       return shim.Error(err.Error())

}

returnedId := compositeKeyParts[0]

returnedColor := compositeKeyParts[1]

returnedPrice := compositeKeyParts[2]     

4.5.3 部分复合键的查询

GetStateByPartialCompositeKey(objectType string, keys []string) (StateQueryIteratorInterface, error)

一种对Key进行前缀匹配的查询,也就是说,我们虽然是部分复合键的查询,但是不允许拿后面部分的复合键进行匹配,必须是前面部分。即,根据局部的复合键(前缀)返回所有匹配的键值。返回结果是一个迭代器。可以按照字典序迭代每个键值对,最后需调用Close()方法关闭。

说明

名称

类型

函数名

GetStateByPartialCompositeKey

 

传入值

目标变量的类型

string

传入值

Key

[]string

返回值

StateQueryIteratorInterface

StateQueryIteratorInterface

返回值

error

error

使用:


func (sc *SimpleChaincode) queryAllOwner(stub shim.ChaincodeStubInterface) pb.Response {

    coloredMarbleResultsIterator, err := stub.GetStateByPartialCompositeKey(INDEX, []string{})

    if err != nil {
        return shim.Error(err.Error())
    }
    defer coloredMarbleResultsIterator.Close()   //函数结束时执行
    for coloredMarbleResultsIterator.HasNext() {
        responseRange, err := coloredMarbleResultsIterator.Next()
        if err != nil {
            return shim.Error(err.Error())
        }
        _, compositeKeyParts, err := stub.SplitCompositeKey(responseRange.Key)

        if err != nil {
            return shim.Error(err.Error())
        }
        // name := compositeKeyParts[0]
        // hashvalue := compositeKeyParts[1]
        owner := compositeKeyParts[2]
    }
    return shim.Success(buffer.Bytes())
}

4.6高级查询

4.6.1 Key区间查询

GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error)

提供了对某个区间的Key进行查询的接口,适用于任何State DB。由于返回的是一个StateQueryIteratorInterface接口,我们需要通过这个接口再做一个for循环,才能读取返回的信息,所有我们可以独立出一个方法,专门将该接口返回的数据以string的byte数组形式返回。

说明

名称/说明

类型

函数名

GetStateByRange

 

传入值

查询开始key:startKey

string

传入值

查询结束key:endKey

string

返回值

StateQueryIteratorInterface接口

StateQueryIteratorInterface

返回值

error

error

转换方法:

func getListResult(resultsIterator shim.StateQueryIteratorInterface) ([]byte,error){

 
   defer resultsIterator.Close()
   // buffer is a JSON array containing QueryRecords
   var buffer bytes.Buffer
   buffer.WriteString("[")

 
   bArrayMemberAlreadyWritten := false
   for resultsIterator.HasNext() {
      queryResponse, err := resultsIterator.Next()
      if err != nil {
         return nil, err
      }
      // Add a comma before array members, suppress it for the first array member
      if bArrayMemberAlreadyWritten == true {
         buffer.WriteString(",")
      }
      buffer.WriteString("{\"Key\":")
      buffer.WriteString("\"")
      buffer.WriteString(queryResponse.Key)
      buffer.WriteString("\"")

 
      buffer.WriteString(", \"Record\":")
      // Record is a JSON object, so we write as-is
      buffer.WriteString(string(queryResponse.Value))
      buffer.WriteString("}")
      bArrayMemberAlreadyWritten = true
   }
   buffer.WriteString("]")
   fmt.Printf("queryResult:\n%s\n", buffer.String())
   return buffer.Bytes(), nil
}
//假如我们要查询编号从1号到3号的所有学生,那么我们的查询代码可以这么写:
func (t *SimpleChaincode) testRangeQuery(stub shim.ChaincodeStubInterface, args []string) pb.Response{
   resultsIterator,err:= stub.GetStateByRange("Student:1","Student:3")
   if err!=nil{
      return shim.Error("Query by Range failed")
   }
   students,err:=getListResult(resultsIterator)
   if err!=nil{
      return shim.Error("getListResult failed")
   }
   return shim.Success(students)
}

4.6.2 富查询

GetQueryResult(query string) (StateQueryIteratorInterface, error)

这是一个“富查询”,是对Value的内容进行查询,如果是LevelDB,那么是不支持,只有CouchDB时才能用这个方法。传入的query这个字符串,其实是CouchDB所使用的Mango查询。

说明

名称/说明

类型

函数名

GetStateByRange

 

传入值

CouchDB查询语句query

string

返回值

StateQueryIteratorInterface接口

StateQueryIteratorInterface

返回值

error

error

 

我们仍然以前面的Student为例,我们要按Name来进行查询,那么我们的代码可以写为:

func (t *SimpleChaincode) testRichQuery(stub shim.ChaincodeStubInterface, args []string) pb.Response{
   name:="Devin Zeng"//这里按理来说应该是参数传入
   queryString := fmt.Sprintf("{\"selector\":{\"Name\":\"%s\"}}", name)
   resultsIterator,err:= stub.GetQueryResult(queryString)//必须是CouchDB才行
   if err!=nil{
      return shim.Error("Rich query failed")
   }
   students,err:=getListResult(resultsIterator)
   if err!=nil{
      return shim.Error("Rich query failed")
   }
   return shim.Success(students)
}

4.6.3 历史数据查询

GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)

对同一个数据(也就是Key相同)的更改,会记录到区块链中,我们可以通过GetHistoryForKey方法获得这个对象在区块链中记录的更改历史,包括是在哪个TxId,修改的数据,修改的时间戳,以及是否是删除等。

说明

名称/说明

类型

函数名

GetHistoryForKey

 

传入值

查询key

string

返回值

StateQueryIteratorInterface接口

StateQueryIteratorInterface

返回值

error

error

 

比如之前的Student:1这个对象,我们更改和删除过数据,现在要查询这个对象的更改记录,那么对应代码为:

func (t *SimpleChaincode) testHistoryQuery(stub shim.ChaincodeStubInterface, args []string) pb.Response{
   student1:=Student{1,"Devin Zeng"}
   key:="Student:"+strconv.Itoa(student1.Id)
   it,err:= stub.GetHistoryForKey(key)
   if err!=nil{
      return shim.Error(err.Error())
   }
   var result,_= getHistoryListResult(it)
   return shim.Success(result)
}
func getHistoryListResult(resultsIterator shim.HistoryQueryIteratorInterface) ([]byte,error){

 
   defer resultsIterator.Close()
   // buffer is a JSON array containing QueryRecords
   var buffer bytes.Buffer
   buffer.WriteString("[")

 
   bArrayMemberAlreadyWritten := false
   for resultsIterator.HasNext() {
      queryResponse, err := resultsIterator.Next()
      if err != nil {
         return nil, err
      }
      // Add a comma before array members, suppress it for the first array member
      if bArrayMemberAlreadyWritten == true {
         buffer.WriteString(",")
      }
      item,_:= json.Marshal( queryResponse)
      buffer.Write(item)
      bArrayMemberAlreadyWritten = true
   }
   buffer.WriteString("]")
   fmt.Printf("queryResult:\n%s\n", buffer.String())
  return buffer.Bytes(), nil
}

4.6.4 部分复合键查询

GetStateByPartialCompositeKey(objectType string, keys []string) (StateQueryIteratorInterface, error)

与2.5.3类似

说明

名称

类型

函数名

GetStateByPartialCompositeKey

 

传入值

目标变量的类型

string

传入值

Key

[]string

返回值

StateQueryIteratorInterface

StateQueryIteratorInterface

返回值

error

error

2.7 获得当前用户

GetCreator() ([]byte, error)

这个方法可以获得调用这个ChainCode的客户端的用户的证书,这里虽然返回的是byte数组,但是其实是一个字符串,内容格式如下:

-----BEGIN CERTIFICATE----- 
MIICGjCCAcCgAwIBAgIRAMVe0+QZL+67Q+R2RmqsD90wCgYIKoZIzj0EAwIwczEL 
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG 
cmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh 
Lm9yZzEuZXhhbXBsZS5jb20wHhcNMTcwODEyMTYyNTU1WhcNMjcwODEwMTYyNTU1 
WjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN 
U2FuIEZyYW5jaXNjbzEfMB0GA1UEAwwWVXNlcjFAb3JnMS5leGFtcGxlLmNvbTBZ 
MBMGByqGSM49AgEGCCqGSM49AwEHA0IABN7WqfFwWWKynl9SI87byp0SZO6QU1hT 
JRatYysXX5MJJRzvvVsSTsUzQh5jmgwkPbFcvk/x4W8lj5d2Tohff+WjTTBLMA4G 
A1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIO2os1zK9BKe 
Lb4P8lZOFU+3c0S5+jHnEILFWx2gNoLkMAoGCCqGSM49BAMCA0gAMEUCIQDAIDHK 
gPZsgZjzNTkJgglZ7VgJLVFOuHgKWT9GbzhwBgIgE2YWoDpG0HuhB66UzlA+6QzJ 
+jvM0tOVZuWyUIVmwBM= 
-----END CERTIFICATE-----

        我们常见的需求是在ChainCode中获得当前用户的信息,方便进行权限管理。那么我们怎么获得当前用户呢?我们可以把这个证书的字符串转换为Certificate对象。一旦转换成这个对象,我们就可以通过Subject获得当前用户的名字

func (t *SimpleChaincode) testCertificate(stub shim.ChaincodeStubInterface, args []string) pb.Response{
   creatorByte,_:= stub.GetCreator()
   certStart := bytes.IndexAny(creatorByte, "-----BEGIN")
   if certStart == -1 {
      fmt.Errorf("No certificate found")
   }
   certText := creatorByte[certStart:]
   bl, _ := pem.Decode(certText)
   if bl == nil {
      fmt.Errorf("Could not decode the PEM structure")
   }

 
   cert, err := x509.ParseCertificate(bl.Bytes)
   if err != nil {
      fmt.Errorf("ParseCertificate failed")
   }
   uname:=cert.Subject.CommonName
   fmt.Println("Name:"+uname)
   return shim.Success([]byte("Called testCertificate "+uname))
}

4.7 调用另外的链上代码

InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response

在自己的链上代码中调用别人已经部署好的链上代码。

在本地使用相同的交易上下文调用指定链码 的invoke()方法,在链码中调用链码不会产生新的交易消息。

如果被调用的链码在同一个通道,那么它只是简单地将被调用链码的 读写集添加到被调用交易中。

如果被调用的链码处于不同的通道,那么只会返回响应结果,在被调用 链码中的PutState调用不会影响账本的状态。

说明

名称

类型

函数名

InvokeChaincode

 

传入值

chaincodeName

string

传入值

args

[][]byte

传入值

channel(要调用的链码所在的通道名称)

string

返回值

 

pb.Response

 

比如官方提供的example02,要在代码中去实现a->b的转账,实现如下:

func (t *SimpleChaincode) testInvokeChainCode(stub shim.ChaincodeStubInterface, args []string) pb.Response{
   trans:=[][]byte{[]byte("invoke"),[]byte("a"),[]byte("b"),[]byte("11")}
   response:= stub.InvokeChaincode("mycc",trans,"mychannel")
   fmt.Println(response.Message)
   return shim.Success([]byte( response.Message))
}

4.8获得提案对象Proposal属性

4.8.1 获得签名的提案

GetSignedProposal() (*pb.SignedProposal, error)

从客户端发现背书节点的Transaction或者Query都是一个提案,GetSignedProposal获得当前的提案对象包括客户端对这个提案的签名。提案的内容如果直接打印出来就像是乱码,其内包含了提案Header,Payload和Extension,里面更包含了复杂的结构,这里不讲,以后可以写一篇博客专门研究提案对象。

4.8.2获得Transient对象

GetTransient() (map[string][]byte, error)

Transient是在提案中Payload对象中的一个属性,也就是ChaincodeProposalPayload.TransientMap

4.8.3获得交易时间戳

GetTxTimestamp() (*timestamp.Timestamp, error)

交易时间戳也是在提案对象中获取的,提案对象的Header部分,也就是proposal.Header.ChannelHeader.Timestamp

 

4.8.4 获得Binding对象

GetBinding() ([]byte, error)

这个Binding对象也是从提案对象中提取并组合出来的,其中包含proposal.Header中的SignatureHeader.Nonce,SignatureHeader.Creator和ChannelHeader.Epoch。

2.9 事件设置

SetEvent(name string, payload []byte) error

当ChainCode提交完毕,会通过Event的方式通知Client。而通知的内容可以通过SetEvent设置。

func (t *SimpleChaincode) testEvent(stub shim.ChaincodeStubInterface, args []string) pb.Response{
   tosend := "Event send data is here!"
   err := stub.SetEvent("evtsender", []byte(tosend))
   if err != nil {
      return shim.Error(err.Error())
   }
   return shim.Success(nil)
}

 

4.9其他

4.9.1 设置指定键的背书策略

GetStateValidationParameter(key string) ([]byte, error)

设置key的背书策略。

 

2.9.2 获取指定键的背书策略

GetStateValidationParameter(key string) ([]byte, error)

获取key的背书策略

Hyperledger Fabric 实战教程:企业级区块链应用开发指南 本文从环境搭建、链码开发、网络部署到客户端应用开发,全面介绍了 Hyperledger Fabric 的开发流程。通过实践,您可以深入理解 Fabric 的架构和工作机制,为构建企业级区块链应用打下坚实基础。 阅读详情

相关推荐

Hyperledger系列(十三)开发Chaincode

Chaincode简介chaincode通常处理由网络成员赞同的业务逻辑,因此它类似于“智能合约”。 可以调用chaincode来更新或查询提案交易中的ledger。 如果有适当的许可,chaincode可以调用另一个chaincode,以访问其状态,无论是在同一个Channel还是在不同的Channel中。 请注意,如果被调用的chaincode与调用chaincode位于不同的通道上,则只允许...

maixia24的专栏 2815

Hyperledger Fabric的使用及开发

Hyperledger Fabric是Linux基金会发起的一种跨行业的区块链技术,目前在多家大型公司有着应用,这里就不多做HF本身的介绍了,有兴趣可关注其官网。

Arwind的专栏 1415

在 hyperledger fabric 环境对Validating Peers布署 chaincode (智能合约)

在开发 hyperledger App 时为了要 access 分类帐的 block 必须使用 chaincode, 也就是 App上层传来的 data 将透过 chaincode 传至 block, 所以user 在写 chaincode时,先要定义 App上层 (for NODEJS) 所传来的参数及传回值; user 在写的chaincode 时是根据系统所提供 interface 将 data读出 or 写入

chenjaulin的博客 6320

Hyperledger Fabric 复合键使用

Hyperledger Fabric 的复合键是基于多个列组合成一个复合键,并基于复合键存数据,基于复合键或部分列快速取数据。复合键将会使用复合键的类型名及多个列数据、"\u0000"生成实际使用的Key。 示例: CreateCompositeKey("id~version~min~sub", []string{"1","1","3","1"}) 类型名:id~version~min~su...

逃命的影子的博客 3165

Hyperledger Fabric 1.0 安装和使用

注意:代码路径已更新,可以直接参考 https://github.com/yeasy/docker-compose-files/tree/master/hyperledger_fabric/。Hyperledger Fabric 1.0 版本整体 重新设计了架构,预计将于今年 3 月份发布。目前已经进入了 alpha 阶段,可以进行功能性验证。本文将介绍如何快速启动一个 Fabric 1.0 的网...

yeasy的专栏 2万+

通过Java Chaincode实例学习交易系统中基于Hyperledger Fabric帐户的钱包模型

通过Java Chaincode实例学习交易系统中基于Hyperledger Fabric帐户的钱包模型 这是Hyperledger Fabric Java Chaincode的教程。还有Go和NodeJS Chaincodes,我们将来可能会讨论它们。此外,我采用基于帐户的钱包模型作为示例,我们将使用Hyperledger Fabric构建你的第一个网络(BYFN,build your firs...

mongo_node的专栏 1618

Hyperledger Fabric Java Chaincode 开发指南

Hyperledger Fabric Java Chaincode 开发指南 项目介绍 Hyperledger Fabric 是一个企业级的开源区块链框架,用于构建去中心化的、可扩展的、高度安全的分布式账本解决方案。hyperledger/fabric-chaincode-java 仓库是专门针对Fabric平台开发Java链码(Chaincode)的库。它提供了丰富的API接口,使得Java开...

gitblog_00215的博客 1059

超级账本HyperLedger:Fabric的Chaincode(智能合约、链码)开发、使用演示

作者: 李佶澳   转载请保留:原文地址   发布时间:2018/07/17 10:20:00 说明 Example-1:demo 合约安装&单合约调用 获取合约代码 安装合约&初始化 合约直接调用 并发或快速修改数据时需要注意的问题 合约链式调用 参考 说明 这是网易云课堂“IT技术快速入门学院”使用的素材。 这里演示合约的用法,合约...

IT技术快速入门学院的博客 6301

Hyperledger Fabric Chaincode Node 使用指南

Hyperledger Fabric Chaincode Node 使用指南 1. 项目的目录结构及介绍 Hyperledger Fabric Chaincode Node 项目的目录结构如下: fabric-chaincode-node/ ├── bin ├── docs ├── examples ├── lib ├── node_modules ├── scripts ├── test ├──...

gitblog_00941的博客 487

Hyperledger Fabric 2.0 chaincode lifecycle

bin/configtxgen -profile SampleDevModeSolo -channelID sys-channel -outputBlock ./channel-artifacts/genesis.block bin/configtxgen -profile SampleSingleMSPChannel -outputCreateChannelTx ./channel-artif...

HeYuanxun 的专栏 2018

Hyperledger Fabric 1.0 实战学习(三) chaincode go语言编写

   在Fabric的环境搭建后,就可以进行Fabric的开发工作。Fabric的开发主要分成两块,chaincode开发和基于SDK客户端应用开发。本章先讲chaincode的开发。Fabric的链上代码支持node,Java或者Go语言进行开发,因为Fabric本身是Go开发的,所以建议还是用Go进行chaincode的开发。Fabric中使用了系统包shim包,shim包主要负责和客户端进行...

lilindawan的博客 2793

使用Java开发Fabric智能合约Chaincode

场景:之前公司使用的是Fabric1.4,智能合约使用的是go语言开发的。现在为了方便接入到Bass平台,需要切换fabric的java SDK,并且智能合约也使用java开发。 1、pom文件 引入pom依赖: <dependency> <groupId>org.hyperledger.fabric-chaincode-java</groupId&g...

DamonREN的博客 8522

Hyperledger Fabric的智能合约开发:Go语言的最佳实践

在 Hyperledger Fabric 中,智能合约(链码)负责管理账本状态和执行交易。它定义了区块链网络中资产(如数字货币、商品、合同等)的状态变更。查询:查询账本上的现有数据。交易处理:修改账本数据,执行业务逻辑。验证:验证交易是否合法,确保数据一致性。智能合约在 Fabric 网络中以链码的形式存在。链码可以被多个节点执行,通过合约的接口与账本数据交互。import ("fmt"// SmartContract 定义链码结构// Asset 结构定义资产。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 898

Hyperledger Fabric Chaincode智能合约

前言 之前Hyperledger Fabric 1.1区块链的环境搭建完成了,接下来要为项目开发智能合约。那么先编写一份简单的智能合约吧。 什么是chaincode chaincode代码通常处理由网络成员同意的业务逻辑,因此它相当于“智能合约”。可以调用chaincode代码来更新或查询提案交易中的分类帐。考虑到适当的许可,chaincode代码可以调用另一个chaincode代码,无论是...

卿酒酒丶的博客 5867

避坑指南:RK3588视频编码与SRT推流实战中,我遇到的5个典型问题及解决方案

本文深度解析RK3588平台视频编码与SRT推流实战中的五个典型问题,包括MIPI摄像头内存对齐、多线程数据传递、FFmpeg时间戳设置、SRT连接参数调优及系统资源监控。提供具体解决方案和优化技巧,帮助开发者高效实现实时视频网络传输。

weixin_28718793的博客 324

UFS 3.1协议分析(第五章) -- UFS协议栈

ContentsUFS顶层架构应用层UFS命令集UFS 设备管理器UFS任务管理器传输层互连层 UFS顶层架构     UFS基于SCSI SAM架构模型定义了一个完整的协议栈,从上到下依次为应用层、传输层、数据链路层、物理层。UFS使用MIPI联盟的UniPro作为数据链路层和MIPI的M-PHY作为物理层,两者合起来称之为互连层(UFS InterConnect Layer) 应用层     应用层包括UFS命令集、设备管

Frank_sample的专栏 7371

基于Hyperledger Fabric开发一个食品溯源项目(一)

最近接触了Hyperledger Fabric,官网给的app并没有界面,不过有一个单页版的项目,在此基础上做出了一个简易app github项目地址 功能: 发布食品 添加配料信息 中转食品 查询食品信息 查询配料信息 查询中转信息 首页 查询页面 发布信息页面 动态图画 配置项目过程中有任何问题,欢迎提问...

eye_water的博客 1万+

嵌入式Linux网络调试:YT8531/YT8521 PHY驱动移植与设备树配置避坑指南

本文深入解析嵌入式Linux系统中YT8531/YT8521 PHY驱动移植与设备树配置的关键技术,涵盖内核驱动适配、RGMII接口时序调整及常见问题排查。针对Motorcomm千兆以太网PHY芯片,提供详细的设备树配置示例和调试技巧,帮助开发者规避典型设计陷阱,确保网络功能稳定运行。

weixin_42525632的博客 673

Hyperledger Fabric智能合约开发实战:Chaincode容器化部署与gRPC通信原理

Hyperledger Fabric是一个开源的企业级区块链平台,支持智能合约(Chaincode)的开发与部署。Chaincode作为Fabric的核心组件,运行在隔离的容器环境中,并通过gRPC协议与Peer节点通信,确保交易的安全性和可靠性。本文将详细介绍Chaincode的容器化部署流程及gRPC通信原理,帮助开发者快速掌握智能合约开发的关键技术。 ## 一、Chaincode容器化部署

gitblog_00077的博客 766

Open3D 计算点云配准的旋转和平移误差

通过计算旋转误差和平移误差来量化配准结果与真实变换之间的偏差。

点云侠的博客 251

YOLOv8改进 | Conv篇:基于FasterBlock与C2f结构的二次创新,参数量下降70万【附保姆级代码】

通过引入FasterBlock二次创新C2f结构,我们成功地对YOLOv8模型进行了优化,显著降低了其参数量,并提升了推理速度,而精度保持不变甚至有所提升。该模型在多个实际应用场景中展现出了优异的性能,尤其是在嵌入式设备、移动端和自动驾驶等领域,具有广泛的应用潜力。未来的研究将进一步优化模型结构,探索更多的应用场景,为目标检测技术的发展做出贡献。

一键难忘的博客 3215

hyperledger fabric chaincode 教程二

# 下面将自己写好的chaincode部署并且实例化到fabric: ## 首先把写好的chaincode copy 到 cli ``` 命令参考:docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH docker cp /chaincode/bdata/ 3a113b6c0ecf:/opt/gopath/src/github.com

自由的大月 1798

Vue - 萤石云监控 ezuikit 视频实例销毁方案,解决使用stop方法无法销毁EZUIKit实例或销毁后依然占用内存并且监控画面依然有声音问题(解决页面多个监控摄像头画面同时播放,翻页或关闭页

vue2,vue3,萤石,监控摄像头,萤石云销毁视频实例,退出页面销毁,stop销毁原视频流,占用内存怎么办,销毁后视频依旧在后台播放有声音,销毁视频播放器,页面上有多个视频画面怎么销毁某一个,stop方法不生效怎么办,浏览器非常卡,dom销毁,ezuikit-js萤石云播放器Vue中使用beforeDestory销毁播放器实例,调用萤石云ezuikit-js的视频对象销毁,vue使用萤石云监控视频录像回放,不销毁实例会出现离开页面后依旧有监控声音并且占内存问题,不好使,页面崩了,崩溃,视频监控太多,没有用

🏆 前端领域优质创作者 1万+

hyperledger fabric chaincode 开发

chaincode是由go语言写的,实现了定义的接口。其他语言例如JAVA也是支持的。通过application的transaction,chaincode可以初始化并管理Ledger状态。 本文基于一个用于在Ledger上创建资产(键值对)的简单案例来讲述如何在fabric开发智能合约代码 1.1 首选需要确定Go的环境被安装以及被合适的配置。 为了简单起见,我们使用以下命令: mkdir ...

六神的博客 661

华为OD机试双机位C卷:采购订单 (Py/Java/C/C++/Js/Go)

华为OD机试双机位C卷 采购订单,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,并提供在线OJ模拟做题。华为OD机试真题【采购订单】

qq_45776114的博客 3534

《低功耗方法学》翻译——前言

前言

记录所学,分享知识,结识挚友 1208
上一篇: 深入理解hyperledger fabric-1.4环境搭建的详细过程
下一篇: 协程介绍和boost中的协程实现——Boost.Coroutine2
sampson MrLiang
博客等级 码龄19年 127粉丝 82原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值