nodeos
从架构角度看,本质上是一个插件系统,系统提供的主要功能都依赖它的插件系统,通过不同的插件组合来提供各种服务功能,如区块链查询,交易验证执行,打包区块,P2P网络通信等服务。
系统的插件系统位于 eos/plugins
目录下,插件系统包含三个层次:
libraries/appbase/include/appbase/plugin.hpp
文件中的抽象类 abstract_plugin
。这个抽象类提供了插件的基本接口,包括:
RITT
,结合 boost::core::demangle
来获取,获取到的名称包括了命名空间,比如:eosio::chain_api_plugin
。libraries/appbase/include/appbase/application.hpp
文件中的模板类,它实现了抽象插件中定义的方法,并且定义了一个虚函数来定义了插件的依赖的。
RTTI
运行时类型识别技术,获得具体的实例化插件的名称,并保存在 _name
属性中。这个名称包含了命名空间在内,比如:eosio::chain_api_plugin
。_state
。static_cast
方法,把当前插件转化为具体的实例化插件,然后调用插件的 plugin_requires
模板方法,加载插件依赖的其他插件。plugin_requires
模板方法,加载插件依赖的其他插件,并且通过 Lambda 表达式执行其它插件的 initialize
方法;plugin_initialize
方法,进行初始化;plugin_initialized
方法,把插件加入已初始化集合 initialized_plugins
。通过以上几个步骤,插件及其依赖都得到了初始化。
plugin_requires
模板方法,加载插件依赖的其他插件,并且通过 Lambda 表达式执行其它插件的 startup
方法;plugin_startup
方法,进行启动;plugin_started
方法,把插件加入已运行集合 running_plugins
。通过以上几个步骤,插件及其依赖都是运行中的。
plugin_shutdown
方法,进行停止。注意:插件的初始与启动方法分别是在 main
函数中通过调用应用对象的 application::iinitialize_impl
与 application::startup
中被调用的。
eos/plugins
,它们都定义了下面一些方法:
在 EOS 提供的插件中 chain_plugin
、net_plugin
、http_plugin
、producer_plugin
这4个插件不需要用户手动注册,节点会自动注册。
系统提供的插件及其功能如下所述:
nodeos
节点程序与区块链交互的基本功能,包括:
nodeos
节点程序与钱包交互的相关功能,包括3个基本功能:
EOS 的每个插件,在生命期内都会经历以下阶段
无论是在 main
方法通过模板函数 initialize
自动启动的,还是用户通过 --plugin
参数或配置文件指定的插件都要经过上面说的 3 个生成生命周期。
在 C++ 的 main
函数执行前,系统会提前初始化静态变量,这其中就包括了初始化插件相关的变量,这些插件都是通过调用 app().register_plugin<xxx_plugin>()
方法时行注册。我们简单看下这个方法:
find_plugin
,查找插件是否存在,如果存在则直接返回,否则,进入下一步;plugins
集合;register_dependencies
的方法来注册插件的依赖。系统中有如下一些插件采用了静态注册:
系统通过这种静态注册方法和插件间的依赖关系,间接地在系统启动前把所有插件都注册到系统中。
如果我们新开发了一个插件,因这个插件没有被任何现在的插件依赖,所以一定要采用静态注册方法,在系统启动之前就要进行注册,然后才可以在配置文件或参数中进行指定,这样插件才会进行初始化与启动。
无论是自动启动的插件,还是用户通过 --plugin
参数或配置文件指定的插件,所有的这此二插件都是在 main
函数中通过调用应用对象的 application::iinitialize_impl
方法完成初始化的。
在插件初始化之后,已经完成初始化的插件在 main
函数中通过调用应用对象的 application::startup
方法完成启动的。
由于本人水平所限,文中错误在所难免,欢迎您踊跃指出错误,在下感激不尽。我的微信联系方式:joepeak。
原创不易,尤其寒冬,欢迎赞助我一杯咖啡,本人比特币地址如下:3C1gyc2tsVudvVNQCZfrwHviDQeUpPeT95
版权声明:自由转载-非商用-非衍生-保持署名(创意共享4.0许可证)