序
2017年底刚开始接触区块链,目前在被 NEO 折磨。
一开始被官方文档和 NEO-GUI 搞得体无完肤(尤其是传说中的 F12),也找了各种调试工具用来搞 NeoContract,然并卵。
直到有一天发现了 NewEconoLab ,在它的 github 上有一个项目 neo-thinsdk-cs ,用 C# 实现了一个轻钱包 —— thinWallet 。
这个轻钱包只做了一件事情,就是做交易,它把整个交易的流程都体现出来了,给开发者展示了明确的可视化交易拼接流程(包括Attribute、Inputs、Outputs、Script、Witness等,我曾经用 VS F11 一行一行的调试跟踪过它的源代码,所有的这些交易必须的数据都组装好,放到一个数据结构里,非常清晰)。
最重要的是分解了 UTXO 和 使得 Witness 变得可处理,以达成 NEO-GUI 达不到的操作。
此外,目前的 thinWallet ,默认接入到 Testnet,还不支持直接接入 Mainnet ,也不支持接入到 NEO 私有链 ,我们都知道 Testnet 上的 Gas 十分珍贵,需要去申请才能有,而我们部署合约,动不动就消耗 990 Gas 。而在自己的私有链上 Gas 就是大白菜了,随便乱玩都可以。
所以为了方便部署合约调试,今天的任务是将 thinWallet 接入到私有链中。
1、环境准备
- 基础要求:四台 Debian 9(其他发行版随你喜欢,单击此处查看支持的机器,建议创建一台虚拟机配好环境然后直接克隆,别忘了强制刷新 MAC 地址,要不然 IP 冲突) ,一台 Windows 10 ,.net core sdk,visual studio 2017 community,.net framework 4.7 SDK,NEO-CLI,搭私链跑共识,建钱包,拿到一亿的 NEO 币和至少 1000 个 Gas (相当于你的区块高度超过 125,这至少需要耗费31分钟),这些东西文档里都有,此处不再赘述。
- 克隆项目:NeoBlock-Mongo-Storage,NEO_Block_API,neo-thinsdk-cs,三个项目都是直接用 master 分支就可以了。
这里解释一下克隆下来的三个项目是什么样的关系,三个都是 .net 项目
- neo-thinsdk-cs 是一整个解决方案,用 vs 2017 打开,里面有一个 WPF 项目是 thinWallet ,把它设置为启动项目,直接 CTRL+F5 就可以运行了,当然默认是接入 Testnet 。项目里面有一个《NEO智能合约开发(一)不可能完成的任务.docx》,好好看看。运行结果如下:
这里我们按第二个按钮 ThinWallet Test 就好了,进去是这样的界面:
- 我们可以看到右上角在调用一个 API for UTXO,这是一个 webapi ,由 NEO_Block_API 提供,大家可以看到这地方默认就是 Testnet ,区块高度也是 Testnet 的高度,切换网络那个按钮还没写功能。总共五个大面板都很好理解,第一个登录方式,第二个 api 信息,第三个账户信息(你的 utxo 将会出现在这里),第四个交易三要素,第五个决定是什么类型的交易。
- NEO_Block_API 里面用到了 mongodb ,所以我们的第三个项目 NeoBlock-Mongo-Storage 作为一个调度任务跑着,用来实时收集链上的交易信息存入 mongodb 中,供 NEO_Block_API 使用。
- 顺便说明一下, vs 2017 很人性化,你直接 CTRL+F5 或者生成解决方案 ,会帮你还原依赖库的,看见黄色感叹号不要慌。如果你无法打开项目或者无法还原或者出现任何异常,相信我,一定是你的打开方式不对,或者你改了里面的东西改错了,或者环境有问题,三个项目是绝对没有错误的,我验证了好几遍了,请回头好好检查自己的环境等基础设施吧。
配置 NEO_Block_API
到这里,基础环境全部搭建完毕,thinWallet 也可以在 Testnet 上正常使用了,那么接下来就需要开始接入私链了。首先我们要把 NEO_Block_API 的源代码增改一下,让它支持接入私链。
我们先看一下源代码长什么样,还是 vs 2017 打开:
我已经生成过解决方案了,所以依赖库都没问题了,结构非常简单。Controllers 是控制器,就是一些 web 接口在这里实现,lib 就是要用到的工具,RPC 定义了一些数据结构,再加一个 Startup.cs 和 Program.cs 文件,典型的 .net core web 项目。
我们可以看到里边有一个 mongodbsettings.json 文件带了个黄色警告标志,说明这个文件丢失了,因为在 .gitignore 里边把它写进去了,所以 git 就把它忽略了,问题不大,我们删掉它重新建立一个一样名字的文件就好了,我们可以找一下在哪里用到了这个文件,你可以 CTRL+SHIFT+F 全局查找,最终发现在 mongoHelper.cs 里面有这么一段:
public mongoHelper() {
var config = new ConfigurationBuilder()
.AddInMemoryCollection() //将配置文件的数据加载到内存中
.SetBasePath(System.IO.Directory.GetCurrentDirectory()) //指定配置文件所在的目录
.AddJsonFile("mongodbsettings.json", optional: true, reloadOnChange: true) //指定加载的配置文件
.Build(); //编译成对象
mongodbConnStr_testnet = config["mongodbConnStr_testnet"];
mongodbDatabase_testnet = config["mongodbDatabase_testnet"];
neoCliJsonRPCUrl_testnet = config["neoCliJsonRPCUrl_testnet"];
mongodbConnStr_mainnet = config["mongodbConnStr_mainnet"];
mongodbDatabase_mainnet = config["mongodbDatabase_mainnet"];
neoCliJsonRPCUrl_mainnet = config["neoCliJsonRPCUrl_mainnet"];
mongodbConnStr_NeonOnline = config["mongodbConnStr_NeonOnline"];
mongodbDatabase_NeonOnline = config["mongodbDatabase_NeonOnline"];
}
那么事情就简单了,我们看到这里面一共有 8 个字段要用到,给它就是了,我们在新建的 mongodbsettings.json 文件写上这些内容:
{
"mongodbConnStr_testnet": "mongodb://127.0.0.1:27017",
"mongodbDatabase_testnet": "testnet",
"neoCliJsonRPCUrl_testnet": "http://47.96.168.8:20332",
"mongodbConnStr_mainnet": "mongodb://127.0.0.1:27017",
"mongodbDatabase_mainnet": "mainnet",
"neoCliJsonRPCUrl_mainnet": "",
"mongodbConnStr_privatenet": "mongodb://127.0.0.1:27017",
"mongodbDatabase_privatenet": "privatenet",
"neoCliJsonRPCUrl_privatenet": "http://192.168.1.135:20332",
"mongodbConnStr_NeonOnline": "mongodb://127.0.0.1:27017",
"mongodbDatabase_NeonOnline": "neononline"
}
mainnet 一时半会儿肯定用不着,我懒得写了,testnet 还是保留原样,加一个 privatenet 。注意 neoCliJsonRPCUrl_privatenet 这个字段的值是 http://192.168.1.135:20332 ,192.168.1.135 这台机器是四台共识机中的一台,开了 RPC ,就是:dotnet neo-cli.dll /rpc
。我们可以用 postman 来测试一下,随便找个接口,路由是: http://192.168.1.135:20332
就用 getbestblockhash 吧:
先看一下我跑的四个共识节点,我的共识跑了挺久了,现在高度接近 7000 :
接下来我们看一下 rpc 接口调用结果:
如果你无法得到类似的结果,那还是得去多看看文档,跑跑共识。现在我们得到了正确结果,说明私链的 RPC 完全没有问题。此刻我们得到了第一个需要的接口就是刚才打开的 thinWallet 右上角 RPC Node 所需要的接口地址:http://192.168.1.135:20332
。
mongodb 你得装一下(随你 linux 还是 windows,推荐 linux),为了演示方便,我装在了 windows 里面。装完之后就是 C:\Program Files\MongoDB\Server\3.6\bin 里面有一堆东西。其中 mongod.exe 这个是服务端,因为国际惯例有个 d 。别急着双击它,你得先建立两个文件夹:C:\data\db,不然双击就闪退了,其实你可以用 cmd 来打开,可以看到异常信息。现在你可以双击它了,结果就是一个控制台,打印了一堆日志,你可以用 mongodb 自带的可视化客户端连接一下。这边注意,我们不需要事先创建数据库。
下面开始创建 webapi 接口,也就是新建一个控制器,在项目的 Controllers 文件夹下,新建一个类,取名:PrivatenetController.cs ,然后把随便 TestnetController.cs 或者 MainnetController.cs 里面的内容全部复制粘贴到我们的 PrivatenetController.cs 中,改一下两个地方,变成 privatenet :
[Route("api/[controller]")]
public class PrivatenetController : Controller
{
Api api = new Api("privatenet");
接着 mongoHelper.cs 里面改一下,把私链的东西加进去:
public string mongodbConnStr_testnet = string.Empty;
public string mongodbDatabase_testnet = string.Empty;
public string neoCliJsonRPCUrl_testnet = string.Empty;
public string mongodbConnStr_mainnet = string.Empty;
public string mongodbDatabase_mainnet = string.Empty;
public string neoCliJsonRPCUrl_mainnet = string.Empty;
public string mongodbConnStr_privatenet = string.Empty;
public string mongodbDatabase_privatenet = string.Empty;
public string neoCliJsonRPCUrl_privatenet = string.Empty;
public string mongodbConnStr_NeonOnline = string.Empty;
public string mongodbDatabase_NeonOnline = string.Empty;
public mongoHelper() {
var config = new ConfigurationBuilder()
.AddInMemoryCollection() //将配置文件的数据加载到内存中
.SetBasePath(System.IO.Directory.GetCurrentDirectory()) //指定配置文件所在的目录
.AddJsonFile("mongodbsettings.json", optional: true, reloadOnChange: true) //指定加载的配置文件
.Build(); //编译成对象
mongodbConnStr_testnet = config["mongodbConnStr_testnet"];
mongodbDatabase_testnet = config["mongodbDatabase_testnet"];
neoCliJsonRPCUrl_testnet = config["neoCliJsonRPCUrl_testnet"];
mongodbConnStr_mainnet = config["mongodbConnStr_mainnet"];
mongodbDatabase_mainnet = config["mongodbDatabase_mainnet"];
neoCliJsonRPCUrl_mainnet = config["neoCliJsonRPCUrl_mainnet"];
mongodbConnStr_privatenet = config["mongodbConnStr_privatenet"];
mongodbDatabase_privatenet = config["mongodbDatabase_privatenet"];
neoCliJsonRPCUrl_privatenet = config["neoCliJsonRPCUrl_privatenet"];
mongodbConnStr_NeonOnline = config["mongodbConnStr_NeonOnline"];
mongodbDatabase_NeonOnline = config["mongodbDatabase_NeonOnline"];
}
最后,Api.cs 里面加私链的东西:
public Api(string node) {
netnode = node;
switch (netnode) {
case "testnet":
mongodbConnStr = mh.mongodbConnStr_testnet;
mongodbDatabase = mh.mongodbDatabase_testnet;
neoCliJsonRPCUrl = mh.neoCliJsonRPCUrl_testnet;
break;
case "mainnet":
mongodbConnStr = mh.mongodbConnStr_mainnet;
mongodbDatabase = mh.mongodbDatabase_mainnet;
neoCliJsonRPCUrl = mh.neoCliJsonRPCUrl_mainnet;
break;
case "privatenet":
mongodbConnStr = mh.mongodbConnStr_privatenet;
mongodbDatabase = mh.mongodbDatabase_privatenet;
neoCliJsonRPCUrl = mh.neoCliJsonRPCUrl_privatenet;
break;
}
}
打完收工我们来试一下,CTRL+F5,我们可以看到内置的 IIS Express 被启动了,可以访问这个地址:http://localhost:59908/api/privatenet
显示的结果是:{"jsonrpc":"2.0","id":0,"error":{"code":-100,"message":"Parameter Error","data":"Value cannot be null.\r\nParameter name: s"}}
那说明 webapi 本身已经没问题了,我们看到用的是 localhost ,如果想局域网都能用的话我们可以改一下 .vs\config\applicationhost.config 里面的配置再运行,或者我们用典型的 .net core 方法(我采用这种),就是在 Program.cs 里面加一点料:.UseUrls("http://*:59908")
,详细如下,这是允许局域网 ip 访问的第一步:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseUrls("http://*:59908")
.Build();
第二步我们改一下启动方式,先重新生成解决方案,然后把 appsettings.json
和 mongodbsettings.json
两个文件复制到 bin\Debug\netcoreapp2.0
里面去,关掉刚才启动的 IIS Express,然后我们以管理员身份打开 cmd ,cd 到你的 bin\Debug\netcoreapp2.0
文件夹里面,然后 dotnet NEO_Block_API.dll
就好了,结果如下:
你可以去局域网的其他机器上用 postman 访问一下,没啥问题,用 getblockcount
接口吧,路由是这个: http://192.168.1.151:59908/api/privatenet
,文档在这:单击此处 。
我在这台 windows 10 上操作的,IP 是 192.168.1.151
,所以我们得到了第二个想要的接口地址,就是 API for UTXO 的 api 地址:http://192.168.1.151:59908/api/privatenet
。
thinWallet 接入私链
现在我们来观察一下 thinWallet 的代码结构:
很显然,上面三个项目都是通用库,第四个是用户端,而且我们只需要改一个地方就可以了,双击打开 Window_thinwallet.xaml ,WPF 的界面文件,打开是这样的:
简直不能忍,不仅丑爆了,还影响阅读和写代码,我们做一下调整,下面图里面中间,左右两个红圈圈出来的按钮,先按左边那个,上下窗口对调,然后按右边那个,把下窗口缩进去,这样就是纯代码界面了,又好看又能高效阅读。
接下来我们要把它接入私链,其实就改两个接口地址,就在这个界面代码里面,thinWallet 对这两个地址目前是写死在界面上的,我们在界面代码里面查找一下 CTRL+F ,输入 47.96
就能找到了,一共两个地方,分别对应的填进去:
打完收工我们来访问一下,CTRL+F5:
我们发现一个很诡异的数字,下面那个直接访问 neo rpc 的已经完全正常了,但是上面那个访问 webapi 的居然是这么个诡异的数字,那么碰到问题,我们首先得想到的事情只有一件,就是 F5,首先我们先打开 Window_thinwallet.xaml 这个文件的后台文件,就是 Window_thinwallet.xaml.cs
,我们观察一下里面的代码,发现有一个异步更新界面的地方:
再来看一下这个 api_getHeight
是怎么实现的,F12 过去:
真相在这里,请求了 webapi 的一个 getblockcount
的接口,那么现在来看一下 NEO_Block_API 项目对 getblockcount
是怎么实现的:
这时候就发现了,这里居然在调用 mongodb 的数据,我们回想一下,似乎没有任何操作 mongodb 的地方,也就是说没有任何数据,那么我们可以猜到,getblockcount
接口返回了一个 0 ,而且在我们的 Window_thinwallet.xaml.cs
文件异步更新界面的地方,最后 var height = ulong.Parse(json[0].AsDict()["blockcount"].ToString()) - 1;
来了这么一句,很明确了,无符号长整型,减了个 1 ,导致变成了那个数字,现在来 F5 证明一下,断点打在 api_getHeight
这个方法的最后一句 return 的代码上:
其中 result 是请求结果,就是 0 ,已经说明了一切。那还差什么呢,想想我们好像漏了一个项目,没错还有最后一个调度任务项目没配置好。
NeoBlock-Mongo-Storage 开启对私链的任务调度
老样子观察代码:
很简单,一个入口,两个数据接口,一个工具,没了。
我们可以发现在 Program.cs
里面有这么一段:
var config = new ConfigurationBuilder()
.AddInMemoryCollection() //将配置文件的数据加载到内存中
.SetBasePath(System.IO.Directory.GetCurrentDirectory()) //指定配置文件所在的目录
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) //指定加载的配置文件
.Build(); //编译成对象
mongodbConnStr = config["mongodbConnStr"];
mongodbDatabase = config["mongodbDatabase"];
NeoCliJsonRPCUrl = config["NeoCliJsonRPCUrl"];
sleepTime = int.Parse(config["sleepTime"]);
if (int.Parse(config["utxoIsSleep"]) == 1) {
utxoIsSleep = true;
}
很简单了,加个文件,appsettings.json
:
{
"mongodbConnStr": "mongodb://127.0.0.1:27017",
"mongodbDatabase": "privatenet",
"NeoCliJsonRPCUrl": "http://192.168.1.135:20332",
"sleepTime": "0",
"utxoIsSleep": "0"
}
同样道理,重新生成解决方案,把这个 json 文件复制到 bin\Debug\netcoreapp2.0 里面去,然后管理员身份打开 cmd ,然后 cd 进去,然后 dotnet NeoBlockMongoStorage.dll
,看下结果:
这个狂暴的气息,然后我们开一下 thinWallet,看下结果:
这个高度正在快速地向最高高度同步过去,同步完成之后,我们就完成了 thinWallet 接入私链的所有步骤,你的 thinWallet 就可以在私链中随便玩了。
同步完成之后,我们最好把 NeoBlock-Mongo-Storage 项目的 appsettings.json 改一下,把 sleepTime
从 0 改为 2000,utxoIsSleep
从 0 改为 1,因为调度是个无限循环,如果不让它睡一会,就会一直浪费你的 cpu ,同步完成了,没那么多数据要写了,让它休息休息,这样造成的效果是,上面那个高度永远比下面那个高度更新慢半拍。单位是毫秒。自己随便调节。
{
"mongodbConnStr": "mongodb://127.0.0.1:27017",
"mongodbDatabase": "privatenet",
"NeoCliJsonRPCUrl": "http://192.168.1.135:20332",
"sleepTime": "2000",
"utxoIsSleep": "1"
}
neo-thinsdk-cs 之 thinWallet 接入私链的更多相关文章
-
基于NEO的私链(Private Blockchain)
1.准备工作 1.NEO-GUI 2.NEO-CLI 3..NET Core Runtime (不能是2.x版本,官方建议是1.12,实际上我用1.14也是没有问题的) 4.四台windows操作系统 ...
-
[转]EOS智能合约 &; 私链激活 &; 基本操作
链接:https://www.jianshu.com/p/90dea623ffdf 简介 本篇文章,将跟大家介绍eos私链的激活.基础智能合约的安装,以及为大家演示转账等基础操作.还没有安装eos私链 ...
-
c#实战开发:以太坊私链搭建(一)
1.第一步环境搭建 运行环境:window 客户端版本:Go语言geth 下载地址https://ethereum.github.io/go-ethereum/downloads/ 以太坊API中文 ...
-
c#实战开发:以太坊钱包对接私链 (二)
上一篇讲了 以太坊私链搭建 首先下载Ethereum Wallet 钱包 可以直接百度 下载如果直接打开它会默认连接公链 所以我们要通过命令打开 "F:\Program Files\Ethe ...
-
IPFS私链搭建及常用操作命令
1. 共享密钥 同一个IPFS私链内的所有节点必须共享同一个密钥才能加入. 首先我们使用密钥创建工具,创建一个密钥. 下载地址:https://github.com/Kubuxu/go-ipfs-sw ...
-
win10下搭建私链
首先要下载geth,下载地址:https://gethstore.blob.core.windows.net/builds/geth-windows-amd64-1.7.0-6c6c7b2a.exe ...
-
win7环境搭建以太坊私链
如何创建私链: 创建创世配置文件: 首先需要创建一个“创世”json配置文件,此文件描述了创世区块的一些参数.下面就是文件中的内容: { "coinbase": "0x0 ...
-
以太坊geth区块链私链建立
以太坊geth区块链私链建立 geth的github https://github.com/ethereum/go-ethereum 下载最新(1.8)的geth,windows下安装很简单 关于 ...
-
centos 以太坊多节点私链搭建
环境 centos 7 搭建 3 个节点的 私链. 第一步 安装 一些依赖的 工具 yum update -y && yum install git wget bzip2 vim ...
随机推荐
-
[MySQL Reference Manual] 23 Performance Schema结构
23 MySQL Performance Schema 23 MySQL Performance Schema 23.1 性能框架快速启动 23.2 性能框架配置 23.2.1 性能框架编译时配置 2 ...
-
在web上逐行输出较大的txt文件
在某些场景下,需要在web上展示一些日志文件,这些日志文件是放在文件服务器上的一些txt. 当日志文件很大时,下载日志会导致页面长时间卡住,一直在loading状态,而且下载完日志之后分析日志并生成d ...
-
Effective C++ -----条款29:为“异常安全”而努力是值得的
异常安全函数(Exception-safe functions)即使发生异常也不会泄露资源或允许任何数据结构败坏.这样的函数区分为三种可能的保证:基本型.强烈型.不抛异常型. “强烈保证”往往能够以c ...
-
1.1 C#简介
大家好,这是我的C#(读做 "C sharp")学习之旅,先简介一下我了解的C#吧! 首先,说到C#,就不得不提到微软的.NET..NET是微软推出的软件开发和运行平台,允许应用程 ...
-
简单的js反选,全选,全不选
<html> <head> <base href="<%=basePath%>"> <title>My JSP 'che ...
-
node源码详解(六) —— 从server.listen 到事件循环
本作品采用知识共享署名 4.0 国际许可协议进行许可.转载保留声明头部与原文链接https://luzeshu.com/blog/nodesource6 本博客同步在https://cnodejs.o ...
-
bzoj 1008
记得取模时对答案的处理 #include<bits/stdc++.h> #define ll long long using namespace std; ; ll qpow(ll a,l ...
-
bzoj 3811: 玛里苟斯
3811: 玛里苟斯 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 190 Solved: 95[Submit][Status][Discuss] ...
-
JavaScript 之arguments、caller 和 callee 介绍
1.前言 arguments, caller , callee 是什么? 在javascript 中有什么样的作用?本篇会对于此做一些基本介绍. 2. arguments arguments: ...
-
helpera64开发板下制作ubuntu rootfs镜像
下一篇路径:https://www.cnblogs.com/jizizh/p/10499448.html 环境: HelperA64开发板 Linux3.10内核 时间:2019.02.14 目标:定 ...