Go语言与智能合约的交互
Go语言与智能合约的交互实现步骤首先要编写一份智能合约将智能合约通过工具转化为go文件自己编写go文件调用智能合约转化成的go文件提供的接口具体实现编写一份智能合约智能合约使用solidity语言写的,可以用在线的remix编辑器进行编辑。
pragmasolidity>=0.4.22}functionsetFheAddressHash(bytes32_fheAddressHash)payablepublic{fheAddressHash=_fheAddressHash;emitLogSetFheAddressHash(fheAddressHash);}functionsetModelHash(bytes32_modelHash)payablepublic{modelHash=_modelHash;emitLogSetModelHash(modelHash);}functionsetRsaPublicKeyHash(bytes32_rsaPublicKeyHash)payablepublic{rsaPublicKeyHash=_rsaPublicKeyHash;emitLogSetRsaPublicKeyHash(rsaPublicKeyHash);}functionsetDataHash(bytes32_dataHash)payablepublic{dataHash=_dataHash;emitLogSetDataHash(dataHash);}functionsetEncryptedAesKeyHash(bytes32_encryptedAesKeyHash)payablepublic{encryptedAesKeyHash=_encryptedAesKeyHash;emitLogEncryptedAesKeyHash(encryptedAesKeyHash);}functionsetTrainedResultHash(bytes32_trainedResultHash)payablepublic{trainedResultHash=_trainedResultHash;emitLogTrainedResultHash(trainedResultHash);}functionsetFinalDistance(bytes32_finalDistance)payablepublic{finalDistance=_finalDistance;emitLogSetFinalDistance(finalDistance);}functionsetModelParamsHash(bytes32_modelParamsHash)payablepublic{modelParamsHash=_modelParamsHash;emitLogSetModelParamsHash(modelParamsHash);}eventLogSetFheAddressHash(bytes32_fheAddressHash);eventLogSetModelHash(bytes32_modelHash);eventLogSetRsaPublicKeyHash(bytes32_rsaPublicKeyHash);eventLogSetDataHash(bytes32_dataHash);eventLogEncryptedAesKeyHash(bytes32_encryptedAesKeyHash);eventLogTrainedResultHash(bytes32_trainedResultHash);eventLogSetFinalDistance(bytes32_finalDistance);eventLogSetModelParamsHash(bytes32_modelParamsHash);}将智能合约用工具转化为go语言:我们用abigen将智能合约转化为go文件
abigen安装的方式如下:
gogetgithub.com/ethereum/go-ethereumcd$GOPATH/src/github.com/ethereum/go-ethereum/makemakedevtools接着我们用如下命令将智能合约转化为go语言文件:
DataStorage.sol为智能合约文件,filedir为生成的文件的保存目录。
#第一行命令会生成.abi文件在filedir目录中solcjsDataStorage.sol-ofiledir--abi#第二行命令会生成.bin文件在filedir目录中solcjsDataStorage.sol-ofiledir--bin#第三行命令用filedir中的.abi文件和.bin文件生成一个package为main的名为DataStorage.go的go语言文件.该文件保存在/Users/huyifan/DAI中.abigen--abiDataStorage_sol_DataStorage.abi--binDataStorage_sol_DataStorage.bin--pkgmain--out/Users/huyifan/DAI/DataStorage.go自己编写go文件调用智能合约转化成的go文件提供的接口我这里只调用了setDataHash这个智能合约函数,将字符串存进区块链智能合约中,然后再从区块链中获取我们存进去的字符串。其他的函数以此类推。
packagemainimport("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目录里面constkey=`{"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}`funcmain(){//我们要存进区块链智能合约的字符串dataHash:="testDataHash"//智能合约的在区块链上的地址contractAddress:="0x47d73709bf274160118f8f175695ac3616b7f08f"//连接本地的以太坊私链(一定要保证本地以太坊私链已经启动)conn,err:=ethclient.Dial("http://127.0.0.1:8545")fmt.Println("connecttolocalgethnode...",conn)iferr!=nil{log.Fatalf("couldnotconnecttolocalnode:%v",err)}//fmt.Println("getthecontractobject...")token,err:=NewMain(common.HexToAddress(contractAddress),conn)iferr!=nil{log.Fatalf("FailedtoinstantiateaTokencontract:%v",err)}fmt.Println("contracttoken======>:",token)//解锁对应账户auth,err:=bind.NewTransactor(strings.NewReader(key),"abc")iferr!=nil{log.Fatalf("couldnotcreateauth:%v",err)}alloc:=make(core.GenesisAlloc)alloc[auth.From]=core.GenesisAccount{Balance:big.NewInt(1337000000000)}sim:=backends.NewSimulatedBackend(alloc,100000000)//fmt.Println("token:=====>",token)vararr[32]bytefork,v:=range[]byte(dataHash){arr[k]=byte(v)}fmt.Println(string(arr[:len(arr)]))//调用对应的go语言函数与以太坊私链进行交互fmt.Println("=========startputdata=========")_,err=token.SetDataHash(&bind.TransactOpts{From:auth.From,Signer:auth.Signer,GasLimit:288162,Value:big.NewInt(30),},arr)iferr!=nil{log.Fatalf("transactionproducefail:%v",err)}//提交交易sim.Commit()iferr!=nil{log.Fatalf("putdatatodatapoolerr:%v",err)}fmt.Println("putdatatosmartcontractsuccess!")fmt.Println("==================================")fmt.Println("getdatafromsmartcontract")//从以太坊上获得之前存进去的值info,_:=token.DataHash(&bind.CallOpts{Pending:true})//fmt.Printf("thetotaldatapricesanddesciptionare:%s ",info);fmt.Printf(string(info[:len(info)]))}结果如下所示:以太坊产生的信息如下图所示:
注意点:
只要将想要从以太坊获得值的那个变量在智能合约中设置成public,智能合约转为go语言文件后会自动的生成相应的函数,调用那个函数就可以从以太坊中获得变量值。如果智能合约的某个函数会改变以太坊的状态(例如设置某个变量的值,更新了某个变量的值等等),那么在智能合约中这个函数就要用payable修饰,因为调用这个函数的时候必须要发起交易,待这个交易被确认后,调用的这个函数的产生的结果才生效。我们也可以从设置值的函数和获取值的函数的参数看出端倪:也可以事先不部署智能合约。这样的话,就需要调用DataStorage.go文件中的DeployMain函数自己手动的部署智能合约,代码修改如下:以太坊的状态如下图所示:这里再次提醒只要对区块链状态发生了改变的话,必须提交交易,并被验证通过才能算真正的改变了区块链.