云服务器内容精选

  • 开发环境准备 请根据自身业务选择Go或Java开发环境。推荐使用CloudIDE(支持在线、快速地构建链代码开发环境)。 Go开发环境准备: 安装Go开发环境。安装包下载地址为:https://go.dev/dl/。(请选择1.9.2之后的版本) 各个系统对应的包名(以1.11.12版本为例): 操作系统 包名 Windows go1.11.12.windows-amd64.msi Linux go1.11.12.linux-amd64.tar.gz Windows下您可以使用.msi后缀的安装包来安装。默认情况下.msi文件会安装在“C:\Go”目录下。您可以将“C:\Go\bin”目录添加到Path环境变量中。添加后您需要重启命令窗口才能生效。 Linux下,您需要将下载的二进制包解压至/usr/local目录。将/usr/local/go/bin目录添加至Path环境变量: export PATH=$PATH:/usr/local/go/bin 安装完go语言后可以通过命令go version查看版本信息,以及通过go env命令来查看相关路径配置。 安装Go编辑器。编辑器可自行选择,推荐使用Goland:https://www.jetbrains.com/go/download。 Java开发环境准备: 仅适用于Fabric架构版本的 区块链 实例。 安装Java开发环境。下载JDK并安装(建议选择最新版本):https://www.oracle.com/technetwork/java/javase/downloads/index.html。 各个系统对应的包名(以15.0.2版本为例): 操作系统 包名 Windows jdk-15.0.2_windows-x64_bin.exe Linux jdk-15.0.2_linux-x64_bin.tar.gz Windows下您可以使用 .exe后缀的安装包来安装。 Linux下,您需要将下载的二进制包解压至/usr/local目录。 export PATH=$PATH:/usr/local/go/bin 配置环境变量(若无则新建): JAVA_HOME为jdk安装目录如“C:\Program Files (x86)\Java\jdk1.8.0_91”或“/usr/java/jdk1.8.0_91”(以下均略去双引号); CLASSPATH为“.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar; ”; 在Path中新增两条“%JAVA_HOME%\bin”和“%JAVA_HOME%\jre\bin”。 安装完jdk后,可以通过命令java -version查看版本信息。 安装Java编辑器。编辑器可自行选择,推荐使用IntelliJ IDEA。
  • 下载源码包 下载Fabric源码包作为三方库。仅适用于Fabric架构版本的区块链实例。 请根据实际需求,选择下载对应版本的Fabric源码包: https://github.com/hyperledger/fabric/tree/release-2.2 Fabric源码包选择和创建的区块链实例版本对应,即如果创建区块链实例时,Hyperledger Fabric增强版内核是v2.2(4.X.X版本),则Fabric源码包对应选择2.2版本。
  • 链代码接口 链代码启动必须通过调用shim包中的start方法。实际开发中, 您需要自行定义一个类,来继承ChaincodeBase。以下为继承时必须重写的方法: public class SimpleChaincodeSimple extends ChaincodeBase { @Override public Response init(ChaincodeStub stub) { } @Override public Response invoke(ChaincodeStub stub) { } } init方法:在链代码实例化或升级时被调用,完成初始化数据的工作。 Invoke方法:更新或查询账本数据状态时被调用, 需要在此方法中实现响应调用或查询的业务逻辑。
  • 链代码结构 Java语言的链代码结构如下: package main // 引入必要的包,系统自动操作,只要在maven或gradle中配置即可 import org.hyperledger.fabric.shim.ChaincodeBase; import org.hyperledger.fabric.shim.ChaincodeStub; public class SimpleChaincodeSimple extends ChaincodeBase { @Override public Response init(ChaincodeStub stub) { // 在该方法中实现链代码初始化或升级时的处理逻辑 // 编写时可灵活使用stub中的API } @Override public Response invoke(ChaincodeStub stub) { // 在该方法中实现链代码运行中被调用或查询时的处理逻辑 // 编写时可灵活使用stub中的API } //主函数,需要调用shim.Start()方法 public static void main(String[] args) { new SimpleChaincode().start(args); } }
  • 链代码示例(1.4风格) Fabric架构版本的区块链实例: 如下是一个账户转账的链代码示例(1.4风格)仅供安装实例化,若您需要调测请参考Fabric官方示例中的链代码。 package main import ( "fmt" "strconv" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" )type SimpleChaincode struct {}// 初始化数据状态,实例化/升级链代码时被自动调用func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {// println函数的输出信息会出现在链代码容器的日志中fmt.Println("ex02 Init")// 获取用户传递给调用链代码的所需参数_, args := stub.GetFunctionAndParameters()var A, B string // 两个账户var Aval, Bval int // 两个账户的余额var err error// 检查合法性, 检查参数数量是否为4个, 如果不是, 则返回错误信息if len(args) != 4 {return shim.Error("Incorrect number of arguments. Expecting 4")}A = args[0] // 账户A用户名Aval, err = strconv.Atoi(args[1]) // 账户A余额if err != nil {return shim.Error("Expecting integer value for asset holding")}B = args[2] // 账户B用户名Bval, err = strconv.Atoi(args[3]) // 账户B余额if err != nil {return shim.Error("Expecting integer value for asset holding")}fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)// 将账户A的状态写入账本中err = stub.PutState(A, []byte(strconv.Itoa(Aval)))if err != nil {return shim.Error(err.Error())}// 将账户B的状态写入账本中err = stub.PutState(B, []byte(strconv.Itoa(Bval)))if err != nil {return shim.Error(err.Error())}return shim.Success(nil)}// 对账本数据进行操作时(query, invoke)被自动调用func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {fmt.Println("ex02 Invoke")// 获取用户传递给调用链代码的函数名称及参数function, args := stub.GetFunctionAndParameters()// 对获取到的函数名称进行判断if function == "invoke" {// 调用 invoke 函数实现转账操作return t.invoke(stub, args)} else if function == "delete" {// 调用 delete 函数实现账户注销return t.delete(stub, args)} else if function == "query" {// 调用 query 实现账户查询操作return t.query(stub, args)}// 传递的函数名出错,返回 shim.Error()return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")}// 账户间转钱func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {var A, B string // 账户A和Bvar Aval, Bval int // 账户余额var X int // 转账金额var err errorif len(args) != 3 {return shim.Error("Incorrect number of arguments. Expecting 3")}A = args[0] // 账户A用户名B = args[1] // 账户B用户名// 从账本中获取A的余额Avalbytes, err := stub.GetState(A)if err != nil {return shim.Error("Failed to get state")}if Avalbytes == nil {return shim.Error("Entity not found")}Aval, _ = strconv.Atoi(string(Avalbytes))// 从账本中获取B的余额Bvalbytes, err := stub.GetState(B)if err != nil {return shim.Error("Failed to get state")}if Bvalbytes == nil {return shim.Error("Entity not found")}Bval, _ = strconv.Atoi(string(Bvalbytes))// X为转账金额X, err = strconv.Atoi(args[2])if err != nil {return shim.Error("Invalid transaction amount, expecting a integer value")}// 转账Aval = Aval - XBval = Bval + Xfmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)// 更新转账后账本中A余额err = stub.PutState(A, []byte(strconv.Itoa(Aval)))if err != nil {return shim.Error(err.Error())}// 更新转账后账本中B余额err = stub.PutState(B, []byte(strconv.Itoa(Bval)))if err != nil {return shim.Error(err.Error())}return shim.Success(nil)}// 账户注销func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {if len(args) != 1 {return shim.Error("Incorrect number of arguments. Expecting 1")}A := args[0] // 账户用户名// 从账本中删除该账户状态err := stub.DelState(A)if err != nil {return shim.Error("Failed to delete state")}return shim.Success(nil)}// 账户查询func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {var A stringvar err errorif len(args) != 1 {return shim.Error("Incorrect number of arguments. Expecting name of the person to query")}A = args[0] // 账户用户名// 从账本中获取该账户余额Avalbytes, err := stub.GetState(A)if err != nil {jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"return shim.Error(jsonResp)}if Avalbytes == nil {jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"return shim.Error(jsonResp)}jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"fmt.Printf("Query Response:%s\n", jsonResp)// 返回转账金额return shim.Success(Avalbytes)}func main() {err := shim.Start(new(SimpleChaincode))if err != nil {fmt.Printf("Error starting Simple chaincode: %s", err)}} 父主题: Go语言链代码开发
  • 开发跨链智能合约 开发跨链智能合约前,需要先了解跨链操作的原理。在跨链资产交换场景中,在减少某个链上资产后,需要相应的在对应链上增加资产,这种转移使各条链的资产发生了变化。因此,跨链操作需要保证整个跨链交易结束后不同链之间的全局事务保持一致性,即同时记账,或同时不记账。 可信跨链 服务基于分布式事务两阶段提交的思想设计了一套能确保全局事务保持一致性的跨链资产交换流程。若您的跨链业务不涉及跨链资产交换,则无需定制编写跨链智能合约,否则需设置跨链资产数据锁与跨链智能合约方法。 下面用一个完整的跨链资产交换智能合约为样例说明跨链智能合约开发流程,该样例可完成链A上的A账户与链B上的B账户之间的资产转账。完整智能合约示例获取方法:登录可信跨链服务管理控制台,在“总览”页面的跨链链代码下载用于演示的业务链代码tcsexample.zip。 跨链资产数据锁定义 跨链智能合约方法定义 跨链智能合约方法示例 父主题: 跨链链代码开发(Hyperledger Fabric)