请选择 进入手机版 | 继续访问电脑版

Hi,Tokens

 找回密码
 立即注册
查看: 994|回复: 18

【整理】墨客开发资料

  [复制链接]

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
发表于 2018-9-11 13:54:33 | 显示全部楼层 |阅读模式
原文链接:https://me.csdn.net/lyq13573221675
第一篇 墨客区块链(MOAC BlockChain) 思维导图:https://blog.csdn.net/lyq13573221675/article/details/80856639

第二篇 墨客区块链(MOAC BlockChain) 开发者材料:

https://blog.csdn.net/lyq13573221675/article/details/81075474

第三篇 墨客区块链(MOAC BlockChain) 节点安装教程:

https://blog.csdn.net/lyq13573221675/article/details/81078424

第四篇 在墨客区块链(MOAC BlockChain) 部署ERC-20合约:

https://blog.csdn.net/lyq13573221675/article/details/81085339

第五篇 在墨客区块链(MOAC BlockChain) 部署ERC-721合约:

https://blog.csdn.net/lyq13573221675/article/details/81109474

第六篇 在墨客区块链(MOAC BlockChain) 测试网搭建子链
:
https://blog.csdn.net/lyq13573221675/article/details/81125954

第七篇 墨客区块链(MOAC BlockChain) 开发环境搭建:

https://blog.csdn.net/lyq13573221675/article/details/81214015

第八篇 墨客区块链(MOAC BlockChain) 程序猿怎么部署和调用智能合约:https://blog.csdn.net/lyq13573221675/article/details/81285250

第九篇 墨客区块链(MOAC BlockChain) 怎么发mc:

https://blog.csdn.net/lyq13573221675/article/details/81329107

第十篇 墨客区块链(MOAC BlockChain) 如何将自定义数据写到区块链中:

https://blog.csdn.net/lyq13573221675/article/details/81354458

第十一篇 墨客区块链(MOAC BlockChain) 详解带分发锁仓功能的ERC20合约:

https://blog.csdn.net/lyq13573221675/article/details/81359013

第十二篇 墨客区块链(MOAC BlockChain) ERC20合约的扩展功能:

https://blog.csdn.net/lyq13573221675/article/details/81448709

第十三篇 墨客区块链(MOAC BlockChain) 一文读懂墨客子链:

https://blog.csdn.net/lyq13573221675/article/details/81501978

第十四篇 墨客区块链(MOAC BlockChain) 子链SCS挖矿教程:

https://blog.csdn.net/lyq13573221675/article/details/81624434

第十五篇 墨客区块链(MOAC BlockChain) 搭建自己的第一个DAPP:

https://blog.csdn.net/lyq13573221675/article/details/81698014

第十六篇 墨客区块链(MOAC BlockChain) Chain3 JavaScript API
:
https://blog.csdn.net/lyq13573221675/article/details/82011911

第十七篇 墨客区块链(MOAC BlockChain) JSON RPC API的使用:

https://blog.csdn.net/lyq13573221675/article/details/82107371

第十八篇 墨客区块链(MOAC BlockChain) 轻钱包MOACMask:

https://blog.csdn.net/lyq13573221675/article/details/82380846

---------------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------------

视频资料,来自墨客公众号
1、视频教程 | 如何部署墨客子链
您也可以至百度网盘下载高清版观看,链接地址:
https://pan.baidu.com/s/17wx0Vt_nES5F2NUoje7flA
密码:tqft
2、视频 |MOAC子链开发教程3、视频教程 | 如何使用墨客钱包和本地节点来调试和运行合约4、虎评墨客 | 视频解答智能合约部署中的所有疑问


---------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------


第一篇 墨客区块链(MOAC BlockChain) 思维导图





一句话解释:

1.墨客区块链(MOAC BlockChain)

一种实现了子链功能、对dapp友好的底层公链。


2.子链(Micro Chains)

在墨客主链上派生出来的、具有独立功能的区块链。


3.共识(Consensus)机制

解决区块链如何在分布式场景下达成一致性和有效性的机制。


3.1 POW(Proof of Work)

基于工作量证明的共识机制。


3.2 POS(Proof of Stake)

基于权益证明的共识机制。


3.3 DPOS(Delegated Proof of Stake)

基于授权权益证明的共识机制。


3.4 IPFS(Inter Planetary File System)

一种分布式文件系统协议。


3.5 PBFT(Practical Byzantine Fault Tolerance)

实用拜占庭容错算法。


4.API(Application Programming Interface)

应用程序编程接口。


5.java

一种架构复杂、功能强大的面向对象编程语言。


6.PHP

一种适用于web开发的通用开源脚本语言。


7.Python

一种面向对象的解释型程序设计语言。


8.NodeJS

一种JavaScript运行环境。


9.Go

一种结合了效率和安全性的编译型编程语言。


10.智能合约(Smart Contract)

此处特指可以在区块链上运行的、类似执行合同的计算机协议。


11.solidity

一种适合编写智能合约的语言。


12.remix

一种浏览器版的solidity开发IDE。


13.P2P网络

一种区别于S/C结构的对等计算机网络。


14.分布式系统

构建在计算机网络之上、支持分布式处理的软件系统。


15.密码学(cryptography)

安全、隐秘地传递信息的科学或方法。


16.地址

墨客区块链主要有账号地址和合约地址。


17.数字签名

一段数字串,用于验证发送信息的真实性。


18.零知识证明(Zero Knowledge Proof)

在不提供有用信息的情况下,使验证者相信某个论断是正确的。


19.对称密钥算法

算法中加密和解密使用相同的密钥。


20. 非对称密钥算法

算法中加密和解密使用不同的密钥。


21.散列函数(hash)

把任意长度的输入通过算法变换成固定长度的输出。


22.账号

在区块链中,一对公钥和私钥共同组成唯一标识的账号。


23.挖矿

按区块链共识机制竞争记账的过程。


24.交易所

能够进行数字资产交易的场所。


25.钱包

管理数字资产的钱包,包括网页版钱包和手机版钱包。






回复

使用道具 举报

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
 楼主| 发表于 2018-9-11 13:55:18 | 显示全部楼层
回复

使用道具 举报

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
 楼主| 发表于 2018-9-11 13:55:52 | 显示全部楼层
第三篇 墨客区块链(MOAC BlockChain) 节点安装教程




北京时间2018年4月30日,墨客区块链(MOAC BlockChain)正式上线,运行稳定。


1.准备工作

墨客区块链(MOAC BlockChain)系统软件包下载地址为:

https://github.com/MOACChain/moac-core/releases

当前提供两种版本下载,其中最新的正式版为nuwa1.0.2。

nuwa(女娲)为代号,1.0.2为版本号。

windows版本适用于64位Windows 7及以上系统。

本文实际操作环境为:64位Windows 10 中文版。

注意!注意!注意:如果之前使用的Pangu0.8.2版,请保存keystore文件夹,更新时需要停止原来盘古的节点,更新,再启动,然后确认自动同步区块到最新高度,再挖矿(可以不挖),再跑自己的逻辑(比如充提)。


2.节点安装

解压下载的软件包nuwa-vnode1.0.2.win.zip到本地硬盘。目录下包含四个文件。

说明:

  • moac.exeMOAC VNODE主程序;
  • mctest.js:在console界面使用的部分功能;
  • readme.txt:说明文档;
  • vnodeconfig.json:设置子链服务的配置文件。

2.1 查看帮助

打开命令(cmd)终端,转到墨客解压目录,在命令行中执行:

D:\nuwa1.0.2.win>moac --help

2.2 安装节点

打开命令(cmd)终端,转到墨客当前目录,在命令行中执行:

D:\nuwa1.0.2.win>moac

程序会自动安装到目录:C:\Users\[userName]\AppData\Roaming\MoacNode。该目录下包含两个文件夹,moac和keystore。

如果网络正常,节点会自动开始同步。

如果是要安装到墨客测试网,在命令中执行:

D:\nuwa1.0.2.win>moac --testnet

程序会自动安装到目录:C:\Users\[userName]\AppData\Roaming\MoacNode\testnet。

如果网络正常,节点会自动开始同步。

注意:

  • 仅在安装moac节点的时候使用不带任何参数的moac命令;
  • 测试网安装的节点,每次执行moac命令后面都需要加上--testnet;
  • 如果节点同步比较慢,可以将别人已经同步好的节点的MoacNode\moac目录直接拷贝过来使用。

2.3 启动已经存在的节点

系统关机或主动关闭运行中的节点后,如果需要重新启动节点,在命令行中执行:

D:\nuwa1.0.2.win>moac console

该命令执行后,节点会自动从上次同步的区块开始同步数据

如果是在云端安装的节点,通常是Linux环境。启动节点命令:

nohup ./moac --rpc --rpcaddr=0.0.0.0 --rpcport=8545 --rpcapi="chain3,mc,net,db,personal,debug" &

2.4 进入节点attach界面

节点的console界面因为一直在同步数据,滚屏速度较快,不方便接收命令和查看命令输出效果,需要打开另一个命令(cmd)终端,转到墨客当前目录,在命令行中执行:

D:\nuwa1.0.2.win>moac attach

该命令依赖于节点已经运行起来,进入后,没有滚屏动作,方便用户输入命令及查看输出结果。

如果是非windows系统,可能需要加上ipc endpoint。在terminal命令行中执行:

ubuntu@nuwa1.0.2-ubuntu $ moac attach \\.\pipe\moac.ipc

3.子链服务配置

解压目录下的文件vnodeconfig.json是子链服务的配置文件。该文件默认设置不支持子链。



  • {



  •   "SCSservice":false,



  •   "ShowToPublic":false,



  •   "VnodeServiceCfg":"localhost:50062",



  •   "VnodeIp":"",



  •   "VnodeBeneficialAddress":""



  • }


为了让VNODE节点支持子链,用户需要配置vnodeconfig.json文件。

"SCSservice":

  • false -不支持SCS连接, 为该项的默认设置值。
  • true  -支持SCS 连接, 允许VNODE支持子链, 提供该服务后需要提供一个有效的收益地址。

"VnodeServiceCfg":

     SCS通信IP地址和端口, 默认值为50062。

"VnodeBeneficialAddress":

     此账号地址用于接收因为提供子链服务而得到的奖励收益,需要将"SCSservice"设置为true。

"ShowToPublic":

  • false - 不允许外部用户连接到SCS, 为该项的默认设置值。
  • true  - 允许外部用户通过vnode连接SCS, 同时需要配置有效的VnodeIP地址值。

"VnodeIp":

     允许外部用户通过该IP地址与VNODE连接。


4.挖矿

4.1 建立新账户

挖矿前节点必须已经建立了一个账户。

进入moac console界面,执行命令建立一个新账户:

> personal.newAccount()

系统会提示输入一个密码,例如"passwd",并再次输入相同密码确认后,会显示一个以0x开头的字符串,即为MOAC帐号的地址。

系统同时会在以下目录记录一个账号文件:C:\Users\userName\AppData\Roaming\MoacNode\keystore。

请保存好该文件,并牢记密码,之后用于解密帐号和操作。

也可以直接在命令里带上密码。比如:

> personal.newAccount("123456")

4.2 查看账户

进入MOAC console界面,执行命令:

> mc.accounts

可以查看本节点下的所有账号。

4.3 查看账户余额

进入MOAC console界面,执行命令:

> mc.getBalance(mc.accounts[0])

可以查看本节点下的账号余额。0表示第一个账户,也是默认挖矿账户。

或者:导入“mctest.js”的情况下,执行命令:



  • > loadScript("mctest.js")



  • > checkBalance()


该命令用于查看当前节点所有账号的余额。

mctest.js是节点的一个文件,里面包装了部分功能,需要用loadScript命令导入,才能在界面直接使用。

也可以通过浏览器查看账户余额等情况。

       墨客区块链浏览器:http://explorer.moac.io/home

       测试网浏览器:http://47.75.144.55:3000/home

4.4 查看挖矿状态

进入MOAC console界面,执行命令:

> mc.mining

返回true表明节点正在挖矿,false表明节点没有挖矿。

4.5 开始挖矿

进入MOAC console界面,执行命令:

> miner.start()

启动挖矿状态时,console界面会有提示开始挖矿。

4.6 停止挖矿

进入MOAC console界面,执行命令:

> miner.stop()

注意:因为主网算力大,很难用普通台式机或笔记本用命令行形式挖到矿,在测试网则可以较容易挖到矿。


5. 交易

5.1 读入函数

mctest.js是节点的一个文件,里面包装了部分功能,需要用loadScript命令导入,才能在界面直接使用。

进入MOAC console界面,执行命令:

> loadScript("mctest.js")

5.2 交易条件

为执行交易,需要至少两个帐号,其中一个有足够的mc。

如果没有目标账号,可以用步骤3.1的命令创建一个本地账号。

5.3 交易

进入MOAC console界面,执行命令:

> Send(mc.accounts[0], 'passwd', mc.accounts[1], 0.1)

这个过程中,mc.accounts[0]是发送账号,mc.accounts[1]是接收账号,'passwd'是第一个账号的密码,发送额为0.1 mc。

发送通常在下一个区块产生时完成。

系统显示的是以 sha(Sand) 为单位的余额, 1 mc = 1e18 sha。


附:墨客常用命令行参数



  • API AND CONSOLE OPTIONS:



  •   --testnet              连接到MOAC测试网络



  •   --rpc                  启动HTTP-RPC服务(基于HTTP的)



  •   --rpcaddr value        HTTP-RPC服务器监听地址(default: "localhost")



  •   --rpcport value        HTTP-RPC服务器监听端口(default: 8545)



  •   --rpcapi value         指定需要调用的HTTP-RPC API接口,默认只有mc,net,chain3



  •   --ws                   启动WS-RPC服务(基于WebService的)



  •   --wsaddr value         WS-RPC服务器监听地址(default: "localhost")



  •   --wsport value         WS-RPC服务器监听端口(default: 8546)



  •   --wsapi value          指定需要调用的WS-RPC API接口,默认只有mc,net,chain3



  •   --wsorigins value      指定接收websocket请求的来源



  •   --ipcdisable           禁掉IPC-RPC服务



  •   --ipcpath              指定IPC socket/pipe文件目录(明确指定路径)



  •   --rpccorsdomain value  指定一个可以接收请求来源的以逗号间隔的域名列表(浏览器访问的话,要强制指定该选项)



  •   --jspath loadScript    JavaScript根目录用来加载脚本 (default: ".")



  •   --exec value           执行JavaScript声明



  •   --preload value        指定一个可以预加载到控制台的JavaScript文件,其中包含一个以逗号分隔的列表


示例:



  • ./moac attach /xx/xxx/moac.ipc              通过本地ipc接口连接到MOAC节点;



  • ./moac attach "http://xxx.xxx.xxx.xxx:8545" 通过基于HTTP的RPC接口连接到本地或者远程MOAC节点;



  • ./moac --testnet                            启动MOAC测试节点;



  • ./moac --testnet console                    启动MOAC测试节点,并启动交互命令行;



  • ./moac --testnet --rpc                      启动MOAC测试节点,同时启动RPC服务;



  • ./moac --testnet --rpc --rpcaddr=0.0.0.0 --rpcapi="db,mc,net,chain3,personal,debug" --rpccorsdomain="*"



  •   启动MOAC测试节点,非本机可访问,非本机也可以使用personal及debug服务,同时提供跨域资源共享服务。



  • nohup ./moac --rpc --rpcaddr=0.0.0.0 --rpcport=8545 --rpcapi="db,mc,net,chain3,personal,debug" &



  •                                             云端Linux服务启动





回复

使用道具 举报

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
 楼主| 发表于 2018-9-11 13:56:30 | 显示全部楼层
第四篇 在墨客区块链(MOAC BlockChain) 部署ERC-20合约




本文基于墨客区块链(MOAC BlockChain),使用moac网页版钱包部署ERC-20合约。

环境:

墨客区块链版本:nuwa-vnode1.0.2.win.zip

操作系统:64位Windows 10家庭版。


1.安装并启动本地节点

1.1 安装moac节点

请参考文档《第三篇 墨客区块链(MOAC BlockChain)节点安装教程》。

1.2 启动moac节点

打开命令终端(cmd),转到墨客当前目录,在命令行中执行:

D:\nuwa1.0.2.win>moac --rpc --rpccorsdomain "http://wallet.moac.io"

备注:

--rpc  启动RPC服务,本机访问节点

--rpccorsdomain  启动浏览器访问服务,非本机访问节点

"http://wallet.moac.io" moac在线钱包网址,会自动连接到本机启动的moac节点并显示已有账号,如果本机节点没有启动,会显示以下提示信息。

启动正常,会显示以下账号信息。确保其中一个账号有足够的moac以进行智能合约部署。


2.编写并编译智能合约

2.1 以下为基于erc-20编写的一个代币合约

本文实际测试代码TestToken20.sol附在文章末尾。

注意:该代码为测试实例使用,非标准部署智能合约代码。

2.2 编译、部署合约

在网页钱包点击合约按钮“CONTRACTS”

然后点击部署新合约按钮“DEPLOY NEW CONTRACT”

选择一个有moac余额的账号。

把自己编写的智能合约代码放进代码区“Solidity contract source code”,该代码会自动进行编译,如果编译通过,右侧会显示"Select contract to deploy"。

如果编译没有通过,则不会显示相应内容。

在“Select contract to deploy”下拉框选择相应的token类型,本例为“Token Demo”,下面会自动弹出参数输入框,主要包括四项:

  • initial Amount - 256 bits unsigned integer                    //token发行总量,本例为"10000"
  • token Name - String                                                     //token名称,本例为"KongFuZi Token"
  • decimal Units - 8 bits unsigned integer                        //token最小单位是小数点后第几位
  • token Symbol - String                                                   //token简称,本例为"KFZT"

在选择gas费用后,点击"DEPLOY"部署合约。此时会显示发布合约确认界面。

如果提示需要解锁(发送代币的)账户,进入moac命令行界面,输入命令:

>personal.unlockAccount(mc.accounts[0], "passwd", 300)

该命令共有三个参数:

  • 第一个参数表示解锁的账户,
  • 第二个参数是该账户的密码,
  • 第三个参数是解锁时间,本例为300秒,300秒后会重新锁住账户;

如果解锁时间设为0,表示一直解锁,此时账号有风险,慎用。

为了隐藏密码,可以输入命令:

>personal.unlockAccount(mc.accounts[0]

回车后提示输入密码,此时密码不显示出来,该命令默认将账户解锁300秒。

成功解锁会返回true。此时会显示发布合约确认界面。

注意:Data里必须有数据,否则不能正常部署

点击“OK”,开始部署合约,界面下方会显示当前部署合约的进度条

点击成功部署的合约,可以看到基本内容,包括合约地址hash、被写入的区块号等。

登录moac区块链浏览器:http://explorer.moac.io/home。在tokens下拉框选择“View ERC20”。

在搜索栏输入合约地址,可以搜索到该合约的相应内容。

点击进去,可以看到合约基本信息、Token Transfers和Token Holders信息。

注意:该步骤可能需要已经有交易才能在浏览器查询。

至此,可以确认合约部署成功。


3.token的交易

3.1 查看合约状态

点击部署完毕的合约进度条上的“Test Token (管理页面)”,进入合约管理界面。

管理界面的上半部分显示基本信息,顶部是合约地址,右边有通用功能按钮。主要包括:接收墨客和token、浏览器查看、拷贝地址、二维码和显示接口。

点击“浏览器查看”,会跳转到区块浏览器并自动显示合约查询结果界面。

点击“显示接口”,跳出如下界面,显示“合约JSON接口”。提示如果有其他人需要管理或操作这个智能合约,则需要把接口内容连同合约地址一并发送给他。

管理界面的下半部分显示合约自身功能。

其中左边显示合约的读操作,本例中主要包括name、发行总量等。

右边为对合约的写操作,除非有自己定义的功能,对于erc-20合约不经常用到。

3.2 查看token

点击进入钱包的“CONTRACT”界面,会自动在查看合约(WATCH CONTRACT)和查看通证(WATCH TOKEN)显示所有本节点部署的合约和token。点击均可以进入相应管理和查看界面。

在账户界面,也能看到每个账户拥有的token情况。

进入发行该智能合约的主账户MAIN ACCOUNT,会显示token信息,及该账户拥有的token余额等。

3.3 交易

从钱包里拥有KFZT token的主账户,点击“SEND”进入发送交易界面。

填入要接收的账户(“TO”)、选择要发的代币名称(“KongFuZi Token”)、填入要交易的token数量(“AMOUNT”),点击“SEND”

显示发送信息界面。

此处如果提示需要解锁账户,参考前面2.2节的unlockAccount命令。

交易成功后会看到FROM账号token数量减少。

而TO账号相应token数量增加。

4.增加token

点击主界面右上角“CONTRACTS”。

选择最下面的“WATCH TOKEN”增加需要查看token。弹出增加界面。

输入合约地址,然后点击“OK”,会在界面自动增加该token,如果节点的账号拥有该token,也会自动显示出来。


附件:

本文所用合约代码TestToken20.sol。

注意:该代码为测试实例使用,非通用智能合约代码。



  • pragma solidity ^0.4.16;







  • contract Token{



  •     function balanceOf(address _owner) public constant returns (uint256 balance);       



  •     function transfer(address _to, uint256 _value) public returns (bool success);       



  •     function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);



  •     function approve(address _spender, uint256 _value) public returns (bool success);



  •     function allowance(address _owner, address _spender) public constant returns (uint256 remaining);



  •     event Transfer(address indexed _from, address indexed _to, uint256 _value);       



  •     event Approval(address indexed _owner, address indexed _spender, uint256 _value);



  • }







  • contract TokenDemo is Token {



  •     uint256 public totalSupply;                        //发行总量



  •     string  public name;                           //名称,例如"My test token"



  •     uint8   public decimals;                       //返回token使用的小数点后几位。比如如果设置为3,就是支持0.001表示.



  •     string  public symbol;                       //token简称,like MTT







  •     function TokenDemo(uint256 initialAmount, string tokenName, uint8 decimalUnits, string tokenSymbol) public {



  •         totalSupply = initialAmount * 10 ** uint256(decimalUnits);     // 设置初始总量



  •         balances[msg.sender] = totalSupply;         // 初始token数量全部给予合约的创建者







  •         name = tokenName;                  



  •         decimals = decimalUnits;         



  •         symbol = tokenSymbol;



  •     }







  •     function transfer(address _to, uint256 _value) public returns (bool success) {



  •         //默认totalSupply 不会超过最大值 (2^256 - 1).



  •         //如果随着时间的推移将会有新的token生成,则可以用下面这句避免溢出的异常



  •         require(balances[msg.sender] >= _value && balances[_to] + _value > balances[_to]);



  •         require(_to != 0x0);



  •         balances[msg.sender] -= _value;                        //从消息发送者账户中减去token数量_value



  •         balances[_to] += _value;                        //往接收账户增加token数量_value



  •         Transfer(msg.sender, _to, _value);                //触发转币交易事件



  •         return true;



  •     }







  •     function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {



  •         require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0);



  •         balances[_to] += _value;                        //接收账户增加token数量_value



  •         balances[_from] -= _value;                         //支出账户_from减去token数量_value



  •         allowed[_from][msg.sender] -= _value;                //消息发送者可以从账户_from中转出的数量减少_value



  •         Transfer(_from, _to, _value);                        //触发转币交易事件



  •         return true;



  •     }



  •     function balanceOf(address _owner) public constant returns (uint256 balance) {



  •         return balances[_owner];



  •     }







  •     function approve(address _spender, uint256 _value) public returns (bool success)   



  •     {



  •         allowed[msg.sender][_spender] = _value;



  •         Approval(msg.sender, _spender, _value);



  •         return true;



  •     }







  •     function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {



  •         return allowed[_owner][_spender];                //允许_spender从_owner中转出的token数,也就是授权



  •     }



  •     mapping (address => uint256) balances;



  •     mapping (address => mapping (address => uint256)) allowed;



  • }






回复

使用道具 举报

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
 楼主| 发表于 2018-9-11 13:57:28 | 显示全部楼层
第五篇 在墨客区块链(MOAC BlockChain) 部署ERC-721合约
版权声明:Copyright Reserved © 2018-2020        https://blog.csdn.net/lyq13573221675/article/details/81109474



本文基于墨客区块链(MOAC BlockChain),使用moac网页版钱包部署ERC-721合约,实现相应数字化操作。

环境:

墨客区块链版本:nuwa-vnode1.0.2.win.zip

操作系统:64位Windows 10家庭版。


1.安装并启动本地节点

1.1 安装moac节点

请参考文档《第三篇 墨客区块链(MOAC BlockChain)节点安装教程》。

1.2 启动moac节点

打开命令终端(cmd),转到墨客当前目录,在命令行中执行:

D:\nuwa1.0.2.win>moac --rpc --rpccorsdomain "http://wallet.moac.io"

备注:

--rpc  启动RPC服务,本机访问节点

--rpccorsdomain  启动浏览器访问服务,非本机访问节点

"http://wallet.moac.io" moac在线钱包网址,会自动连接到本机启动的moac节点并显示已有账号,如果本机节点没有启动,会显示以下提示信息。

启动正常,会显示以下账号信息。确保其中一个账号有足够的moac以进行智能合约部署。


2.编写并编译智能合约

2.1 以下为基于erc-721编写的一个代币合约

本文实际测试代码TestToken721.sol附在文章末尾。

注意:该代码为测试实例使用,非标准部署智能合约代码。

2.2 编译、部署合约

在网页钱包点击合约按钮“CONTRACTS”

然后点击部署新合约按钮“DEPLOY NEW CONTRACT”

选择一个有moac余额的账号。

把自己编写的智能合约代码放进代码区“Solidity contract source code”,该代码会自动进行编译,如果编译通过,右侧会显示"Select contract to deploy"。

如果编译没有通过,则不会显示相应内容。

在“Select contract to deploy”下拉框选择相应的token类型,本例为“Token Demo”。

在选择gas费用后,点击"DEPLOY"部署合约。此时会显示发布合约确认界面。

如果提示需要解锁(部署智能合约的)账户,进入moac命令行界面,输入命令:

>personal.unlockAccount(mc.accounts[0], "passwd", 300)

该命令共有三个参数:

  • 第一个参数表示解锁的账户,
  • 第二个参数是该账户的密码,
  • 第三个参数是解锁时间,本例为300秒,300秒后会重新锁住账户;

如果解锁时间设为0,表示一直解锁,此时账号有风险,慎用。

为了隐藏密码,可以输入命令:

>personal.unlockAccount(mc.accounts[0]

回车后提示输入密码,此时密码不显示出来,该命令默认将账户解锁300秒。

成功解锁会返回true。此时会显示发布合约确认界面。

注意:Data里必须有数据,否则不能正常部署

点击“OK”,开始部署合约,界面下方会显示当前部署合约的进度条

进度条12区块确认,表示部署完毕。

点击成功部署的合约,可以看到基本内容,包括合约地址hash、被写入的区块号等。

登录moac区块链浏览器:http://explorer.moac.io/home。在tokens下拉框选择“View ERC721”。

在搜索栏输入合约地址,可以搜索到该合约的相应内容。

点击进去,可以看到合约基本信息、Token Transfers和Token Holders信息。

注意:该步骤可能需要已经有交易才能在浏览器查询。

至此,可以确认合约部署成功。


3.token的交易

3.1 查看合约状态

点击部署完毕的合约进度条上的“Token Demo (管理页面)”,进入合约管理界面。


管理界面的上半部分显示基本信息,顶部是合约地址,右边有通用功能按钮。主要包括:接收墨客和token、浏览器查看、拷贝地址、二维码和显示接口。

点击“显示接口”,跳出如下界面,显示“合约JSON接口”。提示如果有其他人需要管理或操作这个智能合约,则需要把接口内容连同合约地址一并发送给他。

管理界面的下半部分显示合约自身功能。

其中左边显示合约的读操作,本例中主要包括name、根据tokenID查询拥有者账户、根据账户查询余额等。

右边为对合约的写操作,简单理解就是合约中的public函数。

本例中,当前没有创建token,因此该合约中的721token数为0。

3.2 创建第一个erc721数字资产

本例中,创建token是一个写合约的操作,在右边select function下拉框选中“Create Token”,填入参数和拥有者地址,点击“EXECUTE”。

此处的参数property就是数据结构里的内容,用户可以根据自己的实际需要在合约里写入多个字段。


界面提示“transaction send”。

如果此处提示需要解锁账户,请参照前面的步骤执行解锁操作。

写入区块后,就可以在读操作界面进行查询了。如下图所示:

上图中,在index界面输入0,显示拥有该合约第一个721token(合约index编号从0开始,每次创建时,index编号自动递增)的地址。本例为主账户。

在owner中输入一个账号,自动显示该账号当前拥有的token数量。

3.3 交易erc721数字资产

本例中,发送token是一个写合约的操作,在右边select function下拉框选中“Transfer”,填入接收地址和发送的index编号,选择发送账户,点击“EXECUTE”。如果该账户拥有该token,则会发送成功;如果该账户不拥有该token,此处的操作也没有报错信息,只是不会有交易真实发生。

交易成功后,左边的合约读操作会自动更新。index编号为0的token有了新的拥有者,而之前的拥有者的token数量会自动减少1个,新的拥有者的数量会自动增加1个。

在主界面,将显示你的所有账户及它们所拥有的数字资产。

至此,一个典型的ERC-721智能合约部署完成。

ERC-721智能合约可以与实际生活中的唯一性资产对应,有着广阔的应用前景。


附件:

本文所用合约代码TestToken721.sol。

注意:该代码为测试实例使用,非通用智能合约代码。



  • pragma solidity ^0.4.16;







  • contract ERC721Token {



  •   //Non-fungible Token



  •   //与ERC20兼容的接口



  •   function balanceOf(address _owner) public constant returns (uint256 balance);  



  •   //所有权相关的接口



  •   function transfer(address _to, uint256 _token) public returns (bool success);  



  •   function transferFrom(address _from, address _to, uint256 _token) public returns (bool success);



  •   function approve(address _spender, uint256 _token) public returns (bool success);



  •   function allowance(address _owner, address _spender) public constant returns (uint256 remaining);  



  •   function ownerOf(uint256 _tokenId) public returns (address owner);  



  •   function tokensOfOwner(address _owner) public returns(uint256[] ownerTokens);  



  •   //元数据接口,可选



  •   function tokenMetadata(uint256 _tokenId) public constant returns (string infoUrl);  



  •   //事件



  •   event Transfer(address indexed _from, address indexed _to, uint256 _token);  



  •   event Approval(address indexed _owner, address indexed _spender, uint256 _token);







  • }







  • contract TokenDemo is ERC721Token {







  •   string  public name = "Test Token";   



  •   string  public symbol = "TEST";                 



  •   uint8   public decimals = 0;



  •   uint256 public INITIAL_SUPPLY = 100 * (10 ** uint256(decimals));  







  •   address minter;







  •   mapping (address => uint256) balances;



  •   mapping (address => mapping (address => uint256)) allowed;







  •   //token structure



  •   struct Token {                        //users can change structure for their dapp                               



  •       string property;     



  •   }







  •   Token[] tokens;







  •   mapping (uint256 => address) public tokenIndexToOwner;



  •   mapping (address => uint256) ownershipTokenCount;



  •   mapping (uint256 => address) public tokenIndexToApproved;  



  •   mapping (uint256 => string) tokenLinks;  //元数据,例如IPFS哈希或HTTP(S)链接







  •   function TokenDemo() public {



  •           minter = msg.sender;



  •   }







  •   //通证元数据接口



  •   function tokenMetadata(uint256 _tokenId) public constant returns (string infoUrl){



  •           return tokenLinks[_tokenId];



  •   }







  •   function getProperty(uint256 _tokenId) public returns (string property){



  •       return tokens[_tokenId].property;



  •   }







  •   function totalSupply() public returns (uint) {



  •       return tokens.length;



  •   }







  •   function ownerOf(uint256 _tokenId)  public returns (address owner) {



  •       owner = tokenIndexToOwner[_tokenId];



  •       require(owner != address(0));



  •   }







  •   function tokensOfOwner(address _owner) public returns(uint256[] ownerTokens) {



  •       uint256 tokenCount = balanceOf(_owner);







  •       if (tokenCount == 0) {



  •           return new uint256[](0);



  •       } else {



  •           uint256[] memory result = new uint256[](tokenCount);



  •           uint256 totalTokens = totalSupply();



  •           uint256 resultIndex = 0;







  •           uint256 tokenId;



  •           for (tokenId = 0; tokenId < totalTokens; tokenId++) {



  •               if (tokenIndexToOwner[tokenId] == _owner) {



  •                   result[resultIndex] = tokenId;



  •                   resultIndex++;



  •               }



  •           }



  •           return result;



  •       }



  •   }







  •   function _transfer(address _from, address _to, uint256 _tokenId) internal {



  •       ownershipTokenCount[_to]++;



  •       tokenIndexToOwner[_tokenId] = _to;



  •       if (_from != address(0)) {



  •           ownershipTokenCount[_from]--;



  •           delete tokenIndexToApproved[_tokenId];



  •       }







  •       Transfer(_from, _to, _tokenId);        // Emit the transfer event



  •   }







  •   function createToken(string _property, address _owner) public returns (uint) {        



  •           require(msg.sender == minter);                //only minter can create token               







  •       Token memory token = Token({



  •             property: _property



  •       });







  •       var newTokenId = tokens.push(token) - 1;



  •       require(newTokenId == uint256(uint32(newTokenId)));



  •       _transfer(0, _owner, newTokenId);



  •       return newTokenId;



  •   }







  •   function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {



  •       return tokenIndexToOwner[_tokenId] == _claimant;



  •   }







  •   function transfer(address _to, uint256 _tokenId) public returns (bool) {



  •       require(_to != address(0));



  •       require(_to != address(this));



  •       require(_owns(msg.sender, _tokenId));



  •       _transfer(msg.sender, _to, _tokenId);



  •   }







  •   function transferFrom(address _from, address _to, uint256 _tokenId) public returns (bool success) {



  •       require(_to != address(0));



  •       require(_to != address(this));



  •       require(_approvedFor(msg.sender, _tokenId));



  •       require(_owns(_from, _tokenId));



  •       _transfer(_from, _to, _tokenId);



  •   }







  •   function balanceOf(address _owner) public view returns (uint256 count) {



  •       return ownershipTokenCount[_owner];



  •   }







  •   function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) {



  •       return tokenIndexToApproved[_tokenId] == _claimant;



  •   }







  •   function _approve(uint256 _tokenId, address _approved) internal {



  •       tokenIndexToApproved[_tokenId] = _approved;



  •   }







  •   function approve(address _to, uint256 _tokenId) public returns (bool success) {



  •       require(_owns(msg.sender, _tokenId));



  •       _approve(_tokenId, _to);



  •       Approval(msg.sender, _to, _tokenId);



  •   }







  •   function allowance(address _owner, address _spender) public constant returns (uint256 remaining) {



  •       return allowed[_owner][_spender];



  •   }







  • }








回复

使用道具 举报

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
 楼主| 发表于 2018-9-11 13:58:14 | 显示全部楼层
第六篇 在墨客区块链(MOAC BlockChain) 测试网搭建子链
版权声明:Copyright Reserved © 2018-2020        https://blog.csdn.net/lyq13573221675/article/details/81125954


北京时间2018年6月30日,MOAC子链正式上线公测。

以下为MOAC 子链公测版安装及应用教程。


1. 准备工作

从MOAC版本发布页:

https://github.com/MOACChain/moac-core/releases

下载Windows版本的系统软件包pangu1.0.2.windows.zip

该版本适用于64位Windows 7及以上系统。本文实际操作环境为:64位Windows 10 中文版。

本文主要内容来自MOAC中文wiki。建议操作前浏览子链相关内容。网址:

https://github.com/delida/MoacDocs/wiki


2. 产生本地MOAC节点

解压系统软件包pangu1.0.2.windows.zip到本地硬盘。

安装节点到MOAC测试网。安装命令:

D:\nuwa1.0.2.win\vnode>moac --testnet

注意:在moac测试网,任何情形使用moac命令均需要加--testnet。

节点自动安装到目录:C:\Users\[user]\AppData\Roaming\MoacNode\testnet

墨客测试网区块高度可以通过墨客测试网区块浏览器查询。

浏览器网址:http://47.75.144.55:3000/home


3.节点基本操作

此节内容参考文档《第三篇 墨客区块链(MOAC BlockChain)节点安装教程》。

3.1 进入console界面

系统关机或主动关闭运行中的节点后,如果需要重新启动节点,在命令行中执行:

D:\nuwa1.0.2.win\vnode>moactestnet console

命令执行后,界面一直滚屏以同步区块数据。

3.2 进入attach界面

打开另一个命令(cmd)终端,转到当前目录,在命令行中执行:

D:\nuwa1.0.2.win\vnode>moactestnet attach

该命令依赖于节点已经启动,命令执行后不会主动滚屏,而是等待命令。

3.3 创建账号

进入MOAC console界面后,执行命令:

> personal.newAccount()

系统会在以下目录:C:\Users\[userName]\AppData\Roaming\MoacNode\testnet\keystore,记录一个账号文件。

请保存好该文件,并牢记密码。

3.4 挖矿

在测试网,可以尝试挖矿,用于之后操作的gas费,进入界面后,执行命令:

> miner.start()

停止挖矿,执行命令:

> miner.stop()

账号余额变动可以通过命令或者在墨客测试网区块浏览器查询。


4.scs注册

此处内容参考中文wiki内容《scs矿工参与方法》。

4.1 部署子链矿池

部署子链矿池智能合约,用于子链SCS节点矿工加入矿工池。

从MOAC版本发布页:

https://github.com/MOACChain/moac-core/releases

下载合约SubChainProtocolBase.sol。进行合约部署,部署前需要按以下方式启动节点:

D:\nuwa1.0.2.win\vnode>moac –testnet --rpc –rpccorsdomain "http://wallet.moac.io"

此处内容参考文档《第四篇 在墨客区块链(MOAC BlockChain)部署ERC-20合约》。

部署时选择“Sub Chain Protocol Base”,填入参数Protocol(POS)和Bmin(1),如图所示。

成功部署后

注意:该步骤非必须,可以直接加入测试网已经存在的矿工池。仅在受网络限制,本节点不能同步的情况下,才必须自己部署子链矿池。

该合约地址经测试工作正常,用户可以在后面的步骤将scs注册到该合约地址。

0x225Ebb0b9DF76E3D48eA0614943340611f635EA0

4.2 启动SCS

在下载的节点文件中,有一个scs目录。

在scs\config目录下有一个配置文件userconfig.json。其中的Beneficiary为矿工收益账号。为了安全起见,建议采用与scsid不同的墨客底层账号用来获取子链的收益(scsid将会在后面讲到)。

进入目录scs\scsserver启动scs:

D:\nuwa1.0.2.win\scs\scsserver>scsserver -p "123456123456"

命令中:“-p [密码]” scsid的密码,不设置,则默认密码为 moacscsofflineaccountpwd。

启动后,SCS将会在当前目录下生成一个keystore目录,并在目录中新建一个账号,这个账号就是scsid,可在第一次启动时使用-p设置密码。如果想换一个scsid,则需要删除keystore中的内容重新启动。

可以根据实际需要,按照以上步骤重新启动一个或多个scs。单台电脑建议启动不超过3个scs。

4.3 注册SCS

在启动scs并已经知道一个子链矿池合约地址的情况下(见4.1节),可以进行注册。

写一个scsRegister.js,代码如下。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));



  • //scs注册



  • console.log('SCS Register start!');



  • var baseAddr = "0x7610fd66c272332edd59a43460ad24eee1973bfe";



  • var basePasswd = "password";



  • var protocolAddr = "0x225Ebb0b9DF76E3D48eA0614943340611f635EA0";



  • var scsAddr = "755a37ec5ba302cd0022af2b8e3ff97c1996601b";    //不带0x开头



  • chain3.personal.unlockAccount(baseAddr, basePasswd,0);



  • sendtx(baseAddr, protocolAddr, '5','0x4420e486000000000000000000000000' + scsAddr);



  • function sendtx(src, tgtaddr, amount, strData) {



  •     chain3.mc.sendTransaction(



  •         {



  •             from: src,



  •             value:chain3.toSha(amount,’mc’),



  •             to: tgtaddr,



  •             gas: "9000000",



  •             gasPrice: chain3.mc.gasPrice,



  •             data: strData



  •         });



  •     console.log('sending from:' +   src + ' to:' + tgtaddr  + ' with data:' + strData);



  • }


主要参数如下:

  • baseAddr、basePasswd:主网的一个账户及其密码,付出本次交易的gas费及scs注册所需的押金(本例5mc);
  • protocolAddr:步骤4.1子链矿池合约subchainprotocolbase地址;
  • scsAddr:步骤4.2的scsid地址,放在“…/scsserver/scskeystore”目录下;
  • 注册mc数量,本例子中为5mc,此处必须大于矿池合约的设置值。scs提交押金越多,能参与的子链越多。

特别注意:scsAddr的地址不要加上“0x”。

在文件目录下执行该注册文件scsRegister.js:

D:\nuwa1.0.2.win\scs>node scsRegister.js

在等待一定时间之后(通常是母链50个block),就进入子链矿池,成为该子链的候选SCS节点。注册后,保证金会从baseAddr账号转到子链矿池合约账号。

注册时缴纳的保证金,将在SCS被选中服务子链的时候临时扣除。下图为注册两个SCS,各交2个mc保证金的情况。

4.4 给SCS地址转账

scs在跟底层vnode通信或被调用时,tx是需要交易费的,因此需要在scsid存入1个mc作为gas费。


4.5 查询SCS注册数量

如果是使用网页版钱包部署的子链矿池合约,可以直接在界面看到scs注册数量等信息。

或者,通过attach界面,使用合约地址查询注册scs数量

> mc.getStorageAt("0x225Ebb0b9DF76E3D48eA0614943340611f635EA0",0x02)


5.部署Vnode矿池合约

此处内容参考中文wiki内容《代理vnode节点介绍》。

5.1 部署vnode矿池

从MOAC版本发布页

https://github.com/MOACChain/moac-core/releases

下载合约VnodeProtocolBase.sol

部署时选择“Vnode Protocol Base”,填入参数Bmin(1)。如图所示。

成功后得到合约地址,用于后面vnode的注册。

注意:该步骤非必须,可以直接加入测试网已经存在的Vnode池子。仅在受网络限制,本节点不能同步的情况下,才必须自己部署Vnode池子。

该合约地址经测试工作正常,用户可以不必自己部署合约,在后面的步骤将Vnode节点注册到该合约地址。

0x0fB05e4a2b878855e27A7675135BecA0E257e896

5.2 添加节点到vnode矿池

添加本节点到vnode矿池的代码如下vnodeRegister.js,执行node即可。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));



  • //vnode register



  • var baseAddr = "0x7610fd66c272332edd59a43460ad24eee1973bfe";



  • var basePasswd = "123456123456";



  • var vnodeChain = "0x0fB05e4a2b878855e27A7675135BecA0E257e896";



  • var vnodeAddr = "7610fd66c272332edd59a43460ad24eee1973bfe";







  • chain3.personal.unlockAccount(baseAddr,basePasswd,0);



  • sendtx(baseAddr, vnodeChain, '2','0x32434a2e000000000000000000000000' + vnodeAddr //数据1



  •     +'0000000000000000000000000000000000000000000000000000000000000040'//数据2



  •     +'0000000000000000000000000000000000000000000000000000000000000013'//数据3



  •     //192.168.10.16:50062(填入本机实际IP地址值,并修改数据3和数据4)



  •     +'3139322e3136382e31302e31363a353030363200000000000000000000000000');//数据4







  • function sendtx(src, tgtaddr, amount, strData) {



  •     chain3.mc.sendTransaction(



  •         {



  •             from: src,



  •             value:chain3.toSha(amount,'mc'),



  •             to: tgtaddr,



  •             gas: "9000000",



  •             gasPrice: chain3.mc.gasPrice,



  •             data: strData



  •         });



  •     console.log('sending from:' +   src + ' to:' + tgtaddr  + ' with data:' + strData);



  • }


主要参数如下:

  • baseAddr、basePasswd:Dapp用户用来发送交易前账户解锁;
  • vnodeChain:部署VNODE-PROXY合约得到的合约地址;
  • vnodeAddr:vnodeconfig.json的VnodeBeneficialAddress
  • 数据1:'0x32434a2e '是VNODE-PROXY合约 中‘register(address vnode, string link)’通过hash算法Keccak256得到前4个字节,本例押金交2mc;本例带两个参数;

添加成功后,启动节点方式不变。

注意:该步骤非必须,也就是说并不是必须把本节点注册为proxy Vnode,可以直接加入测试网已经存在的Vnode矿工池,后面附有合约地址。仅在受网络限制,本节点不能同步的情况下,才必须自己部署vnode矿池并将本节点注册为proxy。


6.部署子链合约

此处内容参考中文wiki内容《DAPP用户的参与方法》。

6.1 编译子链合约

合约可以通过多种方式编译,比如在线编译工具remix等,如果是本地命令行编译,需要安装solidity环境。

D:\scs> solcjs --bin --abi -o bin SubChainBase.sol SubChainProtocolBase.sol

SubChainBase.sol是子链合约,其中import "./SubChainProtocolBase.sol";

因此要把SubChainProtocolBase.sol合约放在同一个目录下。

编译结果如果没有error,会在bin目录生成相应的*.bin和*.abi文件。

6.2 部署子链合约

部署子链合约的代码如下deploySubChain.js,执行node即可。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));



  • //deploy subChainBase



  • chain3.personal.unlockAccount(chain3.mc.accounts[0], '123456123456',0);



  • var proto = "0x225Ebb0b9DF76E3D48eA0614943340611f635EA0" ;



  • var vnodeProtocolBaseAddr = "0x0fB05e4a2b878855e27A7675135BecA0E257e896" ;



  • var min = 1 ;



  • var max = 10 ;



  • var thousandth = 1 ;



  • var flushRound = 20 ;



  • var subchainbaseContract = chain3.mc.contract([{"constant":true,......,"type":"event"}]);



  • var subchainbase = subchainbaseContract.new(



  •     proto,



  •     vnodeProtocolBaseAddr,



  •     min,



  •     max,



  •     thousandth,



  •     flushRound,



  •     {



  •         from: chain3.mc.accounts[0],



  •         data: '0x6060604052600c601555670d...708e8ee3c23da8b02d0278eb0029',



  •         gas: '9000000'



  •     }, function (e, contract){



  •         console.log(e, contract);



  •         if (typeof contract.address !== 'undefined') {



  •             console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);



  •         }



  •    })


子链控制合约subchainbase是DAPP用户使用子链的基本合约,其提供子链运行前和运行中的一些必要接口。

通常来说,子链控制合约subchainbase需要修改相应的内容如下:

  • 参数proto:通过官方渠道获取到,或者自己部署的子链矿池合约subchainprotocolbase的地址,复制粘贴到此变量;
  • 参数vnodeProtocolBaseAddr:通过官方渠道获取到,或者自己部署的代理智能合约vnodeprotocolbase的地址,复制粘贴到此变量;
  • 参数min:子链运行后需要的SCS的最小数量,建议数量为1;
  • 参数max:子链运行后需要的SCS的最大数量,建议数量为100;
  • 参数thousandth:默认为1;
  • 参数flushRound:子链刷新周期(以母链block生成数量为准),小于100的值,合约会自动置为100;
  • 合约部署时的gas值必须为9000000;
  • Chain3.mc.contract:其内容是6.1节编译结果的SubChainBase.abi;
  • data:其内容是6.1节编译结果的SubChainBase.bin,前面要加”0x”。

6.3 子链控制合约信息

部署成功后:

得到子链控制合约地址(0x8a194e9567d7339b968dac61546a52f89a8c7a2f)和本次交易hash。

6.4 子链开放注册

通过开放子链注册,候选SCS内部完成注册,最终成为子链的一员,才有资格参与子链的相关业务。 需要注意的是:SCS参与子链注册是通过SCS地址(我们也称为scsid,放在“./scskeystore”目录下)发送交易到子链完成;因此需要给SCS地址储备一定量的moac,建议1个moac。同时子链合约需要最终提供gas费给scs,因此,也需要给子链控制合约发送一定量的moac。

部署子链开放注册的代码如下registerOpen.js,执行node即可。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));



  • //register open



  • var dappAddr = "0x7610fd66c272332edd59a43460ad24eee1973bfe";



  • var dappPasswd = "123456123456";



  • var subchainAddr = "0x8a194e9567d7339b968dac61546a52f89a8c7a2f";//子链控制合约地址







  • chain3.personal.unlockAccount(dappAddr, dappPasswd,0);



  • sendtx(dappAddr, subchainAddr, '0','0x5defc56c' );







  • function sendtx(src, tgtaddr, amount, strData) {



  •     chain3.mc.sendTransaction(



  •          {



  •             from: src,



  •             value:chain3.toSha(amount,'mc'),



  •             to: tgtaddr,



  •             gas: "2000000",



  •             gasPrice: chain3.mc.gasPrice,



  •             data: strData



  •          });



  •     console.log('sending from:' +   src + ' to:' + tgtaddr  + ' with data:' + strData);  



  • }   


  • dappAddr、dappPasswd:Dapp用户用来发送交易前账户解锁;
  • subchainAddr:部署子链控制合约subchainbase的地址;
  • 数据:'0x5defc56c'是子链控制合约subchainbase中‘registerOpen()’通过hash算法Keccak256得到前4个字节,此处不用修改;

执行后:

6.5 查看注册情况

通过registerOpen后,系统将自动选择符合条件的SCS节点并通知他们进行注册,DAPP用户需要通过如下方法查看已经注册完成的SCS节点数目(nodeCount):

>mc.getStorageAt(subchainAddr,0x0e)

通过合约地址subchainAddr查询合约中第0x0e个public成员变量(即nodeCount)的值,请不要修改此值 当达到子链运行需要的SCS的数量区间后,即可进入RegisterClose步骤。

6.6 子链关闭注册

首先介绍一下RegisterClose的主要工作:

  • Dapp用户设置子链关闭注册;
  • 已经注册SCS数目必须不小于子链要求的最小数目,否则子链注册无效;
  • 主网广播通知所有的协议合约中候选SCS,包括已经注册的成功的SCS;
  • SCS收到广播后,SCS自身完成初始化并开始子链运行。

关闭子链注册后,候选SCS不能再通过subchain RegisterOpen方式注册该子链,已经注册的SCS处于正常运行状态,参与子链的相关业务,如:处理交易、出块、刷新等。

部署子链关闭注册的代码如下registerClose.js,执行node即可。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));



  • //register open



  • var dappAddr = "0x7610fd66c272332edd59a43460ad24eee1973bfe";



  • var dappPasswd = "123456123456";



  • var subchainAddr = "0x8a194e9567d7339b968dac61546a52f89a8c7a2f";//子链控制合约地址







  • chain3.personal.unlockAccount(dappAddr, dappPasswd,0);



  • sendtx(dappAddr, subchainAddr, '0','0x69f3576f' );







  • function sendtx(src, tgtaddr, amount, strData) {



  •     chain3.mc.sendTransaction(



  •          {



  •              from: src,



  •              value:chain3.toSha(amount,'mc'),



  •              to: tgtaddr,



  •              gas: "2000000",



  •              gasPrice: chain3.mc.gasPrice,



  •              data: strData



  •           });



  •     console.log('sending from:' +   src + ' to:' + tgtaddr  + ' with data:' + strData);



  • }   


其中,

  • dappAddr、dappPasswd:Dapp用户用来发送交易前账户解锁;
  • subchainAddr:部署子链合约得到的合约地址;
  • 数据:'0x69f3576f'是子链控制合约subchainbase中‘registerClose()’通过hash算法Keccak256得到前4个字节;

执行完毕,如果一切正常,子链建成并开始出块。实测环境中3个scs轮流出块,显示如下。

图中显示本scs出块正常,当前为子链第15个区块,由本scs挖矿出块成功。

如果是同步其他scs出的子链区块,“SendBkToVnode”显示为“Insert”。

至此,子链部署完成。




回复

使用道具 举报

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
 楼主| 发表于 2018-9-11 13:59:06 | 显示全部楼层
第七篇 墨客区块链(MOAC BlockChain) 开发环境搭建





版权声明:Copyright Reserved © 2018-2020        https://blog.csdn.net/lyq13573221675/article/details/81214015

本文介绍:构建基于墨客区块链的基础开发环境,面向nodejs,资深程序猿可以绕行。

本文实际操作环境为:64位Windows 10 中文版。

1.git安装

git是一种版本控制系统。github是一个网站,给用户提供git服务。

1.1 下载安装包

到官网:https://git-scm.com/download下载相应版本的安装包。

确定自己要下载的版本,点击下载即可。

1.2 安装git
下载完之后,双击应用程序,一路next即可完成安装。

1.3 配置环境变量

安装成功并配置后,可以在Git Bash或系统自带terminal使用git。

1.4 初次运行前配置

一般在新的系统上,我们都需要先配置下自己的 Git 工作环境。配置工作只需一次,以后升级时还会沿用现在的配置。当然,如果需要,你随时可以用相同的命令修改已有的配置。

Git 提供了一个叫做 git config 的工具,专门用来配置或读取相应的工作环境变量。而正是由这些环境变量,决定了 Git 在各个环节的具体工作方式和行为。

配置用户信息:

第一个要配置的是你个人的用户名称和电子邮件地址。这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录:



  • $ git config --global user.name "John Doe"



  • $ git config --global user.email johndoe@example.com


如果用了 --global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 --global选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。

查看配置信息:

$ git config --list

有时候会看到重复的变量名,那就说明它们来自不同的配置文件(比如 /etc/gitconfig 和 ~/.gitconfig),不过最终 Git 实际采用的是最后一个。

也可以直接查阅某个环境变量的设定,只要把特定的名字跟在后面即可,像这样:



  • $ git config user.name



  • John Doe


获取帮助:

想了解 Git 的各式工具该怎么用,可以阅读它们的使用帮助,方法有三:



  • $ git help <verb>



  • $ git <verb> --help



  • $ man git-<verb>


比如,要学习 config 命令可以怎么用,运行:

$ git help config

1.5 github安装

另一个简单的方法是安装 GitHub for Windows。

网址:http://windows.github.com

该安装程序包含图形化和命令行版本的 Git。


2.nodejs安装

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。
Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。

2.1 下载安装包

到官网:http://nodejs.cn/download/下载相应版本的安装包。

2.2 安装nodejs
下载完之后,双击应用程序,一路next即可完成安装。

新版的Node.js已自带npm(node package manager),安装Node.js时会一起安装。

npm的作用就是对Node.js依赖的包进行管理(包括安装、卸载、管理依赖等);

2.3 配置环境变量

第一项:配置的是npm安装的全局模块所在的路径,以及缓存cache的路径,之所以要配置,是因为以后在执行类似:

npm install express [-g]

的安装语句时,会将安装的模块默认安装到“C:\Users\AppData\Roaming\npm”路径中。

如果希望将全模块所在路径和缓存路径放在node.js安装的文件夹中,则在安装的文件夹“C:\Program Files\nodejs”下创建两个文件夹“node_global”和“node_cache”。

创建完两个空文件夹之后,打开cmd命令窗口,输入:



  • C:\>npm config set prefix "C:\Program Files\nodejs\node_global"



  • C:\>npm config set cache "C:\Program Files\nodejs\node_cache"


第二项:配置系统变量

在【系统变量】下的【Path】会自动添加“C:\ Program Files \nodejs”;

手动新增:“C:\Program Files\nodejs\node_global;”

进入环境变量对话框,在【系统变量】下新建【NODE_PATH】,输入

”C:\Program Files\nodejs\node_global\node_modules”

将【用户变量】下的【Path】值中的【C:\Users\Administrator\AppData\Roaming\npm】修改为【C:\Program Files\nodejs\node_global】,如果两项都已经存在,直接删除【C:\Users\Administrator\AppData\Roaming\npm】即可。

2.4 npm常用命令



  • -g               参数,全局安装(模块安装在系统变量NODE_PATH对应路径下)



  • -save            参数,将保存配置信息至package.jsonpackage.jsonnodejs项目配置文件);



  • -dev             参数,保存至package.jsondevDependencies节点,不指定-dev将保存至dependencies节点;







  • npm help         帮助



  • npm init         在项目中引导创建一个package.json文件,包括名称、版本、作者这些信息等



  • npm start        启动模块



  • npm stop         停止模块



  • npm publish      发布模块



  • npm ls           查看安装的模块



  • npm root         查看包的安装路径



  • npm uninstall <name> [-g] [-save] [-dev]     卸载插件



  • npm update <name> [-g] [-save] [-dev]        更新插件



  • npm update [-save] [-dev]                    更新全部插件



  • npm list                                     查看当前目录已安装插件



3.安装express

Express 是一个基于 Node.js 平台的极简、灵活的 web 应用开发框架,它提供一系列强大的特性,帮助你创建各种 Web 和移动设备应用。

相关内容请参考express官网。需要已经安装了Node.js。

C:\>npm install -g express

最新express4.0版本中将命令工具分家出来了(参考generator项目地址),所以还需要安装一个命令工具:

C:\>npm install -g express-generator@4

注意:“express”和“-genetator”之间没有空格。

查看版本及基本帮助:



  • C:\>express --version



  • C:\>express --help


创建Express项目。使用命令:

C:\>express -e nodeProject1

按照提示做三步:

第1步.进入目录(change directory)

>cd nodeProject1

第2步.安装依赖(install dependencies)

C:\>npm install

第3步.运行app(run the app)

C:\>SET DEBUG=nodeProject1:* & npm start

4.安装solidity编译环境

Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言。

目前尝试 Solidity 编程的最好的方式是使用 Remix。Remix 是一个基于 Web 浏览器的 IDE,它可以让你编写 Solidity 智能合约,然后部署并运行该智能合约。

不过,有时候也需要有本地的solidity编译环境。安装命令:



  • C:\>npm install -g solc             //默认安装最新版本



  • C:\>npm install -g solc@0.4.21      //安装指定版本


查看帮助:



  • C:\>solcjs --help                   //windows版本



  • $ solc --help                       //非windows版本


编译合约(windows环境):

C:\>solcjs --bin --abi -o bin testContract.sol

运行后,输出testContract.abi及testContract.bin到bin目录下,testContract.abi里边放的就是abi的内容,testContract.bin里边放的就是bytecode的内容。


5.安装chain3

墨客区块链当前提供JavaScript版本的API,安装方式:

5.1 Node.js

C:\>npm install chain3               //Node.js

5.2 Bower



  • C:\>npm install -g bower



  • C:\>bower install chain3             //As Browser module


5.3 Meteor.js

C:\>meteor add moaclib:chain3

根据自己的环境,选择合适的命令进行安装。


6.安装Python

在墨客区块链的开发中安装Python主要是环境的需要,并不是必须使用Python语言进行项目开发。在后面的文章中用到Python处都会有相应说明。

6.1 Python下载

Python最新源码,二进制文档,新闻资讯等可以在Python的官网查看到:

Python官网:https://www.python.org/

Python文档下载地址:https://www.python.org/doc/

6.2 Python安装

推荐安装Python的2.7版。

下载后,双击下载包,进入 Python 安装向导,只需要使用默认的设置一直点击"下一步"直到安装完成即可。

默认安装到:C:\Python27。

MAC 系统一般都自带有 Python2.x版本的环境,当然,你也可以在官网上下载最新版安装。

查看python版本:

C:\>python -V              //大写的参数“V”

6.3 配置环境变量

到系统变量的【path】里添加“C:\Python27”。


本文适用于本博客原创文章的开发环境需求。仅供参考。




回复

使用道具 举报

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
 楼主| 发表于 2018-9-11 13:59:39 | 显示全部楼层
第八篇 墨客区块链(MOAC BlockChain) 程序猿怎么部署和调用智能合约
版权声明:Copyright Reserved © 2018-2020        https://blog.csdn.net/lyq13573221675/article/details/81285250


在本博客《第四篇 在墨客区块链(MOAC BlockChain)部署ERC-20合约》和《第五篇 在墨客区块链(MOAC BlockChain)部署ERC-721合约》,已经有使用网页版钱包部署智能合约的方法。

本文基于墨客区块链(MOAC BlockChain),详细说明使用代码部署和调用智能合约的方法。

环境:

墨客区块链版本:nuwa-vnode1.0.2.win.zip

操作系统:64位Windows 10家庭版。


1.安装并启动本地节点

1.1 安装moac节点

请参考文档《第三篇 墨客区块链(MOAC BlockChain)节点安装教程》。

1.2 启动moac节点

打开命令终端(cmd),转到墨客当前目录,在命令行中执行:

D:\nuwa1.0.2.win>moac --rpc

确保本地节点中某个账号有足够的moac以进行智能合约部署和调用。


2.编写并编译智能合约

2.1 编写智能合约

本篇实际测试代码TestToken20.sol附在《第四篇 在墨客区块链(MOAC BlockChain)部署ERC-20合约》文章末尾,TestToken721.sol附在《第五篇 在墨客区块链(MOAC BlockChain)部署ERC-721合约》文章末尾。

修改20合约TestToken20.sol的参数部分,直接写入参数值。



  •     uint256 public totalSupply = 1000000;                //发行总量



  •     string  public name = "My test token";              //名称



  •     uint8   public decimals = 8;                               //返回token使用的小数点位数。



  •     string  public symbol = "MTT";                      //token简称


这样在部署的时候不需要导入参数。

注意:这些代码为测试实例使用,非标准部署智能合约代码。

2.2 使用本地solidity编译器编译合约

需要有本地的solidity编译环境。安装命令:



  • C:>npm install -g solc            //默认安装最新版本



  • C:>npm install -g solc@0.4.21     //安装指定版本


进入TestToken20.sol所在目录,编译合约:

C:>solcjs --bin --abi -o bin TestToken20.sol

运行后,输出TestToken20.abi及TestToken20.bin到bin目录下,TestToken20.abi里边放的就是abi的内容,TestToken20.bin里边放的就是bytecode的内容。

2.3 使用remix编译合约

Remix是一个开发Solidity智能合约的网络版开发软件。

登陆Remix 后,把中间的编辑框里的合约内容删除,然后把自己的合约代码复制到编辑框里。在右上角的菜单里Compile下面选中Auto Compile。

编译后会在右边区域显示是否有error、warning等信息。如果没有报错(Warning可以忽略),点击“Details”显示编译后详细信息。

可以得到跟2.2节一样的bytecode内容和abi内容。拷贝出来备用。

还有FUNCTIONHASHES,包含了本合约中的函数通过hash算法Keccak256得到前4个字节,调用合约时会用到。


3.部署智能合约

3.1 部署

部署智能合约文件deploy.js,内容如下:



  • var abiString = '[{"constant":true,"inputs":[],"name":"name",......"type":"event"}]';     //编译结果的abi



  • var bytecodeString = '606060405234801561001057600080fd5b5060......75fd0029';              //编译结果的bytecode



  • var account = {address:"0x745c57ca5318093115d61bbca368XXXXXXXXXXXX",secret:"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"};







  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));







  • createContract(chain3, account, abiString, bytecodeString);







  • function createContract(chain3, account, abiString, bytecodeString){



  •     var bytecode = "0x" + bytecodeString;



  •     var abi = JSON.parse(abiString);







  •     console.log('bytecode', bytecode);



  •     console.log('abi', abiString);







  •     var gasValue = chain3.mc.estimateGas({data: bytecode});



  •     console.log("gas estimate on contract:", gasValue);







  •     var address = account.address;



  •     var secret = account.secret;







  •     var txCount = chain3.mc.getTransactionCount(address);



  •     console.log("get tx account", txCount)







  •     var rawTx = {



  •         from: address,



  •         nonce: chain3.intToHex(txCount),



  •         gasPrice: chain3.intToHex(25000000000),



  •         gasLimit: chain3.intToHex(400000),



  •         data: bytecode,



  •         chainId: chain3.version.network,



  •     };







  •     var signedTx = chain3.signTransaction(rawTx, account.secret);







  •     console.log("send signed tx:", signedTx);



  •     console.log("len", signedTx.length);







  •     chain3.mc.sendRawTransaction(signedTx, function(err, hash) {



  •         if (!err){



  •             console.log("succeed: ", hash);



  •         }else{



  •             console.log("error:", err.message);



  •         }



  •     });



  • }


代码中的account是本地节点的一个账号,需要付出本次部署智能合约的gas费。部署后的合约也归该账号所有。

合约部署完成后,如果没有报错,会返回一个hash值,通过这个hash值到浏览器可以查询到本次合约部署的详细信息。

或者通过节点命令得到相应信息。

>mc.getTransactionReceipt("transactionHash")

3.2 从keystore得到privateKey

本节中部署智能合约时,代码使用sendRawTransaction需要私钥签名,得到本地节点账号的私钥有两种方式:

  • 方式一:使用“keystore + password”的方式将账号导入手机版钱包TokenPocket,然后导出私钥。
  • 方式二:使用如下代码getPrivateKey.js得到本地节点账号的私钥。


  • var keythereum = require("keythereum");



  • var datadir = "C:\\Users\\lyq2018\\AppData\\Roaming\\MoacNode";  //moacnode目录,根据实际修改



  • //var datadir = "/Users/gm/Library/MoacNode";                    //苹果mac系统moacnode目录,根据实际修改



  • var address= "0x68986c1bcd54ae5dae69310XXXXXXXXXXXXXXXXX";       //本地节点账号,根据实际修改



  • const password = "password";                                     //账号密码,根据实际修改







  • var keyObject = keythereum.importFromFile(address, datadir);



  • var privateKey = keythereum.recover(password, keyObject);        //输出私钥



  • console.log(privateKey.toString('hex'));


代码运行需要nodejs和python2.7环境,同时需要导入keythereum。

c:\>npm install -g keythereum

3.3 从privateKey得到keystore

有时候用户会需要从私钥导出keystore用于节点,此时得到本地节点账号的keystore有两种方式:

  • 方式一:使用“私钥”的方式将账号导入手机版钱包TokenPocket,然后导出为keystore。
  • 方式二:使用如下代码getKeystore.js得到本地节点账号的keystore。


  • var Wallet = require('ethereumjs-wallet');



  • var privateKey = 'bb673026deda3c3cd0c63f6ccddfb02a7ae320078aa8XXXXXXXXXXXXXXXXXXXX';



  • var key = Buffer.from(privateKey, 'hex');



  • var wallet = Wallet.fromPrivateKey(key);







  • wallet.toV3String('password');



  • console.log("Get keystore", wallet.toV3String('password'));


代码运行需要nodejs和python2.7环境,同时需要导入ethereumjs-wallet。

c:\>npm install -g ethereumjs-wallet

安装时如果报类似“npm ERR! Unexpected end of JSON input while parsing near......”的错,可以先清理缓存再安装。

c:\>npm cache clean --force

4.调用智能合约

以下为TestToken20.sol的调用代码,call_erc20.js。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));







  • var contractAddress = "0xA2580D58A58998ca06e6f5b2A96AXXXXXXXXXXXX";                       //智能合约地址



  • var address = "0x68986c1BCD54Ae5dAe69310fC64EXXXXXXXXXXXX";



  • var account = {address:"0x68986c1BCD54Ae5dAe69310fC64XXXXXXXXXXXX",secret:"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"};



  • var abiString = '[{"constant":true,"inputs":[],"name":"name",......"type":"event"}]';     //智能合约的abi







  • //调用erc20合约



  • //基本属性



  • callContract1(chain3, contractAddress, address, abiString);







  • function callContract1(chain3, contractAddress, address, abiString){



  •     var abi = JSON.parse(abiString);



  •     var contract = chain3.mc.contract(abi);



  •     var token = contract.at(contractAddress);







  •     console.log(JSON.stringify(token.totalSupply()));      //总量



  •     console.log(JSON.stringify(token.name()));             //名称



  •     console.log(JSON.stringify(token.decimals()));         //位数



  •     console.log(JSON.stringify(token.symbol()));           //简称



  • }







  • //调用erc20合约



  • //通过abi生成智能合约对象, 直接通过对应合约方法进行call调用



  • //查询余额



  • callContract2(chain3, contractAddress, address, abiString);







  • function callContract2(chain3, contractAddress, address, abiString){



  •     var abi = JSON.parse(abiString);



  •     var contract = chain3.mc.contract(abi);



  •     var token = contract.at(contractAddress);



  •     token.balanceOf.call(address, function(err, result){



  •         console.log(err, JSON.stringify(result));



  •     });



  • }







  • //调用erc20合约



  • //通过对交易签名进行调用



  • //发送代币



  • var amount = 100;                                                       //发送数量



  • var anotherAddress = "0x745c57ca5318093115d61bbca3687ca02cxxxxxx";      //接收地址



  • callContract3(chain3, contractAddress, account, abiString, anotherAddress, amount);







  • function callContract3(chain3, contractAddress, account, abiString, anotherAddress, amount){



  •     var address = account.address;



  •     var abi = JSON.parse(abiString);



  •     var contract = chain3.mc.contract(abi);



  •     var token = contract.at(contractAddress);







  •     var data = token.transfer.getData(anotherAddress, amount);



  •     console.log('data', data);



  •     var txCount = chain3.mc.getTransactionCount(account.address);



  •     var rawTx = {



  •         nonce: chain3.intToHex(txCount),



  •         gasPrice: chain3.intToHex(25000000000),



  •         gasLimit: chain3.intToHex(100000),



  •         to: contractAddress,



  •         data: data,



  •         chainId: chain3.version.network



  •     };



  •     var signedTx = chain3.signTransaction(rawTx, account.secret);



  •     chain3.mc.sendRawTransaction(signedTx, function(err, hash) {



  •         if (!err){



  •             console.log("succeed: ", hash);



  •             var filter = chain3.mc.filter('latest');



  •             filter.watch(function(error, result) {



  •                 var receipt = chain3.mc.getTransaction(hash);



  •                 if (!error && receipt && receipt.blockNumber != null) {



  •                     console.log("done.");



  •                     filter.stopWatching();



  •                     process.exit(0);



  •                 }



  •             });



  •         }else{



  •             console.log("error:", err.message);



  •         }



  •     });



  • }


以上代码三个调用实例的函数分别为callContract1、callContract2、callContract3;可以根据需要单独或组合使用。


以下为TestToken721.sol的调用代码,call_erc721.js。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));







  • var contractAddress = "0xA2580D58A58998ca06e6f5b2A96AXXXXXXXXXXXX";                       //智能合约地址



  • var address = "0x68986c1BCD54Ae5dAe69310fC64EXXXXXXXXXXXX";



  • var account = {address:"0x68986c1BCD54Ae5dAe69310fC64XXXXXXXXXXXX",secret:"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"};



  • var abiString = '[{"constant":true,"inputs":[],"name":"name",......"type":"event"}]';     //智能合约的abi







  • //调用erc721合约



  • //读合约



  • callContract(chain3, contractAddress, address, abiString);







  • function callContract(chain3, contractAddress, address, abiString){



  •     var abi = JSON.parse(abiString);



  •     var contract = chain3.mc.contract(abi);



  •     var token = contract.at(contractAddress);



  •     var tokenID = 5;                //从0开始的编号







  •     //输出721 token的name



  •     token.name.call(function(err, result){



  •         console.log(err, JSON.stringify(result));



  •     });







  •     //输出balance



  •     token.balanceOf.call(address, function(err, result){



  •         console.log( "721 getBalanceof",err, JSON.stringify(result));



  •     });







  •     //输出该tokenID的属性



  •     token.getProperty.call(tokenID, function(err, result){



  •         console.log( "721 getTitle",err, JSON.stringify(result));



  •     });       







  •     //输出tokenID的拥有者



  •     token.ownerOf.call(tokenID, function(err, result){



  •         console.log( "721 ownerOf",err, JSON.stringify(result));



  •     });







  •     //输出某个地址拥有的所有tokenID



  •     token.tokensOfOwner.call(address, function(err, result){



  •         console.log( "721 tokensOfOwner",err, JSON.stringify(result));



  •     });       



  • }







  • //调用erc721合约



  • //创建721token



  • callContract1(chain3, account, contractAddress, address, abiString)







  • function callContract1(chain3, account, contractAddress, address, abiString){



  •     var abi = JSON.parse(abiString);



  •     var contract = chain3.mc.contract(abi);



  •     var token = contract.at(contractAddress);







  •     console.log('data', token.createToken.getData("property",address));    //导入token的属性



  •     var privateKey = new Buffer(account.secret, "hex");



  •     var txCount = chain3.mc.getTransactionCount(account.address);



  •     var rawTx = {



  •         nonce: chain3.intToHex(txCount),



  •         gasPrice: chain3.intToHex(25000000000),



  •         gasLimit: chain3.intToHex(400000),



  •         to: contractAddress,



  •         data: token.createToken.getData("property",address),



  •         chainId: chain3.version.network,



  •     };







  •     var signedTx = chain3.signTransaction(rawTx, account.secret);



  •     chain3.mc.sendRawTransaction(signedTx, function(err, hash) {



  •         if (!err){



  •             console.log("succeed: ", hash);



  •         }else{



  •             console.log("error:", err.message);



  •         }



  •     });



  • }







  • //调用erc721合约



  • //发送721token



  • var tokenID = 100;                                                      //721token编号



  • var anotherAddress = "0x745c57ca5318093115d61bbca3687ca02cxxxxxx";      //接收地址



  • callContract2(chain3, account, contractAddress, anotherAddress, tokenID, abiString)







  • function callContract2(chain3, account, contractAddress, anotherAddress, tokenID, abiString){



  •     var abi = JSON.parse(abiString);



  •     var contract = chain3.mc.contract(abi);



  •     var token = contract.at(contractAddress);







  •     console.log('data', token.transfer.getData(anotherAddress,tokenID ));



  •     var privateKey = new Buffer(account.secret, "hex");



  •     var txCount = chain3.mc.getTransactionCount(account.address);



  •     var rawTx = {



  •         nonce: chain3.intToHex(txCount),



  •         gasPrice: chain3.intToHex(25000000000),



  •         gasLimit: chain3.intToHex(400000),



  •         to: contractAddress,



  •         data: token.transfer.getData(anotherAddress,tokenID ),



  •         chainId: chain3.version.network,



  •     };







  •     var signedTx = chain3.signTransaction(rawTx, account.secret);



  •     chain3.mc.sendRawTransaction(signedTx, function(err, hash) {



  •         if (!err){



  •             console.log("succeed: ", hash);



  •         }else{



  •             console.log("error:", err.message);



  •         }



  •     });



  • }







  • //调用721合约的时候



  • //得到所有拥有该721token的地址



  • var tokenNow = 0;    //tokenID从该编号开始,必须 >= 0



  • var tokenMax = 8;    //tokenID到该编号结束,必须已经create token到该编号



  • callContract3(tokenNow, chain3, contractAddress, address, abiString);







  • function callContract3(tokenNow, chain3, contractAddress, address, abiString){



  •     var abi = JSON.parse(abiString);



  •     var contract = chain3.mc.contract(abi);



  •     var token = contract.at(contractAddress);  



  •     //console.log("以下输出721合约的owner:");



  •     token.ownerOf.call(tokenNow, function(err, result){



  •         console.log( "721 ownerOf",tokenNow,err, JSON.stringify(result));



  •     });



  •     //通过tokenID循环



  •     if (tokenNow < tokenMax){



  •         allContract3(tokenNow+1, chain3, contractAddress, address, abiString);



  •     }       



  • }






回复

使用道具 举报

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
 楼主| 发表于 2018-9-11 14:00:06 | 显示全部楼层
第九篇 墨客区块链(MOAC BlockChain) 怎么发mc
版权声明:Copyright Reserved © 2018-2020        https://blog.csdn.net/lyq13573221675/article/details/81329107


本文中mc是指墨客区块链的底层COIN,在墨客区块链上主要用来支付交易手续费和作为运算服务的媒介。

1.通过手机版钱包发mc

登录手机版钱包TokenPocket官网,下载相应版本的客户端,并安装。

1.1 创建钱包

进入TP钱包,点击最下面的菜单“我”,进入“个人中心”。

选择“管理钱包”,选择“创建钱包”或“导入钱包”,“钱包体系”选择“墨客”。

在输入钱包名称和钱包密码后会创建一个新的墨客底层钱包。

1.2 发送和接收mc

进入一个墨客底层钱包。界面显示该钱包所拥有的资产。

点击“转账”可以发送mc,点击“收款”接收mc。


2.使用网页版钱包发mc

使用网页版钱包发mc需要节点。节点安装参考《第三篇 墨客区块链(MOAC BlockChain)节点安装教程》。

节点启动命令:

D:\nuwa1.0.2.win>moac --rpc --rpccorsdomain "http://wallet.moac.io"

登录网页版钱包:http://wallet.moac.io/

如果本地节点有账号,并且账号里有mc。点击界面“发送”。

输入“接收地址”、“发送数量”、选择发送“MC”,选择手续费后点击按钮“发送”。

发送前需要在节点解锁发送账号。

>personal.unlockAccount(mc.accounts[0], "passwd", 300)

发送成功,通常可以马上查看到mc数量的变化情况。


3.使用节点[Send]命令发mc

使用节点[Send]发mc需要本地节点。节点安装参考《第三篇 墨客区块链(MOAC BlockChain)节点安装教程》。

节点启动后,另开一个cmd窗口进入attach界面。

D:\nuwa1.0.2.win>moac attach

需要本地节点至少有一个有mc的账号。

Send函数封装在mctest.js里,因此需要先load。

>loadScript("mctest.js")

使用Send发mc命令如下:

> Send(mc.accounts[0], 'passwd', mc.accounts[1], 0.1)

这个过程中,mc.accounts[0]是发送账号,mc.accounts[1]是接收账号,'passwd'是第一个账号的密码,发送额为0.1 mc。

发送mc通常在下一个区块产生时完成。

通过命令可以查看到本地所有账号余额变化情况:

>checkBalance()

4.使用代码发mc

在节点文件夹的mctest.js里有Send函数,可以直接拿来嵌入代码,发送mc。

4.1 Send函数



  • function sendtx(src, tgtaddr, amount, strData) {               



  •     chain3.mc.sendTransaction(



  •         {



  •             from: src,



  •             value:chain3.toSha(amount,'mc'),



  •             to: tgtaddr,



  •             gas: "22000",//min 1000



  •             gasPrice: chain3.mc.gasPrice,



  •             data: strData



  •         }, function (e, transactionHash){



  •             if (!e) {



  •                 console.log('Transaction hash: ' + transactionHash);



  •             }



  •         });               



  •     console.log('sending from:' +         src + ' to:' + tgtaddr  + ' amount:' + amount + ' with data:' + strData);



  • }







  • //Send function unlock the source account and



  • //send the input value to the target account



  • function Send(src, passwd, target, value){



  •     chain3.personal.unlockAccount(src, passwd, 0);



  •     sendtx(src, target, value, '' );       



  • }


这段代码需要personal.unlockAccount,因此节点启动方式为:

D:\nuwa1.0.2.win>moac --rpc --rpcapi="db,mc,net,chain3,personal,debug"

4.2 给多个地址自动发送mc

在4.1节代码的基础上,尝试实现给多个地址发送mc。

首先设计一个excel文件,保存接收mc的地址及每个地址的数量。命名为test.xlsx。

本实例用到address和amount。id和name不在代码里使用,仅用于文档记录。

这段代码需要personal.unlockAccount,因此节点启动方式为:

D:\nuwa1.0.2.win>moac --rpc --rpcapi="db,mc,net,chain3,personal,debug"

代码文件sendMoac.js。node执行即可。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));







  • var xlsx = require('node-xlsx');



  • var fs = require('fs');







  • //发送mc地址



  • var address_from = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";



  • var password_from = "password";                //发送地址密码







  • //主要参数



  • var interval = 2;                        //发送一笔交易的间隔时间,秒



  • var address_to = "";                        //接收地址,从test.xlsx得到



  • var amount = 0.0;                        //发送额度,从test.xlsx得到







  • //读取文件内容



  • var obj = xlsx.parse(__dirname+'/test.xlsx');



  • var excelObj=obj[0].data;



  • //console.log(excelObj);







  • var data = [];



  • for(var i in excelObj){



  •     var arr=[];



  •     var value=excelObj;                //记录循环



  •     //console.log(i,"  ",value);       







  •     if (i > 0){



  •         //以下每隔2秒,发送一次墨客



  •         sleep(interval * 1000);



  •         address_to = value[2];



  •         amount = value[3];



  •         console.log(i,"  ",address_to,"  ",amount);



  •         Send(address_from,password_from,address_to,amount);



  •     }







  •     for(var j in value){                //每一条记录内容



  •         arr.push(value[j]);



  •         //console.log(j,"  ",value[j]);



  •     }



  •     data.push(arr);



  • }







  • var buffer = xlsx.build([



  •     {



  •         name:'sheet1',



  •         data:data



  •     }        



  • ]);







  • //将文件内容插入新的文件中,根据实际需要使用



  • fs.writeFileSync((new Date).toLocaleDateString()+'-'+(new Date).getTime()+'-'+'test.xlsx',buffer,{'flag':'w'});







  • //自己写的休眠函数



  • function sleep(numberMillis) {                                



  •     var now = new Date();



  •     var exitTime = now.getTime() + numberMillis;



  •     while (true) {



  •         now = new Date();



  •         if (now.getTime() > exitTime)



  •         return;



  •     }



  • }







  • function sendtx(src, tgtaddr, amount, strData) {               



  •     chain3.mc.sendTransaction(



  •         {



  •             from: src,



  •             value:chain3.toSha(amount,'mc'),



  •             to: tgtaddr,



  •             gas: "22000",//min 1000



  •             gasPrice: chain3.mc.gasPrice,



  •             data: strData



  •         }, function (e, transactionHash){



  •             if (!e) {



  •                 console.log('Transaction hash: ' + transactionHash);



  •             }



  •         });               



  •     console.log('sending from:' +         src + ' to:' + tgtaddr  + ' amount:' + amount + ' with data:' + strData);



  • }







  • //Send function unlock the source account and



  • //send the input value to the target account



  • function Send(src, passwd, target, value)



  • {



  •     chain3.personal.unlockAccount(src, passwd, 0); //启动节点的时候需要包含personal



  •     sendtx(src, target, value, '' );       



  • }



5.使用私钥签名发mc

该方法的主要优点是安全。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));







  • var address = "0x745c57ca5318093115d61bbca368XXXXXXXXXXXX";



  • var account = {address:"0x745c57ca5318093115d61bbca368XXXXXXXXXXXX",secret:"bb673026deda3c3cd0c63f6ccddfb02a7ae320078aa8XXXXXXXXXXXXXXXXXXXX"};







  • var toAddress = "0x68986c1bcd54ae5dae69310fc64eXXXXXXXXXXXX";



  • var amount = 0.002;







  • send(chain3, account.address, account.secret, toAddress, amount, txCount = -1)







  • function send(chain3, fromAddress, fromSecret, toAddress, amount, txCount = -1){



  •     var mc = chain3.mc;







  •     var txcount = txCount >= 0 ? txCount : chain3.mc.getTransactionCount(fromAddress);



  •     console.log("Get tx account", txcount);







  •     var gasPrice = 25000000000;



  •     var gasLimit = 100000;



  •     var value = chain3.toSha(amount, 'mc');



  •     var gasTotal = gasPrice * gasLimit + Number(value);



  •     console.log(gasPrice, gasLimit, value, chain3.fromSha(gasTotal, 'mc'));







  •     var rawTx = {



  •         from: fromAddress,



  •         to: toAddress,



  •         nonce: chain3.intToHex(txcount),



  •         gasPrice: chain3.intToHex(gasPrice),



  •         gasLimit: chain3.intToHex(gasLimit),



  •         value: chain3.intToHex(value),



  •         shardingFlag: 0,



  •         chainId: chain3.version.network



  •     };







  •     var signedTx = chain3.signTransaction(rawTx, fromSecret);



  •     mc.sendRawTransaction(signedTx, function(err, hash) {



  •         if (!err){



  •             console.log("succeed: ", hash);



  •             return hash;



  •         }else{



  •             console.log("error:", err);



  •             console.log('raw tx:', rawTx);



  •         }



  •     });



  • }


代码使用sendRawTransaction时需要私钥签名,得到本地节点账号的私钥方法见:

本博客《第八篇 墨客区块链(MOAC BlockChain) 程序猿怎么部署和调用智能合约》的第三节“3.部署智能合约”。




回复

使用道具 举报

646

主题

1012

帖子

3669

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3669
 楼主| 发表于 2018-9-11 14:00:32 | 显示全部楼层
第十篇 墨客区块链(MOAC BlockChain) 如何将自定义数据写到区块链中
2018年08月02日 10:42:49 阅读数:702 标签:




版权声明:Copyright Reserved © 2018-2020        https://blog.csdn.net/lyq13573221675/article/details/81354458

区块链的一个显著特点是,数据一旦写入链中,就不可篡改重写。

在墨客区块链中,每一笔交易(transaction),都有一个保存数据的data空间,本文主要讲解如何将自定义数据(可以是一句话、一篇文章等)写入区块链的交易中,并读取出来。

当然,保存数据到区块链是会消耗gas费的,且gas费跟数据量是正相关的。

本文内容不适用于有强逻辑性和关系型的大数据存储。

1.做一笔交易,将数据写入区块链

该笔交易没有发送mc,或者其他token,仅将数据写到区块链。

代码文档sendData.js如下:



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));







  • var address = "0x745c57ca5318093115d61bbca368XXXXXXXXXXXX";



  • var account = {address:"0x745c57ca5318093115d61bbca368XXXXXXXXXXXX",secret:"bb673026deda3c3cd0c63f6ccddfb02a7aXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"};







  • send(chain3, account.address, account.secret, txCount = -1);







  • function send(chain3, fromAddress, fromSecret, txCount = -1){



  •   var mc = chain3.mc;



  •   var txcount = txCount >= 0 ? txCount : chain3.mc.getTransactionCount(fromAddress);



  •   console.log("Get tx account", txcount);







  •   var gasPrice = 25000000000;



  •   var gasLimit = 100000;



  •   var gasTotal = gasPrice * gasLimit;



  •   console.log(gasPrice, gasLimit, chain3.fromSha(gasTotal, 'mc'));







  •   //以下为写入数据log



  •   let log = {



  •     timenew Date).getTime(),



  •     type:"info",



  •     msg:"Hello MOAC!!!"



  •   };



  •   //转换log数据格式



  •   let str = JSON.stringify(log);



  •   console.log(str);



  •   let data = Buffer.from(str).toString('hex');



  •   data = '0x'+data;



  •   console.log(data);  







  •   var rawTx = {



  •     from: fromAddress,



  •     nonce: chain3.intToHex(txcount),



  •     gasPrice: chain3.intToHex(gasPrice),



  •     gasLimit: chain3.intToHex(gasLimit),



  •     data: data ,



  •     shardingFlag: 0, //default is global contract



  •     chainId: chain3.version.network



  •   };







  •   var signedTx = chain3.signTransaction(rawTx, fromSecret);



  •   mc.sendRawTransaction(signedTx, function(err, hash) {



  •       if (!err){



  •           console.log("succeed: ", hash);



  •           return hash;



  •       }else{



  •           console.log("error:", err);



  •           console.log('raw tx:', rawTx);



  •       }



  •   });



  • }


代码使用sendRawTransaction时需要私钥签名,得到本地节点账号的私钥方法见:

第八篇 墨客区块链(MOAC BlockChain) 程序猿怎么部署和调用智能合约》的第三节“3.部署智能合约”。

直接node,运行结果如下:

返回信息中包含:

本次交易写入数据“Hello MOAC!!!”及其十六进制表示。

本次交易的hash值:0x7834667df3890d0a4bc2fc949d45206fec8fe4b63853181dd9cc20c1b6c009dc。

浏览器查询hash:

其中的Input Data就是本次交易写入的数据。与node sendData.js时显示的hex格式数据内容一致。


2.查看区块链里的数据字段

当前,每笔交易里的数据在浏览器还显示为hex。因此需要自己写代码解读出其中的内容。

读数据代码callData.js如下:



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));  //设置API访问moac节点方式







  • //获取交易信息



  • hash = "0x7834667df3890d0a4bc2fc949d45206fec8fe4b63853181dd9cc20c1b6c009dc";



  • var receipt = chain3.mc.getTransaction(hash);



  • console.log('get transaction from hash  :'+ JSON.stringify(receipt));







  • console.log();



  • //获取交易内保存的数据data,需要提前写入



  • hash = "0x7834667df3890d0a4bc2fc949d45206fec8fe4b63853181dd9cc20c1b6c009dc";



  • chain3.mc.getTransaction(hash,function(error, result){



  •     //console.log(result);



  •     inputData = result.input;



  •     res_str = Buffer.from(inputData.replace('0x',''),'hex').toString();



  •     res_json = JSON.parse(res_str);



  •     console.log('your data :',res_json);



  •     console.log('your msg  :',res_json.msg);



  • });


直接node,运行结果如下:

通过交易hash得到交易的所有信息,并分析出data数据。


3.将数据批量写入区块链

结合对excel表格的读写操作,可以简单地将批量数据写入到区块链中去。

首先设计一个excel文件,保存要写到区块链的数据。命名为testMessage.xlsx。

本实例用到message。id和name不在代码里使用,仅用于文档记录。time用于返回时间,在成功后会新建一个文件,返回每次信息发送的时间。

代码文件goMessage.js。node执行即可。

注意:1. 将数据上链的交易会收取gas费,且收取的费用跟数据大小正相关;
           2. 该代码里包含手动设置nounce完成tx的实例。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));







  • //通过node-xlsx读取的excel文件就是一个json数据



  • var xlsx = require('node-xlsx');    //定义xlsx,自行npm install node-xlsx



  • var fs = require('fs');             //定义fs,自行npm install fs







  • var address = "0x745c57ca5318093115d61bbca36XXXXXXXXXXXX";



  • var account = {



  •     address: "0x745c57ca5318093115d61bbca36XXXXXXXXXXXX",



  •     secret: "bb673026deda3c3cd0c63f6ccddfb02a7ae320078aa8XXXXXXXXXXXXXXXXXXXX"



  • };







  • //主要参数



  • var thisTxCount = -1;               //nounce值,本例手动设置,初始为-1,读取实际值后,每次自增1



  • var interval = 2;                   //发送一次信息的间隔时间,秒



  • var message = "Hello MOAC!!!";      //定义要发送的信息,从cxcel文件读取







  • var obj = xlsx.parse(__dirname + '/testMessage.xlsx');//配置excel文件的路径



  • var excelObj = obj[0].data;         //obj.data表示excel文件第i+1个sheet文档的全部内容







  • var data = [];



  • var promiseList = [];               //用于异步返回



  • for (var i in excelObj) {



  •     var arr = [];



  •     if (i > 0) {                    //数据从第二行开始,通常在excel中第一行(i=0)就是每一列的title



  •         sleep(interval * 1000);     //每隔2秒,发送一次信息



  •         message = excelObj[2];   //得到要发送的信息内容



  •         excelObj[3] = (new Date).toLocaleString();  //记录发送交易的时间



  •         promiseList.push(send(chain3, account.address, account.secret, message, thisTxCount, i));               



  •     }



  • }







  • Promise.all(promiseList).then(function (objList) {  //所有异步完成后回调



  •     //遍历objList



  •     objList.forEach(item=>{



  •         excelObj[item.index][4] = item.hash;        //记录发送交易的哈希



  •     })



  •     var buffer = xlsx.build([



  •         {



  •             name: 'sheet1',



  •             data: excelObj



  •         }



  •     ]);



  •     //创建新文件,将发送时间等记录到文件中



  •     fs.writeFileSync((new Date).toLocaleDateString() + '-' + (new Date).getTime() + '-' + 'hadSendMessage.xlsx', buffer, {'flag': 'w'});



  • });







  • //自己写的休眠函数



  • function sleep(numberMillis) {



  •     var now = new Date();



  •     var exitTime = now.getTime() + numberMillis;



  •     while (true) {



  •         now = new Date();



  •         if (now.getTime() > exitTime)



  •             return;



  •     }



  • }







  • function send(chain3, fromAddress, fromSecret, message, txCount = -1, index) {



  •     var mc = chain3.mc;



  •     var txcount = txCount >= 0 ? txCount : chain3.mc.getTransactionCount(fromAddress);//获取nounce值



  •     //console.log("Get tx account", txcount);



  •     thisTxCount = txcount + 1;        //手动设置nounce,每次自增1







  •     var gasPrice = 25000000000;



  •     var gasLimit = 100000;            //数据量越大,gas费应该设置得越高



  •     var gasTotal = gasPrice * gasLimit;



  •     //console.log(gasPrice, gasLimit, chain3.fromSha(gasTotal, 'mc'));







  •     //以下为写入数据log



  •     let log = {



  •         time: (new Date).getTime(),   //获取当前时间(从1970.1.1开始的毫秒数)



  •         type: "info",



  •         msg: message



  •     };



  •     //转换log数据格式,将数据转换为16进制字符串



  •     let str = JSON.stringify(log);



  •     console.log(str);



  •     let data = Buffer.from(str).toString('hex');



  •     data = '0x' + data;



  •     console.log(data);







  •     var rawTx = {



  •         from: fromAddress,



  •         nonce: chain3.intToHex(txcount),



  •         gasPrice: chain3.intToHex(gasPrice),



  •         gasLimit: chain3.intToHex(gasLimit),



  •         data: data,



  •         shardingFlag: 0, //default is global contract



  •         chainId: chain3.version.network



  •     };







  •     var signedTx = chain3.signTransaction(rawTx, fromSecret);



  •     return new Promise(function (resolve, reject) {                   //异步调用方法



  •         mc.sendRawTransaction(signedTx, function (err, hash) {



  •             if (!err) {               



  •                 console.log('i=', index);



  •                 console.log("succeed: ", hash);



  •                 let objBack = {                                       //index及对应的hash



  •                     hash,



  •                     index



  •                 }



  •                 resolve(objBack);



  •             } else {



  •                 console.log("error:", err);



  •                 console.log('raw tx:', rawTx);



  •                 reject(err);



  •             }



  •         });



  •     })



  • }


执行结果:返回所有交易的hash值。

并且建立一个新的文件2018-8-12-1534085632480-hadSendMessage.xlsx。


4.在交易里发送 mc + data

发送一笔交易,包含发送mc,同时把数据写到data字段。



  • var Chain3 = require('chain3');



  • var chain3 = new Chain3(new Chain3.providers.HttpProvider('http://localhost:8545'));







  • var address = "0x745c57ca5318093115d61bbca368XXXXXXXXXXXX";



  • var account = {address:"0x745c57ca5318093115d61bbca368XXXXXXXXXXXX",secret:"bb673026deda3c3cd0c63f6ccddfb02a7ae320078aa8XXXXXXXXXXXXXXXXXXXX"};







  • var toAddress = "0x68986c1bcd54ae5dae69310fc64eXXXXXXXXXXXX";



  • var amount = 0.002;







  • send(chain3, account.address, account.secret, toAddress, amount, txCount = -1)







  • function send(chain3, fromAddress, fromSecret, toAddress, amount, txCount = -1){



  •   var mc = chain3.mc;



  •   var txcount = txCount >= 0 ? txCount : chain3.mc.getTransactionCount(fromAddress);



  •   console.log("Get tx account", txcount);







  •   var gasPrice = 25000000000;



  •   var gasLimit = 100000;



  •   var value = chain3.toSha(amount, 'mc');



  •   var gasTotal = gasPrice * gasLimit + Number(value);



  •   console.log(gasPrice, gasLimit, value, chain3.fromSha(gasTotal, 'mc'));







  •   //以下为写入数据log



  •   let log = {



  •     timenew Date).getTime(),



  •     type:"info",



  •     msg:"MOAC GO!!!"



  •   };



  •   let str = JSON.stringify(log);



  •   console.log(str);



  •   let data = Buffer.from(str).toString('hex');



  •   data = '0x'+data;



  •   console.log(data);  







  •   var rawTx = {



  •     from: fromAddress,



  •     to: toAddress,



  •     nonce: chain3.intToHex(txcount),



  •     gasPrice: chain3.intToHex(gasPrice),



  •     gasLimit: chain3.intToHex(gasLimit),



  •     value: chain3.intToHex(value),



  •     data: data ,



  •     shardingFlag: 0, //default is global contract



  •     chainId: chain3.version.network



  •   };







  •   var signedTx = chain3.signTransaction(rawTx, fromSecret);



  •   mc.sendRawTransaction(signedTx, function(err, hash) {



  •       if (!err){



  •           console.log("succeed: ", hash);



  •           return hash;



  •       }else{



  •           console.log("error:", err);



  •                 console.log('raw tx:', rawTx);



  •       }



  •   });



  • }






回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|Hi,Tokens  |网站地图

GMT+8, 2019-9-19 16:59 , Processed in 0.114650 second(s), 4 queries , File On.

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表