长安链--智能合约的开发、编译、安装、调用、查询(二)

作者:明神特烦恼

智能合约是区块链与业务关联度最大的部分,合约的友好性、安全性、执行效率也是优秀的智能合约引擎的重要指标,长安链的支持多种语言的智能合约,包括go、rust、solidity、c++等。本节使用go语言开发智能合约,使用tinygo进行合约编译、使用go sdk 安装、调用、查询智能合约。

官方参考文档: https://docs.chainmaker.org.cn/dev/%E6%99%BA%E8%83%BD%E5%90%88%E7%BA%A6.html

1.开发智能合约

1)合约模板

    学习智能合约的开发,通常需要有Demo来学习API的使用方式,项目组织方式。在长安链学习过程中也是如此,所以第一步获取合约模块。
1.1)拉取镜像:docker pull chainmakerofficial/chainmaker-go-contract:1.1.1
长安链为我们提供合约开发的镜像,内部包含合约模板。

1.2)启动并进入容器: docker run -it --name chainmaker-go-contract -v ${PWD}:/home chainmakerofficial/chainmaker-go-contract:1.1.1 bash
启动chainmaker-go-contract容器并进入,同时将当前目录挂载到容器的 /home目录下

1.3) 解压并分析合约模板
cp /home
tar xzvf contract_go_template.tar.gz

  • 目录结构:
    其中业务逻辑在main.go中,//export 注释的方法被编译器识别,用于外部访问。
    image.png
  • 合约逻辑
    save方法支持传入三个参数file_hashfile_nametime,以file_hash 为索引存入区块链世界状态。
    findByFileHash方法支持传入一个参数file_hash,以file_hash为检索条件进行世界状态检索并返回。
  • 合约逻辑可任意修改,只要后续调用指定export的方法名即可
2)编译合约

按照官方参考文档方式 在chainmaker-go-contract容器中执行./build.sh
生成main.wasm文件

3)安装、调用、查询合约
  1. 下载go sdk代码

git clone --recursive https://git.chainmaker.org.cn/chainmaker/chainmaker-sdk-go.git

  1. 拷贝crypto-config文件

rm -rf chainmaker-sdk-go/testdata/crypto-config
cp -r chainmaker-go/build/crypto-config chainmaker-sdk-go/testdata/

  1. 编写测试用例
    可基于sdk_user_contract_claim_test.go文件进行修改。
    1)创建文件hash_test.go

package chainmaker_sdk_go

import (
    "chainmaker.org/chainmaker-go/common/random/uuid"
    "chainmaker.org/chainmaker-sdk-go/pb/protogo/common"
    "fmt"
    "github.com/stretchr/testify/require"
    "testing"
    "time"
)

var (
    hashContractName = "myhash001"
    hashVersion      = "1.0.0"
    hashByteCodePath = "./testdata/hash-cc/main.wasm"
)

func TestUserContractHash(t *testing.T) {
    fmt.Println("====================== create client ======================")
    client, err := createClientWithCertBytes()
    require.Nil(t, err)

    fmt.Println("====================== create admin1 ======================")
    admin1, err := createAdmin(orgId1)
    require.Nil(t, err)
    fmt.Println("====================== create admin2 ======================")
    admin2, err := createAdmin(orgId2)
    require.Nil(t, err)
    fmt.Println("====================== create admin3 ======================")
    admin3, err := createAdmin(orgId3)
    require.Nil(t, err)
    fmt.Println("====================== create admin4 ======================")
    admin4, err := createAdmin(orgId4)
    require.Nil(t, err)

    fmt.Println("====================== 创建合约 ======================")
    testUserContractHashCreate(t, client, admin1, admin2, admin3, admin4, true, true)

    fmt.Println("====================== 调用合约 ======================")
    fileHash, err := testUserContractHashInvoke(client, "save", true)
    require.Nil(t, err)

    fmt.Println("====================== 执行合约查询接口 ======================")
    //txId := "1cbdbe6106cc4132b464185ea8275d0a53c0261b7b1a470fb0c3f10bd4a57ba6"
    //fileHash = txId[len(txId)/2:]
    params := map[string]string{
        "file_hash": fileHash,
    }
    testUserContractHashQuery(t, client, "find_by_file_hash", params)
}

func testUserContractHashCreate(t *testing.T, client *ChainClient,
    admin1, admin2, admin3, admin4 *ChainClient, withSyncResult bool, isIgnoreSameContract bool) {

    resp, err := createUserContract(client, admin1, admin2, admin3, admin4,
        hashContractName, hashVersion, hashByteCodePath, common.RuntimeType_GASM, []*common.KeyValuePair{}, withSyncResult)
    if !isIgnoreSameContract {
        require.Nil(t, err)
    }

    fmt.Printf("CREATE claim contract resp: %+v\n", resp)
}

func testUserContractHashInvoke(client *ChainClient,
    method string, withSyncResult bool) (string, error) {

    //curTime := fmt.Sprintf("%d", CurrentTimeMillisSeconds())
    curTime := time.Now().Format("2006-01-02 15:04:05")

    fileHash := uuid.GetUUID()
    params := map[string]string{
        "time":      "123",
        "file_hash": fileHash,
        "file_name": fmt.Sprintf("file_%s", curTime),
    }

    err := invokeUserContract(client, hashContractName, method, "", params, withSyncResult)
    //err := invokeUserContractStepByStep(client, claimContractName, method, "", params, withSyncResult)
    if err != nil {
        return "", err
    }

    return fileHash, nil
}

func testUserContractHashQuery(t *testing.T, client *ChainClient,
    method string, params map[string]string) {
    resp, err := client.QueryContract(hashContractName, method, params, -1)
    require.Nil(t, err)
    fmt.Printf("QUERY claim contract resp: %+v\n", resp)
}



2)执行TestUserContractHash Test方法

2.扩展

    这里使用的是默认配置文件,如果需要改变端口、连接数、TLS使能等等,需要修改chainmaker-sdk-go/testdata/sdk_config.yml

你可能感兴趣的:(长安链--智能合约的开发、编译、安装、调用、查询(二))