区块链学习2-合约开发

news2024/11/26 18:34:53

概述

智能合约本质上是运行在某种环境(例如虚拟机)中的一段代码逻辑。

长安链的智能合约是运行在长安链上的一组“动态代码”,类似于Fabric的chaincode,Fabric的智能合约称为链码(chaincode),分为系统链码和用户链码。长安链的合约分为用户合约和系统合约。

长安链·ChainMaker目前已经支持使用C++、Go、Rust、Solidity进行智能合约开发,这里介绍goland合约的开发参考。
 

环境依赖

长安链运行docker-go合约的环境依赖如下:

名称版本描述是否必须
docker18+独立运行容器
7zip16+压缩、解压合约文件

2.2.0版本的合约开发:

编写测试合约:

2.2.0的sdk 不支持 go mod 的形式 ,需要下载sdk 源码,参考其中的“demo"文件夹下的示例合约,

Files · v2.2.0 · chainmaker / contract-sdk-go · ChainMaker

以及开源文档,“5.7.3.1. 示例代码说明”

5. 智能合约开发 — chainmaker-docs v2.2.0 documentation

方法说明:

shim/interfaces.go · v2.2.0 · chainmaker / contract-sdk-go · ChainMaker

以下是根据官网编写的一份示例合约

/*
Copyright (C) BABEC. All rights reserved.
Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.

SPDX-License-Identifier: Apache-2.0
*/

package demo

import (
	"crypto/rand"
	"encoding/json"
	"log"
	"math/big"
	"strconv"
	"fmt" // print


	"chainmaker.org/chainmaker/contract-sdk-go/v2/pb/protogo"
	"chainmaker.org/chainmaker/contract-sdk-go/v2/shim"
)

type FactContract struct {
}

// 存证对象
type Fact struct {
	FileHash string `json:"FileHash"`
	FileName string `json:"FileName"`
	Time     int32  `json:"time"`
}

// 新建存证对象
func NewFact(FileHash string, FileName string, time int32) *Fact {
	fact := &Fact{
		FileHash: FileHash,
		FileName: FileName,
		Time:     time,
	}
	return fact
}

func (f *FactContract) InitContract(stub shim.CMStubInterface) protogo.Response {

	return shim.Success([]byte("Init Success"))

}

func (f *FactContract) InvokeContract(stub shim.CMStubInterface) protogo.Response {

	// 获取参数
	method := string(stub.GetArgs()["method"])

	switch method {
	case "save":
		return f.save(stub)
	case "findByFileHash":
		return f.findByFileHash(stub)
	case "random":
		return f.random()
	default:
		return shim.Error("invalid method")
	}

}
func (f *FactContract) random() protogo.Response {
	// 随机数逻辑
	number, _ := rand.Int(rand.Reader, big.NewInt(10000000000))
	fmt.Println(number)
	number_str := fmt.Sprint(number)
	//number_str := strconv.Itoa(number)
	// 返回结果
	return shim.Success([]byte(number_str))
}

func (f *FactContract) save(stub shim.CMStubInterface) protogo.Response {
	params := stub.GetArgs()

	// 获取参数
	fileHash := string(params["file_hash"])
	fileName := string(params["file_name"])
	timeStr := string(params["time"])
	time, err := strconv.Atoi(timeStr)
	if err != nil {
		msg := "time is [" + timeStr + "] not int"
		stub.Log(msg)
		return shim.Error(msg)
	}
	// 构建结构体
	fact := NewFact(fileHash, fileName, int32(time))
	// 序列化
	factBytes, _ := json.Marshal(fact)
	// 发送事件
	stub.EmitEvent("topic_vx", []string{fact.FileHash, fact.FileName})
	// 存储数据
	err = stub.PutStateByte("fact_bytes", fact.FileHash, factBytes)
	if err != nil {
		return shim.Error("fail to save fact bytes")
	}
	// 记录日志
	stub.Log("[save] FileHash=" + fact.FileHash)
	stub.Log("[save] FileName=" + fact.FileName)

	// 返回结果
	return shim.Success([]byte(fact.FileName + fact.FileHash))

}

func (f *FactContract) findByFileHash(stub shim.CMStubInterface) protogo.Response {
	// 获取参数
	FileHash := string(stub.GetArgs()["file_hash"])

	// 查询结果
	result, err := stub.GetStateByte("fact_bytes", FileHash)
	if err != nil {
		return shim.Error("failed to call get_state")
	}

	// 反序列化
	var fact Fact
	_ = json.Unmarshal(result, &fact)

	// 记录日志
	stub.Log("[find_by_file_hash] FileHash=" + fact.FileHash)
	stub.Log("[find_by_file_hash] FileName=" + fact.FileName)

	// 返回结果
	return shim.Success(result)
}

func main() {

	err := shim.Start(new(FactContract))
	if err != nil {
		log.Fatal(err)
	}
}

编译合约

编译几个必要条件:

  1.  需要在linux环境下编译,如果在mac平台编译,需要把build.sh里面的go build main.go改成CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go

  2. 代码入口包名必须为main 见步骤1,2

  3. main的固定写法:

    package main
    // sdk代码中,有且仅有一个main()方法
    func main() {  
       // main()方法中,下面的代码为必须代码,不建议修改main()方法当中的代码
       // 其中,TestContract为用户实现合约的具体名称
    	err := shim.Start(new(TestContract))
    	if err != nil {
    		log.Fatal(err)
    	}
    }

        3. 必须实现以下几个方法:

// 合约结构体,合约名称需要写入main()方法当中
type TestContract struct {
}

// 合约必须实现下面两个方法:
// InitContract(stub shim.CMStubInterface) protogo.Response
// InvokeContract(stub shim.CMStubInterface) protogo.Response
// 用于合约的部署和升级
// @param stub: 合约接口
// @return: 	合约返回结果,包括Success和Error
func (t *TestContract) InitContract(stub shim.CMStubInterface) protogo.Response {
	return shim.Success([]byte("Init Success"))
}
// 用于合约的调用
// @param stub: 合约接口
// @return: 	合约返回结果,包括Success和Error
func (t *TestContract) InvokeContract(stub shim.CMStubInterface) protogo.Response {
	return shim.Success([]byte("Invoke Success"))
}

编译合约的具体操作步骤:

1. 将contract-sdk-go/main.go的内容替换成自己编写的合约:

2. 将自己编写的合约中package 改为main

3. 运行./build.sh 输入合约名。

 2.3.0版本的合约开发:

2.3.0版本的Golang合约SDK支持通过go.mod的方式引用,可直接使用go get引用

1. 创建一个project:

 2. 在terminal里执行

go get chainmaker.org/chainmaker/contract-sdk-go/v2@v2.3.2

3. 按照官方给出的示例编写合约。
2. 使用Golang进行智能合约开发 — chainmaker-docs v2.3.0 documentation

4. 在当前目录 下运行:
go build -ldflags="-s -w" -o contract_save.go

生成结果如下:

├── contract_save 生成的二进制文件

├── contract_save.7z 打包好的压缩文件,用于在链上创建合约

└── contract_save.go 源文件

部署合约到区块链中

使用长安链提供的cmc工具部署:
示例脚本:

# pk模式
./cmc client contract user create \
--contract-name=save_random \
--runtime-type=DOCKER_GO \
--byte-code-path=./testdata/docker-go-demo/save_random.7z \
--version=1.0 \
--sdk-conf-path=./testdata/sdk_config_pk.yml \
--admin-key-file-paths=./testdata/crypto-config/node1/admin/admin1/admin1.key \
--sync-result=true \
--params="{}"
# cert模式
./cmc client contract user create \
--contract-name=save_random \
--runtime-type=DOCKER_GO \
--byte-code-path=./testdata/docker-go-demo/save_random.7z \
--version=1.0 \
--sdk-conf-path=./testdata/sdk_config.yml \
--admin-key-file-paths=./testdata/crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.tls.key,./testdata/crypto-config/wx-org2.chainmaker.org/user/admin1/admin1.tls.key,./testdata/crypto-config/wx-org3.chainmaker.org/user/admin1/admin1.tls.key,./testdata/crypto-config/wx-org4.chainmaker.org/user/admin1/admin1.tls.key \
--admin-crt-file-paths=./testdata/crypto-config/wx-org1.chainmaker.org/user/admin1/admin1.tls.crt,./testdata/crypto-config/wx-org2.chainmaker.org/user/admin1/admin1.tls.crt,./testdata/crypto-config/wx-org3.chainmaker.org/user/admin1/admin1.tls.crt,./testdata/crypto-config/wx-org4.chainmaker.org/user/admin1/admin1.tls.crt \
--sync-result=true \
--params="{}"

使用sdk部署:chainmaker / sdk-go · ChainMaker

示例代码参考: sdk-go/examples/user_contract_claim_docker 

func testUserContractClaimCreate(client *sdk.ChainClient, withSyncResult bool, isIgnoreSameContract bool, usernames ...string) string {

	resp, err := createUserContract(client, claimContractName, claimVersion, claimByteCodePath,
		common.RuntimeType_DOCKER_GO, []*common.KeyValuePair{}, withSyncResult, usernames...)
	if err != nil {
		if !isIgnoreSameContract {
			log.Fatalln(err)
		} else {
			fmt.Printf("CREATE claim contract failed, err: %s, resp: %+v\n", err, resp)
		}
	} else {
		fmt.Printf("CREATE claim contract success, resp: %+v\n", resp)
	}

	if resp != nil {
		return resp.TxId
	}

	return ""
}

func createUserContract(client *sdk.ChainClient, contractName, version, byteCodePath string, runtime common.RuntimeType,
	kvs []*common.KeyValuePair, withSyncResult bool, usernames ...string) (*common.TxResponse, error) {

	payload, err := client.CreateContractCreatePayload(contractName, version, byteCodePath, runtime, kvs)
	if err != nil {
		return nil, err
	}

	payload = client.AttachGasLimit(payload, &common.Limit{
		GasLimit: 60000000,
	})

	//endorsers, err := examples.GetEndorsers(payload, usernames...)
	endorsers, err := examples.GetEndorsersWithAuthType(client.GetHashType(),
		client.GetAuthType(), payload, usernames...)
	if err != nil {
		return nil, err
	}

	resp, err := client.SendContractManageRequest(payload, endorsers, createContractTimeout, withSyncResult)
	if err != nil {
		return resp, err
	}

	err = examples.CheckProposalRequestResp(resp, true)
	if err != nil {
		return resp, err
	}

	return resp, nil
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/88838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

对氯间二甲苯酚在活性污泥发酵过程中重塑ARGs的机制类别

2022年8月,凌恩生物客户河海大学罗景阳教授团队在《Science of the Total Environment》期刊上发表研究论文“Para-chloro-meta-xylenol reshaped the fates of antibiotic resistance genes during sludge fermentation: Insights of cell membrane permeability, …

ChatGPT技术解构

ChatGPT的训练主要分为三个步骤,如图所示: Step1: 使用有监督学习方式,基于GPT3.5微调训练一个初始模型;训练数据约为2w~3w量级(根据InstructGPT的训练数据量级估算,参照https://arxiv.org/pdf…

【内网安全-防火墙】防火墙、协议、策略

目录 一、基础知识 1、防火墙五个域 2、协议模型 二、出入站策略 1、单个机器防火墙 2、域控的防火墙 3、安全策略 一、基础知识 1、防火墙五个域 1、Untrust(不信任域,低级安全区域): 用来定义Internet等不安全的网络,用于网络入口线的接入 ——…

沁恒 CH32V003J4M6 开发测试

一、概述 具体看图,SOP8价格在0.6R,TSSOP20价格在0.7R,优势太大了 二、开发准备 通过原厂可以拿到样片,目前我拿到这颗是SOP8,另外官方淘宝可以买到TSSOP20的测试板,也带样片购买WCHLINK,TB…

Mysql 进阶(面向面试篇)锁

全局锁、表级锁(表锁、元数据锁、意向锁(意向共享锁、意向排它锁))、行级锁(行锁(共享锁、排它锁)、间隙锁、临键锁) 表级锁(表锁(表锁分为:表共…

仅差一步!如何缩短加入购物车与成单的距离?

不知不觉,2022年已接近尾声,经历了卡塔尔世界杯、黑色星期五等跨境电商狂欢节后,不少跨境电商卖家都在开展复盘行动,为接下来的圣诞节运营计划打下扎实基础。时常关注跨境电商行业的人都知道,衡量跨境电商广告效率的关…

Python函数、类和对象、流程控制语句if-else while的讲解及演示(图文解释 附源码)

一、函数 函数是完成某个功能的代码段,可被其他代码调用,调用的代码可以将数据传递给函数,函数可将对数据的处理结果返回给调用代码。 def mysubt( a, b 0 ): # 定义一个自己的减法函数,第二个参数为默认值为0的默认参数c a -…

2023年湖北报考施工员要多少钱?甘建二告诉您

2023年湖北报考施工员要多少钱?甘建二告诉您 2023年湖北报考施工员要多少钱,甘建二告诉您 2023年武汉报考施工员要多少钱,甘建二告诉您 2023年黄冈报考施工员要多少钱,甘建二告诉您 2023年黄石报考施工员要多少钱,甘…

HBase Java API 开发:批量操作 第3关:批量导入数据至HBase

每一次只添加一个数据显然不像是大数据开发,在开发项目的时候也肯定会涉及到大量的数据操作。 使用Java进行批量数据操作,其实就是循环的在Put对象中添加数据最后在通过Table对象提交。 如何进行批量操作呢,讲到批量操作,相信大…

秋招必备!阿里产出的高并发+JVM豪华套餐送给你,绝对硬核干货

**3、设计了方案,但细节掌握不透彻:**讲不出方案要关注的技术点和可能带来的消极影响。比如读性能有瓶颈会引入缓存,但是忽视了缓存命中率、数据一致性、热点key等问题。 面对马上就要到来的双十一的秒杀环节,你是否已经有备无患…

[附源码]Node.js计算机毕业设计高校第二课堂管理系统Express

项目运行 环境配置: Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术: Express框架 Node.js Vue 等等组成,B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境:最好是Nodejs最新版,我…

数据结构为何重要(《数据结构与算法图解》by 杰伊•温格罗)

本文内容借鉴一本我非常喜欢的书——《数据结构与算法图解》。学习之余,我决定把这本书精彩的部分摘录出来与大家分享。 基础数据结构:数组 数组是计算机科学中最基本的数据结构之一。如果你用过数组,那么应该知道它就是一个含有 数据的列表…

免费U盘文件恢复,你不知道的10款u盘恢复软件

U盘是我们在工作和生活中经常使用的移动存储设备。在操作U盘时,里面重要的文件可能会因为疏忽而被删除。通过电脑回收站、备份等方法都不能恢复U盘里面的数据,我们该怎么办?其实U盘删除的文件在删除后不会被完全删除,通过u盘恢复软…

以太网 STP、RSTP、MSTP基础配置、STP生成树安全保障操作命令介绍

2.13.0 以太网 STP、RSTP、MSTP配置、生成树安全保障操作 主要参考:华为S2750, S5700, S6700 V200R005(C00&C01&C02&C03) 产品文档 《命令手册》 MSTP快速生成树STP配置RSTP配置MSTP配置生成树的安全保障操作(1)根桥保护&#xf…

jdk1.8下载与安装教程(win11)

一、JDK下载 1.首先在Oracle官网上下载jdk1.8 打开官网:https://www.oracle.com/ 2.选择Developer Services的Java 3.选择Oracle JDK 4.选择Java8 Window点击: jdk-8u351-windows-x64.exe下载 5.接受Oracle Java SE的Oracle技术网络许可协议 …

Folate-PEG-DBCO,DBCO-PEG- FA,叶酸聚乙二醇环辛炔

●中文名:叶酸聚乙二醇环辛炔,叶酸聚乙二醇二苯基环辛炔,DBCO-PEG-叶酸 ●英文名:FA-PEG-DBCO , Folate-PEG-DBCO,DBCO-PEG- FA,DBCO-PEG-Folate,DBCO-PEG- Folic acid ●外观以及…

游戏合作伙伴专题:BreederDAO 与 SuperGaming 建立 SuperCharged 合作伙伴关系

BreederDAO 很高兴地宣布与 SuperGaming 建立合作伙伴关系,SuperGaming 是一家充满激情的游戏工作室,希望通过 Tower Conquest:Metaverse Edition 进军 Web 3 行业,这是一款基于 Polygon 区块链的免费多人塔防游戏。 征服新领域 S…

产品设计学习过程中的技术和方法

在产品设计的过程中,当你心中有创意设计时,你需要写下这个创意设计,并生成一个例子标记,以便总结你以前的想法。此时,你需要设计性能。在设计性能的过程中,我们需要使用各种设计工具,这些设计工…

自定义Springboot Starter

1.创建一个父项目&#xff1a; demo 1.1 项目结构&#xff1a; 1.2 pom文件内容&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/X…

大四web前端网页制作课作业——HTML+CSS+JavaScript仿小米手机商城网站(37页)

常见网页设计作业题材有 个人、 美食、 公司、 学校、 旅游、 电商、 宠物、 电器、 茶叶、 家居、 酒店、 舞蹈、 动漫、 服装、 体育、 化妆品、 物流、 环保、 书籍、 婚纱、 游戏、 节日、 戒烟、 电影、 摄影、 文化、 家乡、 鲜花、 礼品、 汽车、 其他等网页设计题目, A…