InitializeNode

本文解析了比特币网络中结点的初始化过程及完成数据同步后的收尾工作,介绍了InitializeNode与FinalizeNode函数的作用,并对孤立交易池的概念及交易数据结构进行了说明。

现在我们接着看RegisterNodeSignals 的下一个连接函数。

InitializeNode

这个函数在main.cpp中。现在我们看这个函数源码:

初始化结点

可以看到这个函数:以nodeid为key ,一个CNodeState()的无名对象为value,构造了一个pair,并将此pair放入mapNodeState这个map中,mapNodeState也定义在main.cpp中。

定义mapNodeState

根据注释意思是说mapNodeState是维护对等结点状态的一个map值。我们也看下CNodeState这个类型吧。其实这个类型是个struct结构类型,我们在《解读六》中有过简单介绍。这个InitializeNode函数比较简单,我们直接看下一个函数:

FinalizeNode

FinalizeNode函数

通过源码可以看到这个函数的功能 是当结点中的交易或区块同步完成后,用于收尾的工作。这个函数首先对cs_main进行了锁定。然后通过State函数获取此结点的状态。我们看下State函数,State函数也在main.cpp中。

State函数获取结点状态

这个函数就是从mapNodeState这个map哈希中得到相应的结点状态对象。因为这个对象里包括了结点的传输区块的信息,就是下面两个循环的值:vBlocksInFlight和vBlocksToDownload,然后将他们的数据清空。

我们还需要看下EraseorphansFor这个函数,这个函数也在main.cpp中。

通过节点id查找此节点的孤立交易并清除

可以看到EraseorphansFor函数遍历了mapOrphanTransactions这个map哈希。这个哈希map就是我们说的�孤立交易池:

孤立交易池

这里定义了两个map变量,这两个变量共同构成了孤立交易池,其中mapOrphanTransactions存储的是CTransaction对象,而mapOrphanTransactionsByPrev存储的是交易输入部分的父交易哈希。我们现在就看下放入孤立交易池和从孤立交易池中删除交易的函数。

将交易放入孤立交易池和从孤立交易池中删除交易

我们现在就简单说下什么是孤立交易池:我们的交易在一个结点中也是一个链条的结构,这条链的形式是一笔交易消耗了先前的交易(父交易)的输出,并为随后的交易(子交易)创造了输出。当一条交易链被整个网络传送时,他们并不能总是按照相同的顺序到达目的地。有时,子交易在父交易之前到达。在这种情况下,节点会首先收到一个子交易,而不能找到他参考的父交易。节点不会立即抛弃这个子交易,而是放到一个临时池中,并等着接收它的父交易,与此同时广播这个子交易给其他节点。没有父交易的交易池被称作孤立交易池。具体的介绍请查看《精通比特币》第五章的内容。

关于CTransaction类就是定义交易的数据结构的类。这个类在core.h中。

交易的数据结构

可以看到比特币交易是一个包括:版本(明确这笔交易参照的规则),交易输入(CTxIn),交易输出(CTxOut),锁定时间。

这个锁定时间需要介绍下:锁定时间定义了能被加到区块链里的最早的交易时间。在大多数交易里,它被设置成 0,用来表示立即执行。如果锁定时间不是 0 并且小于 5 亿,就被视为区块高度,如果锁定时间大于 5 亿,则它被当作是一个 Unix 纪元时间戳(从 1970 年 1 月 1 日以来的秒数)。

我们还要看下CTxIn和TxOut两个类。

可以看到每笔交易Tx的输入交易(CTxIn类)包含一个COutPoint对象prevout,该对象引用另外一笔交易Tx的输出交易作为来源交易。来源交易使当前交易Tx从另一笔交易当中得到可花费的比特币。也就是我们说的UTXO,UTXO 是不能再分割、被所有者锁住或记录于区块链中的并被整个网络识别成货币单位的一定量的比特币货币。一个COutPoint对象指向来源交易的某一笔输出交易,所以COutPoint的hash值就是指向革个CTxOut的哈希值,n是vout序列的序列号。

关于交易这部分内容挺多的,而且非常重要,大家最好详细看下《精通比特币》的交易章节,我也需要去看一遍。好我了们总结下这篇内容的两个函数。

其中 InitializeNode 函数是初始化结点状态的函数。FinalizeNode函数是我们从比特币网络中接收完数据后的收尾工作,包括对传输中的区块数据和交易数据和其他的一些数据。另外我们也看了些交易相关的数据结构。我们对比特币的了解也越来越深入了



作者:ttblack
链接:https://www.jianshu.com/p/0f6880f8bff7
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
下载前必看:https://renmaiwang.cn/s/bvbfw Verilog设计_串并转换 / 移位寄存器实现了一种串并转换的功能,其核心原理在于移位寄存器的运用。 这里详细展示了串转并以及并转串两种不同的设计方案。 每一种转换模式都设有专属的使能信号,同时并行输出数据的格式提供了两种选择:最低有效位优先(lsb)和最高有效位优先(msb)。 串并转换技术主要应用于串行传输与并行传输这两种数据传输模式之间的相互转换,而移位寄存器是达成这一目标的常用工具,能够支持并行及串行的数据输入与输出操作。 这些移位寄存器通常被设定为“串行输入、并行输出”(SIPO)或“并行输入、串行输出”(PISO)两种工作模式。 在串行数据输出的过程中,构成数据和字符的码元会按照既定的时间顺序逐位进行传输。 相比之下,并行数据传输则是在同一时刻将固定数量(普遍为8位或16位等)的数据和字符码元同时发送至接收端。 数据输入通常采用串行格式进行。 一旦数据成功输入寄存器,它便可以在所有输出端同时被读取,或者选择逐位移出。 寄存器中的每个触发器均设计为边沿触发类型,并且所有触发器均以特定的时钟频率协同工作。 对于每一个输入位而言,它需要经过N个时钟周期才能最终在N个输出端呈现,从而完成并行输出。 值得注意的是,在串行加载数据期间,并行输出端的数据状态应保持稳定。 数据输入则采用并行格式。 在将数据写入寄存器的操作过程中,写/移位控制线必须暂时处于非工作状态;而一旦需要执行移位操作,控制线便会变为激活状态,并且寄存器会被锁定以保持当前状态。 只要时钟周期数不超过输入数据串的长度,数据输出端Q将按照预定的顺序逐位读出并行数据,并且必须明确区分最低有效位(LSB)和最高有效位(MSB)。
### 关于 `java.lang.IllegalStateException` 异常的解决方案 `java.lang.IllegalStateException` 是一种运行时异常,通常表示在对象的当前状态下不允许调用特定方法[^1]。当节点初始化失败时,该异常可能由于以下原因引发:配置错误、资源不可用或依赖项未正确初始化。 #### 1. 原因分析 - **配置问题**:如果节点的初始化依赖于某些外部配置文件或参数,而这些配置缺失或不正确,则可能导致异常。 - **资源不可用**:例如数据库连接池耗尽、网络不可达等,都会导致初始化失败。 - **依赖项未初始化**:某些组件需要其他组件先完成初始化才能正常工作,如果顺序错误也可能抛出此异常[^2]。 #### 2. 日志与调试 要解决 `IllegalStateException`,首先需要查看日志信息以定位具体原因。以下是常见的日志记录方式: ```java try { // 节点初始化代码 initializeNode(); } catch (IllegalStateException e) { // 记录详细的异常信息 System.err.println("Node initialization failed: " + e.getMessage()); e.printStackTrace(); } ``` 通过捕获异常并打印堆栈信息,可以更清楚地了解问题所在[^3]。 #### 3. 解决方案 根据常见原因,提供以下几种解决方法: - **检查配置文件**:确保所有必需的配置项均已正确设置。例如,检查 `application.properties` 或 `application.yml` 文件中的参数是否符合预期[^4]。 - **验证资源可用性**:确认所有依赖的外部资源(如数据库、消息队列等)均处于正常状态。 - **调整初始化顺序**:如果多个组件之间存在依赖关系,需确保按照正确的顺序进行初始化[^5]。 #### 4. 示例代码 以下是一个简单的示例,展示如何安全地初始化节点并处理潜在的异常: ```java public class NodeInitializer { public void initializeNode() throws IllegalStateException { if (!checkPrerequisites()) { throw new IllegalStateException("Initialization prerequisites not met"); } // 执行实际的初始化逻辑 System.out.println("Node initialized successfully"); } private boolean checkPrerequisites() { // 检查必要的条件 return true; // 根据实际情况返回 true 或 false } public static void main(String[] args) { NodeInitializer initializer = new NodeInitializer(); try { initializer.initializeNode(); } catch (IllegalStateException e) { System.err.println("Failed to initialize node: " + e.getMessage()); } } } ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值