RandDrop 应用链的部署¶
RandDrop的部署与ProcWind类似,目前提供快速部署的脚本支持,可以在RandDrop的发布目录: https://github.com/MOACChain/moac-core/tree/master/randdrop 中的ASM或者AST目录下,找到对应的deployAll.js。 其中的合约源代码已经使用solidity 0.4.24编译并存储在mcByteCodes.js中便于用户使用。
Vnode节点软件¶
MOAC主网节点 版本来源: https://github.com/MOACChain/moac-core/releases/
此文档采用的版本: 1.1.0 环境:windows testnet浏览器: http://testnet.moac.io/home
- 在测试环境testnet启动节点:
- moac-windows-4.0-amd64.exe –testnet –rpc –rpcapi “chain3,mc,net,db,personal,admin,miner”
验证:
windows command 执行 moac-windows-4.0-amd64.exe attach \\.\pipe\moac.ipc
运行concole命令 mc.blockNumber 检查是否同步到最新区块
SCS节点软件¶
RandDrop 应用链节点 版本来源: https://github.com/MOACChain/moac-core/releases/
userconfig.json配置:
VnodeServiceCfg为代理vnode地址: 192.168.10.209:50062 (对应上面部署的vnode的IP)
Beneficiary为收益账号
启动节点:
scsserver-vss-windows-4.0-amd64 --password "123456" (生成scs keystore的密码)
验证:
scs启动后,并开始从vnode同步块号信息。
在scskeystore目录内生成的keystore文件中生成scs账号的scskeystore文件。
各类账号¶
SCS本身无法创建帐号,可以运行VNODE的命令产生。例如,进入VNODE console:
创建账号:
personal.newAccount()
查看账号:
mc.accounts
按序号查询余额:
mc.getBalance(mc.accounts[0])
MOAC测试网的测试币,可以通过公共提币地址获得:https://faucet.moacchina.com
注意:后续消耗gas的操作都需要执行personal.unlockAccount() 对应账号进行解锁
准备账号列表:(示例地址参考后续的命令操作)
应用链操作账号:进行创建合约,发起交易等基本操作: 0x87e369172af1e817ebd8d63bcd9f685a513a6736
主链vnode收益账号: 0xf103bc1c054babcecd13e7ac1cf34f029647b08c
应用链scs收益账号:0xa934198916cd993c73c1aa6e0c0e7b21ce7c735b 0x2e7c076dbf6e61207a0ddb1b942ef7da8fd139f0
nodejs 环境及 chain3 软件库¶
注意,在windows下,可能还要安装辅助工具 Python 2.X 和 VS2013/2015
1.安装Python 2.X,在这里我安装的是Python 2.7,不能用3及以上版本,安装好了设置环境变量;
2.安装VS2013 或者 VS2015;
3.安装NodeJS及npm工具;
4.安装 chain3 软件库
npm install chain3
验证:
> chain3 = require('chain3');
> chain3 = new chain3();
> chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545'));
> chain3.mc.blockNumber 检查是否获得当前区块
此外,目前应用链的合约编译仅支持solc 0.4.24版本,需要在工程目录下执行下面命令,更换solc版本
npm uninstall solc
npm install solc@0.4.24
部署VNODE节点池合约¶
请参考 VNODE 节点池部署 ,并记录VNODE节点池合约的地址,如果加入现成的VNODE节点池,则可以跳过此步骤。
部署VSS合约¶
在vnode系统链上部署vssbase合约,构造函数需要提供1个threshold参数,该参数表示阀值签名的阀值。部署后,记录下vssbase合约的部署地址vssbaseAddress Vssbase的构造函数签名如下: function VssBase(int threshold) public
threshold参数用来决定随机数的阈值,即需要的阈值签名数量,如果获得的节点数目超过这个,就可以出块。 建议取大概2/3的预设节点数,例如,对于应用链使用节点数为11,threshold需要取7。
部署应用链合约¶
- 根据需要使用的合约类型,确定好合约文件。目前主要有ASM和AST两种类型的ProcWind。最新的合约可以从
- MOAC 开源地址 处获取。
现在我们可以部署一个应用链合约。
部署ChainBaseASM.sol示例,首先运行Node.js,在node命令行下:
> chain3 = require('chain3')
> solc = require('solc')
> chain3 = new chain3();
> chain3.setProvider(new chain3.providers.HttpProvider('http://localhost:8545'));
> input = {'': fs.readFileSync('ChainBaseASM.sol', 'utf8'), 'SubChainProtocolBase.sol': fs.readFileSync('SubChainProtocolBase.sol', 'utf8')};
> output = solc.compile({sources: input}, 1);
> abi = output.contracts[':SubChainBase'].interface;
> bin = output.contracts[':SubChainBase'].bytecode;
> proto = '0x ' ; // 应用链节点池合约
> vnodeProtocolBaseAddr = '0x ' ; // Vnode节点池合约
> min = 1 ; // 应用链需要SCS的最小数量,当前需要从如下值中选择:1,3,5,7
> max = 11; // 应用链需要SCS的最大数量,当前需要从如下值中选择:11,21,31,51,99
> thousandth = 1 ; // 千分之几,控制选择scs的概率,对于大型应用链节点池才有效
> flushRound = 40 ; // 应用链刷新周期 单位是主链block生成对应数量的时间,当前的取值范围是40-99
> tokenSupply = 1000000 ; // ASM应用链货币总量
> exchangeRate = 100 ; // ASM系统链应用链兑换比率
> vssbaseAddr = '0x' ; // VSS合约地址
> SubChainBaseContract = chain3.mc.contract(JSON.parse(abi));
> chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456');
> SubChainBase = SubChainBaseContract.new( proto, vnodeProtocolBaseAddr, min, max, thousandth, flushRound, vssbaseAddr
{ from: chain3.mc.accounts[0], data: '0x' + bin, gas:'9000000'} , function (e, contract){console.log('Contract address: ' + contract.address + ' transactionHash: ' + contract.transactionHash); });
部署完毕后, 获得应用链合约地址,如:0x1195cd9769692a69220312e95192e0dcb6a4ec09
设定应用链使用VSS服务¶
在基础链上,调用vssbase合约的setCaller方法,传入之前的RandDrop合约地址 subchainbaseAddress。 此方法调用后,保证了vssbase合约的部分关键函数只能由subchainbase合约调用,而无法由外部普通账户调用。 setCaller函数签名如下: function setCaller(address callerAddr) public
应用链开放注册¶
首先应用链合约需要最终提供gas费给scs,需要给应用链控制合约发送一定量的moac,调用合约里的函数addFund
根据ABI chain3.sha3("addFund()") = 0xa2f09dfa891d1ba530cdf00c7c12ddd9f6e625e5368fff9cdf23c9dc0ad433b1
取前4个字节 0xa2f09dfa
> amount = 20;
> subchainaddr = '0x1195cd9769692a69220312e95192e0dcb6a4ec09';
> chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456');
> chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:chain3.toSha(amount,'mc'), to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0xa2f09dfa'});
可以通过查询余额进行验证
> chain3.mc.getBalance('0x1195cd9769692a69220312e95192e0dcb6a4ec09')
然后调用 调用合约里的函数registerOpen 开放注册 (按应用链节点池合约中SCS注册先后排序进行选取)
根据ABI chain3.sha3("registerOpen()") = 0x5defc56ce78f178d760a165a5528a8e8974797e616a493970df1c0918c13a175
取前4个字节 0x5defc56c
> subchainaddr = '0x1195cd9769692a69220312e95192e0dcb6a4ec09';
> chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456');
> chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0x5defc56c'});
验证: 等待scs注册 (vnode 一个 flush周期后 ) , 可不断访问应用链合约的 nodeCount,等待3个scs注册完成
> SubChainBase.nodeCount()
> chain3.mc.getStorageAt(subchainaddr,0x0e) // 注意nodeCount变量在合约中变量定义的位置(16进制)
应用链关闭注册¶
等到两个scs都注册完毕后,即注册SCS数目大于等于应用链要求的最小数目时,调用应用链合约里的函数 registerClose关闭注册。 根据ABI chain3.sha3(“registerClose()”) = 0x69f3576fc10c82561bd84b0045ee48d80d59a866174f2513fdef43d65702bf70 取前4个字节 0x69f3576f:
> subchainaddr = '0x1195cd9769692a69220312e95192e0dcb6a4ec09';
> chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456');
> chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0x69f3576f'});
验证: SCS自身完成初始化并开始应用链运行,可观察scs的concole界面,scs开始出块即成功完成部署应用链。
#####################################
### SendBkToVnode Block Number:1 ###
block.Hash: 0x0c8af045440ed13f2cc6e77635f1d96eeb1724c2cbd3c0640f56ec4c419e188b
block.ParentHash: 0x0c715842a0e53dd2956758ada1a7e270c9de85f219b161c6fbda321e52036c83
SubchainAddr: 0x97d4667ed5f70c4586b5b436c9bbd15eafdbfc02
Sender: 0x50c15fafb95968132d1a6ee3617e99cca1fcf059
#####################################
应用链的运维¶
部署完成应用链后,可以手工加入SCS节点或者去除SCS节点,也可以加入监听节点:
应用链合约提供了registerAdd方法来支持应用链添加,必须由应用链部署账号来发送交易请求。
需要对应SubChainProtocolBase(SCSProtolBase.sol)节点池合约有等待加入的scs节点。
应用链收到请求后,在节点池合约选取scs,开始同步应用链区块,等一轮flush后生效,正式加入应用链。
registerAdd参数:
nodeToAdd: 当前scs数+需要加入scs数
调用示例:
> data = subchainbase.registerAdd.getData(20)
> subchainaddr = '0x1195cd9769692a69220312e95192e0dcb6a4ec09';
> chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456');
> chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: data});
验证:scs对应日志开始同步区块,合约公共变量nodeCount更新为scs最新数量:
> SubChainBase.nodeCount()
应用链关闭请求¶
应用链合约提供了close的方法来支持关闭应用链,必须由应用链部署账号来发送交易请求。
调用示例:
根据ABI chain3.sha3("close()") = 0x43d726d69bfad97630bc12e80b1a43c44fecfddf089a314709482b2b0132f662
取前4个字节 0x43d726d6
> subchainaddr = '0x1195cd9769692a69220312e95192e0dcb6a4ec09';
> chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456');
> chain3.mc.sendTransaction( { from: chain3.mc.accounts[0], value:0, to: subchainaddr, gas: "2000000", gasPrice: chain3.mc.gasPrice, data: '0x43d726d6'});
关闭请求发送后,需等待一轮flush后生效,相关应用链维护费用也将退回到应用链部署账号中。 可以通过查询余额进行验证:
> chain3.mc.getBalance('0x1195cd9769692a69220312e95192e0dcb6a4ec09')
应用链的优化部署¶
RandDrop 应用链对网络要求比较高,如果用于商业项目在所有节点可控的情况下建议进行的优化部署。 推荐采用云服务器:
VNODE 最低要求配置:4核4G,推荐4核8G;
SCS 最低要求配置:2核4G;(注意:scs配置建议型号统一);
通讯网络建议带宽:4MB/s;
实用场景 | VNODE数量 | SCS数量 | VNODE-SCS连接配置 |
---|---|---|---|
开发环境 | 1 | 3 | 1V-3S* |
低频生产环境 | 3 | 7 | 1V-2S:1V-2S:1V-3S |
高频生产环境 | 5 | 11 | 1V-2S:1V-2S:1V-2S:1V-2S:1V-3S |
- 1V-3S, 1 VNODE 连接 3 SCSs
在运行RandDrop的时候,需要将所有验证节点的机器时钟调成一致,保证在节点通讯时的时间标记是同步的。如果验证节点之间的时钟不同,那么验证过程的执行可能会被打乱,导致节点无法同步。 建议使用NTP服务来保证SCS之间的时间一致性。可以使用一台SCS机器做NTP时间服务器,同时这台机器本身与外网标准的其它时间服务器同步,其它服务器以这台SCS作为校对即可,当然其它方案也可以,只要保证SCS之间的时间是一致的,即可保证应用链节点的同步。
首先给所有的机器安装nfp软件,可以参考这篇`文章 <https://www.cnblogs.com/wxxjianchi/p/10531582.html>`__来做相关的NTP服务。 这里也给一个大概说明作为重点参数的配置参考,当然也可以自己设置其NTP服务规则,具体需要依照IP地址进行配置。
在各个VNODE节点启动之后,最好加入相邻的节点,使用AddPeer把节点直接相连,可以优化通信。 如果需要调试应用链,可以使用系统日志,参考 SCS 日志设置 。
在VNODE console终端中调用admin.addSubnetP2P方法,第一个参数为应用链合约地址,即subchainbase地址,第二个参数为加入的区块高度,建议设为当前区块高度+100。 例如当前区块为20000
> admin.addSubnetP2P(subchainbase.address, 20100)
未来块最好比当前块高一百个块左右,让其有时间将自己的网络调整到位