一、服务器我选用的是阿里云服务器,按量付费,方便随时不想用的时候直接释放掉就可以了
首先选择配置,按实际情况来选
选择Ubuntu 18.04 64位系统
创建密码,填写主机名
其他保留默认即可!
后面需要用到Xftp传输文件,以及Unity与Loom节点通信所以需要把服务器相关的端口开放
打开服务器实例里的管理,左边列表的安全组进入,点击配置规则,添加安全组规则
二、安装服务器上需要用到的一些插件
我本地使用的是Win7笔记本来开发,为了方便操作服务器,推荐安装Xshell和Xftp软件来连接服务器
使用Xshell比较方便的可以同时开多个窗口
输入命令更新源
apt-get update
安装nodejs
sudo apt-get install nodejs
安装npm
sudo apt-get install npm
然后测试nodejs的版本和包管理器npm的版本node -v、npm -v
三、安装Loom以及开发合约需要用到的相关插件
安装Loom运行Dapp链:
curl https://raw.githubusercontent.com/loomnetwork/loom-sdk-documentation/master/scripts/get_loom.sh | sh
./loom init
./loom run
LoomNetwork官方开发文档:https://loomx.io/developers/zh-CN/how-to-develop-locally.html#introduction
安装truffle
npm install truffle -g
npm install solc -g
安装完成会显示truffle版本
初始化一个新项目
mkdir truffle-dappchain
cd truffle-dappchain
truffle init
cd contracts
touch SimpleStore.sol
vi SimpleStore.sol
编写SimpleStore合约
pragma solidity ^0.5.0;
contract SimpleStore {
uint value;
event NewValueSet(uint _value);
function set(uint _value) public {
value = _value;
emit NewValueSet(value);
}
function get() public view returns (uint) {
return value;
}
}
编写完按esc :wq 保存退出
编译合约
root@LoomNet:~/truffle-dappchain# truffle compile
Compiling your contracts...
===========================
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/SimpleStore.sol
> Artifacts written to /root/truffle-dappchain/build/contracts
> Compiled successfully using:
- solc: 0.5.8+commit.23d335f2.Emscripten.clang
root@LoomNet:~/truffle-dappchain# ls
build contracts migrations test truffle-config.js
root@LoomNet:~/truffle-dappchain#
合约部署需要创建一个迁移文件,进入migrations文件夹
root@LoomNet:~/truffle-dappchain# cd migrations
root@LoomNet:~/truffle-dappchain/migrations# ls
1_initial_migration.js
root@LoomNet:~/truffle-dappchain/migrations# cp 1_initial_migration.js 2_simple_store.js
root@LoomNet:~/truffle-dappchain/migrations# ls
1_initial_migration.js 2_simple_store.js
root@LoomNet:~/truffle-dappchain/migrations# vi 2_simple_store.js
root@LoomNet:~/truffle-dappchain/migrations#
var SimpleStore = artifacts.require("./SimpleStore.sol");
module.exports = function(deployer) {
deployer.deploy(SimpleStore);
};
修改truffle-config.js里的网络配置
const { readFileSync } = require('fs')
const path = require('path')
const { join } = require('path')
const LoomTruffleProvider = require('loom-truffle-provider')
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*",
},
local_loom: {
provider: function() {
const privateKey = readFileSync(path.join(__dirname, 'loom_private_key'), 'utf-8')
const chainId = 'default'
const writeUrl = 'http://127.0.0.1:46658/rpc'
const readUrl = 'http://127.0.0.1:46658/query'
const loomTruffleProvider = new LoomTruffleProvider(chainId, writeUrl, readUrl, privateKey)
loomTruffleProvider.createExtraAccountsFromMnemonic("gravity top burden flip student usage spell purchase hundred improve check genre", 10)
return loomTruffleProvider
},
network_id: '*'
}
}
}
安装loom-truffle-provider
npm install loom-truffle-provider --save
创建一个名为'loom_private_key'的私钥
由于我的loom链是在根节点,私钥需要放到truffle-dappchain的根目录,所以我这样执行
root@LoomNet:~/truffle-dappchain# ../loom genkey -a loom_public_key -k loom_private_key
local address: 0x02b40aAaF26f97f3ea0CA550a4C24F8b5C8d1324
local address base64: ArQKqvJvl/PqDKVQpMJPi1yNEyQ=
root@LoomNet:~/truffle-dappchain# ls
build chaindata contracts loom_private_key loom_public_key migrations test truffle-config.js
root@LoomNet:~/truffle-dappchain#
接下来打开另一个Xshell窗口,启动LoomDapp链
./loom run
在刚才的窗口将合约部署到Loom链上
truffle migrate --network local_loom
这个时候合约就开始部署了
root@LoomNet:~/truffle-dappchain#
root@LoomNet:~/truffle-dappchain#
root@LoomNet:~/truffle-dappchain# truffle migrate --network local_loom
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name: 'local_loom'
> Network id: 13654820909954
> Block gas limit: 0x0
1_initial_migration.js
======================
Deploying 'Migrations'
----------------------
> transaction hash: 0x434fee0b8efcdec81dbf30520bc7d476b038cd3e44441b1655f66a93fc6dd833
> Blocks: 0 Seconds: 0
> contract address: 0x04B755D415BF2D528AfC562866B3DD52c1717893
> block number: 141
> block timestamp: 1569744222
> account: 0x02B40AAAF26F97f3Ea0CA550a4C24f8B5c8D1324
> balance: 0
> gas used: 0
> gas price: 0 gwei
> value sent: 0 ETH
> total cost: 0 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0 ETH
2_simple_store.js
=================
Deploying 'SimpleStore'
-----------------------
> transaction hash: 0x072f26c332cc19b59c3c37c9f0cfe9ea55122169b2308161828271e17010e520
> Blocks: 0 Seconds: 0
> contract address: 0xda98B323AC5c6c4E5DE2C6B71fc908744f14E7d4
> block number: 147
> block timestamp: 1569744228
> account: 0x02B40AAAF26F97f3Ea0CA550a4C24f8B5c8D1324
> balance: 0
> gas used: 0
> gas price: 0 gwei
> value sent: 0 ETH
> total cost: 0 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0 ETH
root@LoomNet:~/truffle-dappchain#
部署成功会在build/contracts目录里找到SimpleStore.json文件,里面就包含我们的合约abi
root@LoomNet:~/truffle-dappchain# cd build
root@LoomNet:~/truffle-dappchain/build# ls
contracts
root@LoomNet:~/truffle-dappchain/build# cd contracts
root@LoomNet:~/truffle-dappchain/build/contracts# ls
Migrations.json SimpleStore.json
root@LoomNet:~/truffle-dappchain/build/contracts# vi SimpleStore.json
{
"contractName": "SimpleStore",
"abi": [
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"name": "_value",
"type": "uint256"
}
],
"name": "NewValueSet",
"type": "event"
},
{
"constant": false,
"inputs": [
{
"name": "_value",
"type": "uint256"
}
],
"name": "set",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "get",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
}
],
我们只需要"abi":[]大括号的部分一会会用到,
记住我们部署的SimpleStore合约地址,等会在Unity工程当中会用到,你的地址部署出来可能跟我的不一样
contract address: 0xda98B323AC5c6c4E5DE2C6B71fc908744f14E7d4
接下来我们在test目录创建一个测试合约脚本
root@LoomNet:~/truffle-dappchain# cd test
root@LoomNet:~/truffle-dappchain/test# ls
root@LoomNet:~/truffle-dappchain/test# touch SimpleStore.js
root@LoomNet:~/truffle-dappchain/test# ls
SimpleStore.js
root@LoomNet:~/truffle-dappchain/test# vi SimpleStore.js
root@LoomNet:~/truffle-dappchain/test#
测试合约内容
const SimpleStore = artifacts.require('SimpleStore')
contract('Test', (accounts) => {
let [alice] = accounts
let contractInstance
beforeEach(async () => {
contractInstance = await SimpleStore.new()
});
it('should be able to set a value', async () => {
let value = 4
const result = await contractInstance.set(value, {from: alice})
assert.equal(result.receipt.status, true)
assert.equal(result.logs[0].args._value.toString(), value.toString())
})
it('should be able to set and then get a value', async () => {
let value = 5
await contractInstance.set(value, {from: alice})
const result = await contractInstance.get({from: alice})
assert.equal(result.toString(), value.toString())
})
})
使用命令测试合约
root@LoomNet:~/truffle-dappchain/test# cd ../
root@LoomNet:~/truffle-dappchain# truffle test --network local_loom
Using network 'local_loom'.
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Contract: Test
✓ should be able to set a value (3018ms)
✓ should be able to set and then get a value (3021ms)
2 passing (12s)
root@LoomNet:~/truffle-dappchain#
测试成功!
四、在Unity工程中调用Loom合约
这里是官方的Unity教程:
https://loomx.io/developers/zh-CN/unity-truffle-loom-sample.html
首先去github下载LoomSDK的Unity工程包:
https://github.com/zandk/CryptoRealmClient
SimpleStoreHandler脚本代码:
using System;
using System.Threading.Tasks;
using UnityEngine;
using Loom.Unity3d;
using Loom.Unity3d.Samples;
using Loom.Nethereum.ABI.FunctionEncoding.Attributes;
public class LoomQuickStartSample : MonoBehaviour {
// 部署合约之后返回的abi
// 合约部署的地址
public TextAsset simpleStoreABI;
public TextAsset simpleStoreAddress;
async Task<EvmContract> GetContract(byte[] privateKey, byte[] publicKey)
{
var writer = RPCClientFactory.Configure()
.WithLogger(Debug.unityLogger)
.WithHTTP("http://127.0.0.1:46658/rpc")//替换自己部署到云服务器上的LoomDapp链的服务器IP
//.WithWebSocket("ws://127.0.0.1:46657/websocket")
.Create();
var reader = RPCClientFactory.Configure()
.WithLogger(Debug.unityLogger)
.WithHTTP("http://127.0.0.1:46658/query")//替换自己部署到云服务器上的LoomDapp链的服务器IP
//.WithWebSocket("ws://127.0.0.1:9999/queryws")
.Create();
var client = new DAppChainClient(writer, reader)
{
Logger = Debug.unityLogger
};
// required middleware
client.TxMiddleware = new TxMiddleware(new ITxMiddlewareHandler[]{
new NonceTxMiddleware{
PublicKey = publicKey,
Client = client
},
new SignedTxMiddleware(privateKey)
});
//合约部署之后返回的abi
string abi = simpleStoreABI.ToString();
//string abi = "[{\"anonymous\": false,\"inputs\": [{\"indexed\": false,\"name\": \"_value\",\"type\": \"uint256\"}],\"name\": \"NewValueSet\",\"type\": \"event\"},{\"constant\": false,\"inputs\": [{\"name\": \"_value\",\"type\": \"uint256\"}],\"name\": \"set\",\"outputs\": [],\"payable\": false,\"stateMutability\": \"nonpayable\",\"type\": \"function\"},{\"constant\": true,\"inputs\": [],\"name\": \"get\",\"outputs\": [{\"name\": \"\",\"type\": \"uint256\"}],\"payable\": false,\"stateMutability\": \"view\",\"type\": \"function\"}]\r\n";
//合约地址
var contractAddr = Address.FromHexString(simpleStoreAddress.ToString());
var callerAddr = Address.FromPublicKey(publicKey);
return new EvmContract(client, contractAddr, callerAddr, abi);
}
/// <summary>
/// 调用合约的set方法
/// </summary>
/// <param name="contract"></param>
/// <returns></returns>
async Task CallContract(EvmContract contract,int value)
{
await contract.CallAsync("set", value);
}
/// <summary>
/// 调用合约的get方法
/// </summary>
/// <param name="contract"></param>
/// <returns></returns>
async Task StaticCallContract(EvmContract contract)
{
if (contract == null)
{
throw new Exception("Not signed in!");
}
var result = await contract.StaticCallSimpleTypeOutputAsync<int>("get");
if (result!=null)
{
Debug.Log("Smart contract returned: " + result.ToString());
}
else
{
throw new Exception("Smart contract didn't return anything!");
}
}
// Use this for initialization
async void Start()
{
// The private key is used to sign transactions sent to the DAppChain.
// Usually you'd generate one private key per player, or let them provide their own.
// In this sample we just generate a new key every time.
var privateKey = CryptoUtils.GeneratePrivateKey();
var publicKey = CryptoUtils.PublicKeyFromPrivateKey(privateKey);
var contract = await GetContract(privateKey, publicKey);
/**
由于合约方法执行需要有一定的时间,
所以这里调用set方法的时候不能直接就调用get方法,
有可能返回的是之前保存的值,不是最新的
为了看到正确结果,可以分两次执行
*/
await CallContract(contract, 123);//调用合约set方法保存一个值
//await StaticCallContract(contract);//调用合约get方法获取合约中保存的值
}
}
如果你在调用get方法之后得到了你之前设置的值,那就说明你通过Unity与LoomSDK通信成功了!
接下来我们就可以编写更复杂的合约了,我会继续更新Unity游戏方面的教程,敬请期待!
下面是我的个人公众号,我是一名Unity游戏开发工程师,也擅长小游戏开发,如果有感兴趣的请关注我!
Loom Network官方发布了一个赏金赢取Loom代币奖励的活动,推荐大家参加!
活动详情:赏金和奖励 —— 参与网络,赢取 LOOM 代币
Loom Network官方的免费学习智能合约游戏编写 DApp:https://cryptozombies.io/zh,一步一步教你如何编写Solidity智能合约!
如果有阿里云服务器的新用户推荐大家使用阿里云的券来体验:高性能云服务器2折起