一、唠叨两句

首先,我们都知道区块链是去中心化的,其中节点都是对等节点,每个节点都几乎有完整的区块链特性,CLI就是NEO的一个命令行对等节点,当然也有GUI这个项目,图形化的NEO节点。节点之间需要通信,互通有无,我们今天主要看看这部分。

二、从入口开始

CLI是一个Console程序,那我们就从它的Main开始把。

static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
new MainService().Run(args);
}

Main

这里除了注册一个未捕获异常的处理事件之外,就是这个MainService的Run方法了。MainService继承自ConsoleServiceBase,我们看下ConsoleServiceBase的代码吧,看一眼你就明白这个Service是在搞什么东东了

using System;
using System.Reflection;
using System.Security;
using System.Text; namespace Neo.Services
{
public abstract class ConsoleServiceBase
{
protected virtual string Prompt => "service"; public abstract string ServiceName { get; } protected bool ShowPrompt { get; set; } = true; protected virtual bool OnCommand(string[] args)
{
switch (args[].ToLower())
{
case "clear":
Console.Clear();
return true;
case "exit":
return false;
case "version":
Console.WriteLine(Assembly.GetEntryAssembly().GetName().Version);
return true;
default:
Console.WriteLine("error");
return true;
}
} protected internal abstract void OnStart(string[] args); protected internal abstract void OnStop(); public void Run(string[] args)
{
OnStart(args);
RunConsole();
OnStop();
} private void RunConsole()
{
bool running = true;
#if NET461
Console.Title = ServiceName;
#endif
Console.OutputEncoding = Encoding.Unicode; Console.ForegroundColor = ConsoleColor.DarkGreen;
Version ver = Assembly.GetEntryAssembly().GetName().Version;
Console.WriteLine($"{ServiceName} Version: {ver}");
Console.WriteLine(); while (running)
{
if (ShowPrompt)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write($"{Prompt}> ");
} Console.ForegroundColor = ConsoleColor.Yellow;
string line = Console.ReadLine().Trim();
Console.ForegroundColor = ConsoleColor.White; string[] args = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (args.Length == )
continue;
try
{
running = OnCommand(args);
}
catch (Exception ex)
{
#if DEBUG
Console.WriteLine($"error: {ex.Message}");
#else
Console.WriteLine("error");
#endif
}
} Console.ResetColor();
}
}
}

ConsoleServiceBase

MainService肯定重写了方法OnStart,OnStop,里面干啥了后面再讲,除此之外,主要方法RunConsole里就是等输入命令,然后根据命令进行相应操作,然后循环继续。可以创建个钱包啊,创建个地址啊,blabla的。OnCommand里实现了一些界面上的操作,那MainService类里一定就是侦听CLI可以支持的各种指令咯,具体每个指令做了什么操作顺着这个线索看代码即可了解,后面我们会选几个关键的指令溜一下代码,现在我们就只关注这个OnStart,OnStop都干啥了。

protected internal override void OnStart(string[] args)
{
Blockchain.RegisterBlockchain(new LevelDBBlockchain(Settings.Default.Paths.Chain));
if (!args.Contains("--nopeers") && File.Exists(PeerStatePath))
using (FileStream fs = new FileStream(PeerStatePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
LocalNode.LoadState(fs);
}
LocalNode = new LocalNode();
Task.Run(() =>
{
const string acc_path = "chain.acc";
const string acc_zip_path = acc_path + ".zip";
if (File.Exists(acc_path))
{
using (FileStream fs = new FileStream(acc_path, FileMode.Open, FileAccess.Read, FileShare.None))
{
ImportBlocks(fs);
}
File.Delete(acc_path);
}
else if (File.Exists(acc_zip_path))
{
using (FileStream fs = new FileStream(acc_zip_path, FileMode.Open, FileAccess.Read, FileShare.None))
using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read))
using (Stream zs = zip.GetEntry(acc_path).Open())
{
ImportBlocks(zs);
}
File.Delete(acc_zip_path);
}
LocalNode.Start(Settings.Default.P2P.Port, Settings.Default.P2P.WsPort);
bool recordNotifications = false;
for (int i = ; i < args.Length; i++)
{
switch (args[i])
{
case "/rpc":
case "--rpc":
case "-r":
if (rpc == null)
{
rpc = new RpcServerWithWallet(LocalNode);
rpc.Start(Settings.Default.RPC.Port, Settings.Default.RPC.SslCert, Settings.Default.RPC.SslCertPassword);
}
break;
case "--record-notifications":
recordNotifications = true;
break;
}
}
if (recordNotifications)
Blockchain.Notify += Blockchain_Notify;
});
}

MainService.OnStart

我们看到OnStart方法里做了如下的事情:

1. 注册LevelDBBlockChain作为本地的链的存储

2. 正常启动需要与其他节点通讯的情况,会先找一个叫做peers.dat的文件。这个文件里存储的是其他对等节点的地址,读取的到地址存储在LocalNode类的静态属性UnconnectedPeers里,拿到这些节点地址可以建立与其的通信。

3. 新建了一个LocalNode实例,这个实例比较关键了,作为本地节点的通讯模块,与之对应的是RemoteNode,每个已连接上的对等节点都会有一个对应的RemoteNode实例,保存在LocalNode实例的connectedPeers列表里。

4. 查看是否有chain.acc或者chain.acc.zip文件,这个文件是链的存储文件,如果不想同步节点,可以使用这个文件作为离线文件启动,免去同步数据的时间。

5. 调用LocalNode.Start方法,该方法里做了啥?

a. 启动两个线程connectThread和poolThread,这两个线程都干啥呢?

I. connectThread: 如果前面讲述的unconnectedPeers列表里还有未连接的节点,就创建对应的任务去连接。如果没有未连接的节点了,就从connectedPeers列表里拿出来已连接的RemoteNode节点,发送一个getaddr消息。如果两个列表都是空,就拿出系统默认的feed节点去连接。

在连接节点的时候,会创建一个RemoteNode实例,添加到connectedPeers列表里,并调用RemoteNode的StartProtocal,这个方法里表达出的是两个对等节点建立连接的过程:

给对方发送Version消息

接收到Version消息,就发送VerAck消息

接收VerAck消息,根据Version消息中的信息判断是不是对方持有更新的数据,如果是就发送getheaders和getblocks消息获取最新的数据

II. poolThread: 首先先说下两个数据结构temp_pool和mem_pool,都是存储交易的,temp_pool存储的是最近接收到的交易,mem_pool是在内存中存储所有未验证交易。当节点接收到了交易消息,会把消息放在temp_pool里,然后在这个poolThread的一个loop中把mem_pool和temp_pool合并,对每笔交易进行验证,验证通过的交易都会发送一个inv消息,把消息发送到已连接上的RemoteNode中去。

b. 开启TcpListener侦听其他对等节点的消息,开启WebSocket侦听WebSocket消息。

6. 如果需要开启rpc,则开启RPC服务。

protected internal override void OnStop()
{
if (consensus != null) consensus.Dispose();
if (rpc != null) rpc.Dispose();
LocalNode.Dispose();
using (FileStream fs = new FileStream(PeerStatePath, FileMode.Create, FileAccess.Write, FileShare.None))
{
LocalNode.SaveState(fs);
}
Blockchain.Default.Dispose();
}

MainService.OnStop

OnStop方法就简单多了

1. 析构共识服务和RPC服务

2. 析构LocalNode,调用LocalNode.Dispose方法,停止TcpListener侦听,与所有的connectedPeers断开连接,并且把所有的connectedPeers放到unconnectedPeers队列里。

3. 将unconnectedPeers写入peers.dat文件

4. 析构链结构,LevelDBBlockchain关闭底层的LevelDB存储。

三、小结

好了,到这里简单介绍了一下NEO CLI,重点讲了启动和关闭时都搞了些什么,基本上也就是NEO网络层干的事情,剩下的就是处理互相通信的消息,处理CLI上输入的指令。到这里你应该已经建立了一个多对等节点建立网络的大概过程。

NEO从入门到开窗(4) - NEO CLI的更多相关文章

  1. NEO从入门到开窗(3) - NEO编译器

    一.啰嗦两句 第一节的时候咱说了C#编译完了之后,就该NEO的编译器搞事情了.我们完全可以按这个节奏搞,手动用NEO的编译器neon编译dll文件生成指令码文件.avm.但是NEO团队给我们写智能合约 ...

  2. NEO从入门到开窗(2) - 智能合约的面相

    一.啰嗦两句 昨天讲了智能合约的一生,那丫长啥样啊?今儿我就跟各位唠叨唠叨. 二.一个简单的智能合约 下面这段就是NEO实例源码里的一个,干撒用的?聪明的你一眼儿就看出来了吧,就是一个所谓域名合约的增 ...

  3. NEO从入门到开窗(1) - 一个智能合约的诞生

    一.啰嗦两句 最近一直都在研究区块链,BitCoin,Etherenum, Hyper Ledger Fabric还有今天的主角小蚂蚁,当然出名以后改了一个艺名叫NEO.区块链大部分都是用Golang ...

  4. [转]NEO与以太坊:为什么NEO可能是2018年最强的加密货币

    本文转自:https://baijiahao.baidu.com/s?id=1591291802129464257&wfr=spider&for=pc NEO,它可以与以太坊竞争吗?N ...

  5. webpack入门(五)webpack CLI

    webpack的CLI安装和命令 Installation $ npm install webpack -g The webpack command is now available globally ...

  6. NEO

    平台: Windows 类型: 虚拟机镜像 软件包: .net core neo application server basic software blockchain neo open sourc ...

  7. C#区块链零基础入门,学习路线图 转

    C#区块链零基础入门,学习路线图 一.1分钟短视频<区块链100问>了解区块链基本概念 http://tech.sina.com.cn/zt_d/blockchain_100/ 二.C#区 ...

  8. SpringBoot入门:Spring Data JPA 和 JPA(理论)

    参考链接: Spring Data JPA - Reference Documentation Spring Data JPA--参考文档 中文版 纯洁的微笑:http://www.ityouknow ...

  9. 使用 Azure CLI 创建 Windows 虚拟机

    Azure CLI 用于从命令行或脚本创建和管理 Azure 资源. 本指南详细介绍如何使用 Azure CLI 部署运行 Windows Server 2016 的虚拟机. 部署完成后,我们连接到服 ...

随机推荐

  1. 配置WebLogic的详细步骤

    配置WebLogic的详细步骤 1.安装好WebLogic后,进入配置阶段,点击"Getting started with WebLogic Server 10.3.6" 2.进入 ...

  2. RHEL64 缺少ISO 9660图像 安装程序试图挂载映像#1,在硬盘上无法找到该映像

    用光盘安装Linux,很容易,按照提示一步一步就好.如果没有光驱,只好想办法用硬盘或者U盘安装了. 首先说说怎样用U盘启动Linux的安装程序:1.将ISO镜像文件拷贝到U盘中,并解压到U盘根目录.将 ...

  3. TypeError: Error #1034: 强制转换类型失败:无法将 "" 转换为 Array。

    1.错误描述 TypeError: Error #1034: 强制转换类型失败:无法将 "" 转换为 Array. at mx.charts.series::LineSeries/ ...

  4. HALCON学习-资料

    HALCON学习网: http://www.ihalcon.com/ 学习资料推荐博客: http://k594081130.blog.163.com/blog/static/218359013201 ...

  5. POJ 2187 Beauty Contest(凸包,旋转卡壳)

    题面 Bessie, Farmer John's prize cow, has just won first place in a bovine beauty contest, earning the ...

  6. Frogger POJ - 2253

    题意 给你n个点,1为起点,2为终点,要求所有1到2所有路径中每条路径上最大值的最小值. 思路 不想打最短路 跑一边最小生成树,再扫一遍1到2的路径,取最大值即可 注意g++要用%f输出!!! 常数巨 ...

  7. java&python环境变量+idea&pycharm激活

    java: JAVA_HOME=C:\jdk1.5.0_06 PATH=%JAVA_HOME%\bin;%PATH% CLASSPATH=.;%JAVA_HOME%\lib;%JAVA_HOME%\l ...

  8. JavaScript方面的书籍

    我要向大家推荐两本js方面的书: <JavaScript权威指南> <JavaScript高级程序设计>适合想在js方面有所提高的开发人员 我们读书是为了什么? 有的人可能是兴 ...

  9. Firefox书签同步工具Xmarks

    Xmarks作为Firefox最受欢迎的社会化书签扩展之一,其前身为Foxmarks,并且显著的增加了它的功能.Xmarks已被LastPass(领先的密码和数据管理)收购. 之前一直是只使用火狐浏览 ...

  10. fail2ban防止SSH暴力破解

    [root@kazihuo /srv]# wget https://github.com/fail2ban/fail2ban/archive/0.8.14.tar.gz [root@kazihuo / ...