Go语言与智能合约的交互

Go语言与智能合约的交互

实现步骤

  1. 首先要编写一份智能合约
  2. 将智能合约通过工具转化为go文件
  3. 自己编写go文件调用智能合约转化成的go文件提供的接口

具体实现

  • 编写一份智能合约

智能合约使用solidity语言写的,可以用在线的remix编辑器进行编辑。

pragma solidity >=0.4.22 <0.6.0;



contract DataStorage {

   
    bytes32 public fheAddressHash ;
    bytes32 public rsaPublicKeyHash;
    bytes32 public dataHash;
    bytes32 public modelHash;
    bytes32 public encryptedAesKeyHash;
    bytes32 public trainedResultHash;
    bytes32 public finalDistance;
    bytes32 public modelParamsHash;
   
    
    constructor() public{
        
    }
    
    function setFheAddressHash(bytes32 _fheAddressHash) payable public {
        fheAddressHash=_fheAddressHash;
        emit LogSetFheAddressHash(fheAddressHash);
    }
    
    function setModelHash(bytes32 _modelHash) payable public {
        modelHash=_modelHash;
        emit LogSetModelHash(modelHash);
    }
    
    function setRsaPublicKeyHash(bytes32 _rsaPublicKeyHash) payable public{
        rsaPublicKeyHash=_rsaPublicKeyHash;
        emit LogSetRsaPublicKeyHash(rsaPublicKeyHash);
    }
    function setDataHash(bytes32 _dataHash) payable public{
        dataHash=_dataHash;
        emit LogSetDataHash(dataHash);
    }
    
    function setEncryptedAesKeyHash(bytes32 _encryptedAesKeyHash) payable public{
        encryptedAesKeyHash=_encryptedAesKeyHash;
        emit LogEncryptedAesKeyHash(encryptedAesKeyHash);
    }
    
    function setTrainedResultHash(bytes32 _trainedResultHash) payable public{
        trainedResultHash=_trainedResultHash;
        emit LogTrainedResultHash(trainedResultHash);
    }
    
    function setFinalDistance(bytes32 _finalDistance) payable public{
        finalDistance=_finalDistance;
        emit LogSetFinalDistance(finalDistance);
    }
    
    function setModelParamsHash(bytes32 _modelParamsHash) payable public{
        modelParamsHash=_modelParamsHash;
        emit LogSetModelParamsHash(modelParamsHash);
    }
    
    event LogSetFheAddressHash(bytes32 _fheAddressHash);
    event LogSetModelHash(bytes32 _modelHash);
    event LogSetRsaPublicKeyHash(bytes32 _rsaPublicKeyHash);
    event LogSetDataHash(bytes32 _dataHash);
    event LogEncryptedAesKeyHash(bytes32 _encryptedAesKeyHash);
    event LogTrainedResultHash(bytes32 _trainedResultHash);
    event LogSetFinalDistance(bytes32 _finalDistance);
    event LogSetModelParamsHash(bytes32 _modelParamsHash);
}

remix编辑器

  • 将智能合约用工具转化为go语言:

我们用abigen将智能合约转化为go文件

abigen安装的方式如下:

go get github.com/ethereum/go-ethereum
cd $GOPATH/src/github.com/ethereum/go-ethereum/
make
make devtools

接着我们用如下命令将智能合约转化为go语言文件:

DataStorage.sol为智能合约文件,filedir为生成的文件的保存目录。

#第一行命令会生成.abi文件在filedir目录中
solcjs DataStorage.sol -o filedir --abi
#第二行命令会生成.bin文件在filedir目录中
solcjs  DataStorage.sol -o filedir --bin
#第三行命令用filedir中的.abi文件和.bin文件生成一个package 为main的名为DataStorage.go的go语言文件.该文件保存在/Users/huyifan/DAI中.
abigen --abi  DataStorage_sol_ DataStorage.abi --bin  DataStorage_sol_ DataStorage.bin --pkg main --out /Users/huyifan/DAI/ DataStorage.go
  • 自己编写go文件调用智能合约转化成的go文件提供的接口

我这里只调用了setDataHash这个智能合约函数,将字符串存进区块链智能合约中,然后再从区块链中获取我们存进去的字符串。其他的函数以此类推。

package main

import (
	"fmt"
	"log"
	"math/big"
	"strings"


	//"time"

	"github.com/ethereum/go-ethereum/accounts/abi/bind"
	"github.com/ethereum/go-ethereum/accounts/abi/bind/backends"
	"github.com/ethereum/go-ethereum/core"
	"github.com/ethereum/go-ethereum/ethclient"
	"github.com/ethereum/go-ethereum/common"
	//"github.com/oraclize/ethereum-api/oraclizeAPI.sol";
	//"github.com/ethereum/go-ethereum/crypto"
)

//本地以太坊私链的某一个账户,这里我用了coinbase对应的账户,这个账户信息在私链数据目录下的keystore目录里面
const key=`{"address":"12769c3419a7f491cf4e576e2e983e009d579076","crypto":{"cipher":"aes-128-ctr","ciphertext":"215430a18ab1132c6eaecdf966bc0d878a3be06cff5dce173d801afec5002db5","cipherparams":{"iv":"d41d87954da3dfca1f38e14111169fb8"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"d5268e70fbf8666435bf82ee53850f14486810f1944110de2aede933ae97fff1"},"mac":"a80e95fc657473f543bb989da9e8e2cde73e2b8bde52e6b05355b44a40c165ec"},"id":"5e034459-6e81-4208-9e26-c91641d20f5d","version":3}`

func main() {

	//我们要存进区块链智能合约的字符串
	dataHash := "testDataHash"

	//智能合约的在区块链上的地址
	contractAddress := "0x47d73709bf274160118f8f175695ac3616b7f08f"
	//连接本地的以太坊私链(一定要保证本地以太坊私链已经启动)
	conn, err := ethclient.Dial("http://127.0.0.1:8545")
	
	fmt.Println("connect to local geth node...", conn)
	if err != nil {
		log.Fatalf("could not connect to local node: %v", err)
	}
	//fmt.Println("get the contract object...")

	token, err := NewMain(common.HexToAddress(contractAddress), conn)
	if err != nil {
		log.Fatalf("Failed to instantiate a Token contract: %v", err)
	}
	fmt.Println("contract token======>:", token)

	//解锁对应账户
	auth, err := bind.NewTransactor(strings.NewReader(key), "abc")
	if err != nil {
		log.Fatalf("could not create auth: %v", err)
	}
	alloc := make(core.GenesisAlloc)
	alloc[auth.From] = core.GenesisAccount{Balance: big.NewInt(1337000000000)}
	sim := backends.NewSimulatedBackend(alloc, 100000000)
	// fmt.Println("token:=====>",token)


	var arr [32]byte
	for k, v := range []byte(dataHash) {
		arr[k] = byte(v)
	}

	fmt.Println(string(arr[:len(arr)]))

	//调用对应的go语言函数与以太坊私链进行交互
	fmt.Println("=========start put data=========")
	_, err = token.SetDataHash(&bind.TransactOpts{
		From:     auth.From,
		Signer:   auth.Signer,
		GasLimit: 288162,
		Value:    big.NewInt(30),
	}, arr)

	if err!=nil {
		log.Fatalf("transaction produce fail: %v", err)
	}
	//提交交易
	sim.Commit()

	

	if err != nil {
		log.Fatalf("put data to data pool err:%v", err)
	}

	fmt.Println("put data to smart contract success!")


	fmt.Println("==================================")
	fmt.Println("get data from smart contract")
	//从以太坊上获得之前存进去的值
	info, _ := token.DataHash(&bind.CallOpts{Pending: true})
	//fmt.Printf("the total data prices and desciption are: %s\n", info);
	fmt.Printf(string(info[:len(info)]))

}

结果如下所示:

以太坊产生的信息如下图所示:
以太坊对应信息

注意点:

  • 只要将想要从以太坊获得值的那个变量在智能合约中设置成public,智能合约转为go语言文件后会自动的生成相应的函数,调用那个函数就可以从以太坊中获得变量值。
  • 如果智能合约的某个函数会改变以太坊的状态(例如设置某个变量的值,更新了某个变量的值等等),那么在智能合约中这个函数就要用payable修饰,因为调用这个函数的时候必须要发起交易,待这个交易被确认后,调用的这个函数的产生的结果才生效。我们也可以从设置值的函数和获取值的函数的参数看出端倪:
    设置函数传入的参数
    获取函数传入的参数
  • 也可以事先不部署智能合约。这样的话,就需要调用DataStorage.go文件中的DeployMain函数自己手动的部署智能合约,代码修改如下:
    在这里插入图片描述
    以太坊的状态如下图所示:
    在这里插入图片描述
    这里再次提醒只要对区块链状态发生了改变的话,必须提交交易,并被验证通过才能算真正的改变了区块链.
Fabric 支持运行 Go 语言智能合约。要在 Fabric 中使用 Go 语言智能合约,你需要: 1. 在你的本地安装 Go 编程语言环境。 2. 下载和安装 Fabric 的 Go SDK。 3. 使用 Go 语言编写智能合约,并将其编译为可执行文件。 4. 将编译后的合约文件打包为 Chaincode 包,并将其部署到 Fabric 网络中。 5. 在你的应用程序中调用智能合约。 下面简要介绍一下如何使用 Go 语言编写、编译和部署智能合约: 1. 编写智能合约 使用 Go 语言编写智能合约编写其他 Go 程序并没有太大区别。你需要实现智能合约接口,包括 Init 和 Invoke 方法。Init 方法在部署合约时执行,而 Invoke 方法在调用合约时执行。 例如,以下是一个简单的示例智能合约,它实现了 Init 和 Invoke 方法,用于存储和检索键值对: ```go package main import ( "fmt" "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 { return shim.Success(nil) } func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { function, args := stub.GetFunctionAndParameters() if function == "put" { key := args[0] value := args[1] err := stub.PutState(key, []byte(value)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } else if function == "get" { key := args[0] value, err := stub.GetState(key) if err != nil { return shim.Error(err.Error()) } return shim.Success(value) } return shim.Error("Invalid function name") } func main() { err := shim.Start(new(SimpleChaincode)) if err != nil { fmt.Printf("Error starting chaincode: %s", err) } } ``` 2. 编译智能合约 使用 Go 语言编写智能合约需要编译为可执行文件。你可以使用 Go 语言提供的工具来编译合约,如 go build 命令。 例如,假设你的合约代码保存在 $GOPATH/src/mychaincode 目录下,你可以使用以下命令编译智能合约: ``` go build -o mychaincode ``` 这将生成一个名为 mychaincode 的可执行文件。 3. 打包智能合约 编译后的智能合约需要打包为 Chaincode 包,然后才能部署到 Fabric 网络中。Chaincode 包是一个 tar 归档文件,其中包含智能合约的二进制文件和一些元数据。 你可以使用 Fabric 提供的 `peer` 命令行工具来打包合约。例如,假设你的智能合约代码保存在 $GOPATH/src/mychaincode 目录下,你可以使用以下命令打包合约: ``` peer chaincode package -n mychaincode -v 1.0 -p mychaincode -s -S -i "OR ('Org1MSP.peer', 'Org2MSP.peer')" mychaincode.tar.gz ``` 这将生成一个名为 mychaincode.tar.gz 的 Chaincode 包。 4. 部署智能合约 部署智能合约需要将 Chaincode 包安装到 Fabric 网络中。你可以使用 Fabric 提供的 `peer` 命令行工具来安装和实例化合约。 例如,假设你已经在本地启动了 Fabric 网络,并且有一个名为 mychannel 的通道可用,你可以使用以下命令安装和实例化合约: ``` peer chaincode install mychaincode.tar.gz peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mychaincode -v 1.0 -c '{"Args":[]}' -P "OR ('Org1MSP.peer', 'Org2MSP.peer')" ``` 5. 调用智能合约 部署智能合约后,你可以在你的应用程序中调用它。你需要使用 Fabric 提供的 SDK 来与合约进行交互。 例如,以下是一个简单的 Go 语言应用程序,它使用 Fabric Go SDK 来调用智能合约: ```go package main import ( "fmt" "github.com/hyperledger/fabric-sdk-go/pkg/client/channel" "github.com/hyperledger/fabric-sdk-go/pkg/fabsdk" ) func main() { // 创建 Fabric SDK 实例 sdk, err := fabsdk.New(nil) if err != nil { panic(err) } defer sdk.Close() // 创建 Fabric Channel 客户端 clientChannelContext := sdk.ChannelContext("mychannel", fabsdk.WithUser("User1")) channelClient, err := channel.New(clientChannelContext) if err != nil { panic(err) } // 调用智能合约 response, err := channelClient.Execute(channel.Request{ ChaincodeID: "mychaincode", Fcn: "put", Args: [][]byte{[]byte("key"), []byte("value")}, }) if err != nil { panic(err) } fmt.Printf("Response: %s\n", response.Payload) } ``` 以上就是使用 Go 语言编写、编译和部署智能合约的基本步骤。需要注意的是,这只是一个简单的示例,实际生产环境中需要考虑更多的安全和性能问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值