[以太坊源代码分析] VI. 基于p2p的底层通信(上篇)

以太坊源码(01):P2P网络及节点发现机制 汪老师发的第一篇以太坊源码的研究,一同领略吧! 阅读详情

以太坊作为一个去中心化的系统,其底层个体相互间的通信显然非常重要,所有数据的同步,各个个体状态的更新,都依赖于整个网络中每个个体相互间的通信机制。以太坊的网络通信基于peer-to-peer(p2p)通信协议,又根据自身传输数据类型(区块,交易,哈希值等),网络节点业务相关性等需求,在各方面做了特别设计。

由于以太坊中p2p通信相关代码量较大,打算分为上下两篇文章来加以详解:上篇主要介绍管理p2p通信的核心类ProtocolManager内部主要流程,以及通信相关协议族的设计;下篇主要介绍ProtocolManager的两个成员Fetcher和Downloader,这里是上篇。

1. 一般意义上的p2p网络

在开始介绍以太坊的p2p通信机制之前,不妨先来看看一般意义上的p2p网络通信的一些特征,以下部分内容摘自peer-to-peer_wiki

peer-to-peer(p2p)首先是一种网络拓扑类型,与之对比最显著的就是client/server(C/S)架构。从TCP/IP协议族分层的角度来说,p2p网络中实际的数据交换,依然是网络层用IP协议,传输层用TCP协议;而p2p协议--如果可称之为协议的话,应算作应用层再往上,类似于逻辑拓扑层,毕竟著名的应用层协议之一FTP,就属于非常典型的一种C/S架构类型。

上图是C/S架构和p2p架构的一个简单示意图,原图来自wiki。左图中C/S架构被描绘成星型拓扑,这当然仅仅是特例,大家可能在工作中遇到各种各样拓扑形状的C/S架构,而其核心特征是不变的:C/S 网络中的个体地位和功能是不平等的,client个体主要消耗资源,发起请求,server个体主要提供资源并处理请求,这使得C/S架构天然是中心化的。

相比之下,p2p架构中最重要的特点在于:其网络中的个体在地位和功能上是平等的,虽然每个个体可能处理不同的请求,实际提供的资源在具体量化后可能有差异,但它们都能同时既消耗资源又提供资源。如果把整个所处网络中的资源--此处的资源包括但不限于运算能力、存储空间、网络带宽等,视为一个总量,那么p2p网络中的资源分布,是分散于各个个体中的(也许不一定均匀分布)。所以,p2p网络架构天然是去中心化的、分布式的。

注意上图右侧p2p网络中,并非每个个体与网络中其他同类均有通信。这其实也是p2p网络的一个很重要的特点:一个个体只需要与相邻的一部分同类有通信即可,每个个体可与多少相邻个体、哪些个体有通信,是可以加以设计的,

无结构化的和有结构化的p2p网络

根据p2p网络中节点相互之间如何联系,可以将p2p网络简单区分为无结构化的(unstructured),和结构化的(structured)两大类。

无结构化的

这种p2p网络即最普通的,不对结构作特别设计的实现方案。优点是结构简单易于组建,网络局部区域内个体可任意分布,反正此时网络结构对此也没有限制;特别是在应对大量新个体加入网络和旧个体离开网络(“churn”)时它的表现非常稳定。缺点在于在该网络中查找数据的效率太低,因为没有预知信息,所以往往需要将查询请求发遍整个网络(至少大多数个体),这会占用很大一部分网络资源,并大大拖慢网络中其他业务运行。

结构化的

这种p2p网络中的个体分布经过精心设计,主要目的是为了提高查询数据的效率,降低查询数据带来的资源消耗。提高查询效率的基本手段是对数据建立索引,结构化p2p网络最普遍的实现方案中使用了分布式哈希表(Distributed Hash Table,DHT),它会对每项数据(value)分配一个key以组成(key,value)键值对,同时网络中每个个体的分布--这里的分布主要指相互通信关系-根据key键进行关联和扩展。这样,当要查找某项数据时,只要跟据其key键就能不断的缩小查找区域,大大减少资源消耗。

尽管如此,这样的p2p网络缺点也很明显:由于每个个体需要存有数量不少的相邻个体列表,所以当网络中发生大量新旧个体频繁加入和离开的“churn”事件时,整个网络的性能会大幅恶化,因为每个个体的很大一部分资源消耗在相邻列表更新上(包括自身相邻列表的更新,和相互之间更新所储列表),同时许多peer所在的key也需要重新定义;另外,哈希表本身容量是有使用限制的,当哈希表中存储的数据空间大于其设计容量的一半时,哈希表就会大概率出现“碰撞”事故,这样的限制也使得依据DHT建立的p2p网络的整体效率大打折扣。

对于以太坊通信机制的借鉴

根据以太坊的运行特点,我们可以大概勾勒出以太坊个体也就是客户端所组成网络的一些需求特征:

  1. 网络中随时可能存在一些个体加入和离开网络的情况,但同一时间内大量新旧个体同时发生加入或离开的概率很低。
  2. 每个个体所存储的数据(区块),理想状态下是相同的。也许有些个体会存在更新不够及时,例如新挖掘区块/新创建交易的广播事件到达有延迟,或者有些个体需要在状态更新后更换自己所维持区块链中的区块,但相应的通信机制一定是希望将这些差异抹平的。所以在以太坊网络中,查找数据时并不需要针对某些特定区域以提高效率,当然也不需要向整个网络大水漫灌的发送请求,正常情况下任意一个(或相邻几个)个体就可以提供。

综上所述,我们对以太坊中的p2p网络设计可以有个初步思路了:

  • 不需要结构化,经过改进的非结构化(比如设计好相邻个体列表)网络模型可以满足需求;
  • 个体间的相互同步更新需要仔细设计;

之后的章节中,我们可以逐步了解以太坊中的这个p2p网络通信是如何完善并实现的。

2. p2p通信的管理模块ProtocolManager

以太坊中,管理个体间p2p通信的顶层结构体叫eth.ProtocolManager,它也是eth.Ethereum的核心成员变量之一。先来看一下它的主要UML关系:


ProtocolManager主要成员包括:

  • peertSet{}类型成员用来缓存相邻个体列表,peer{}表示网络中的一个远端个体。
  • 通过各种通道(chan)和事件订阅(subscription)的方式,接收和发送包括交易和区块在内的数据更新。当然在应用中,订阅也往往利用通道来实现事件通知。
  • ProtocolManager用到的这些通道的另一端,可能是其他的个体peer,也可能是系统内单例的数据源比如txPool,或者是事件订阅的管理者比如event.Mux。
  • Fetcher类型成员累积所有其他个体发送来的有关新数据的宣布消息,并在自身对照后,安排相应的获取请求。
  • Downloader类型成员负责所有向相邻个体主动发起的同步流程。

小小说明:这里提到的"远端"个体,即非本peer的其他peer对象。以太坊的p2p网络中,所有进行通信的两个peer都必须率先经过相互的注册(register),并被添加到各自缓存的peer列表,也就是peerSet{}对象中,这样的两个peers,就可以称为“相邻”。所以,这里提到的“远端"个体,如果处于可通信状态,则必定已经“相邻”。

在运行方面,Start()函数是ProtocolManager的启动函数,它会在eth.Ethereum.Start()中被主动调用。ProtocolManager.Start()会启用4个单独线程(goroutine,协程)去分别执行4个函数,这也标志着该以太坊个体p2p通信的全面启动。

Start():全面启动p2p通信

由Start()启动的四个函数在业务逻辑上各有侧重,下图是关于它们所在流程的简单示意图:


以上这四段相对独立的业务流程的逻辑分别是:

  • 广播新出现的交易对象。txBroadcastLoop()会在txCh通道的收端持续等待,一旦接收到有关新交易的事件,会立即调用BroadcastTx()函数广播给那些尚无该交易对象的相邻个体。
  • 广播新挖掘出的区块。minedBroadcastLoop()持续等待本个体的新挖掘出区块事件,然后立即广播给需要的相邻个体。当不再订阅新挖掘区块事件时,这个函数才会结束等待并返回。很有意思的是,在收到新挖掘出区块事件后,minedBroadcastLoop()会连续调用两次BroadcastBlock(),两次调用仅仅一个bool型参数@propagate不一样,当该参数为true时,会将整个新区块依次发给相邻区块中的一小部分;而当其为false时,仅仅将新区块的Hash值和Number发送给所有相邻列表。
  • 定时与相邻个体进行区块全链的强制同步。syncer()首先启动fetcher成员,然后进入一个无限循环,每次循环中都会向相邻peer列表中“最优”的那个peer作一次区块全链同步。发起上述同步的理由分两种:如果有新登记(加入)的相邻个体,则在整个peer列表数目大于5时,发起之;如果没有新peer到达,则以10s为间隔定时的发起之。这里所谓"最优"指的是peer中所维护区块链的TotalDifficulty(td)最高,由于Td是全链中从创世块到最新头块的Difficulty值总和,所以Td值最高就意味着它的区块链是最新的,跟这样的peer作区块全链同步,显然改动量是最小的,此即"最优"。
  • 将新出现的交易对象均匀的同步给相邻个体。txsyncLoop()主体也是一个无限循环,它的逻辑稍微复杂一些:首先有一个数据类型txsync{p, txs},包含peer和tx列表;通道txsyncCh用来接收txsync{}对象;txsyncLoop()每次循环时,如果从通道txsyncCh中收到新数据,则将它存入一个本地map[]结构,k为peer.ID,v为txsync{},并将这组tx对象发送给这个peer;每次向peer发送tx对象的上限数目100*1024,如果txsync{}对象中有剩余tx,则该txsync{}对象继续存入map[]并更新tx数目;如果本次循环没有新到达txsync{},则从map[]结构中随机找出一个txsync对象,将其中的tx组发送给相应的peer,重复以上循环。

以上四段流程就是ProtocolManager向相邻peer主动发起的通信过程。尽管上述各函数细节从文字阅读起来容易模糊,不过最重要的内容还是值得留意下的:本个体(peer)向其他peer主动发起的通信中,按照数据类型可分两类:交易tx和区块block;而按照通信方式划分,亦可分为广播新的单个数据和同步一组同类型数据,这样简单的两两配对,便可组成上述四段流程。


上述函数的实现中,很多地方都体现出巧妙的设计,比如BroadcastBlock()中,如果发送区块block,由于数据量相对重量级,则仅仅选择一小部分相邻peer,而如果发送hash值 + Number值,则发给所有相邻peer;又比如txsyncLoop()中,会从map[]中随机选择一个peer进行发送(随机选择的txsync{}中包含peer)。这些细节,很好的控制了单次业务请求的资源消耗对于定向区域的倾向性,使得整个网络资源消耗愈加均衡,体现出非常全面的设计思路。

handle():交给其他peer的回调函数

对于peer间通信而言,除了己方需要主动向对方peer发起通信(比如Start()中启动的四个独立流程)之外,还需要一种由对方peer主动调用的数据传输,这种传输不仅仅是由对方peer发给己方,更多的用法是对方peer主动调用一个函数让己方发给它们某些特定数据。这种通信方式,在代码实现上适合用回调(callback)来实现。

ProtocolManager.handle()就是这样一个函数,它会在ProtocolManager对象创建时,以回调函数的方式“埋入”每个p2p.Protocol对象中(实现了Protocol.Run()方法)。之后每当有新peer要与己方建立通信时,如果对方能够支持该Protocol,那么双方就可以顺利的建立并开始通信。以下是handle()的基本代码:

// /eth/handler.go
func (pm *ProtocolManager) handle(p *peer) error {
    td, head, genesis := pm.blockchain.Status()
    p.Handshake(pm.networkId, td, head, genesis)

    if rw, ok := p.rw.(*meteredMsgReadWriter); ok {
        rm.Init(p.version)
    }

    pm.peers.Register(p)
    defer pm.removePeer(p.id)

    pm.downloader.RegisterPeer(p.id, p.version, p)

    pm.syncTransactions(p)
    ...
    for {
        if err := pm.handleMsg(p); err != nil {
            return err
        }
    }
}
handle()函数针对一个新peer做了如下几件事:

  1. 握手,与对方peer沟通己方的区块链状态
  2. 初始化一个读写通道,用以跟对方peer相互数据传输。
  3. 注册对方peer,存入己方peer列表;只有handle()函数退出时,才会将这个peer移除出列表。
  4. Downloader成员注册这个新peer;Downloader会自己维护一个相邻peer列表。
  5. 调用syncTransactions(),用当前txpool中新累计的tx对象组装成一个txsync{}对象,推送到内部通道txsyncCh。还记得Start()启动的四个函数么? 其中第四项txsyncLoop()中用以等待txsync{}数据的通道txsyncCh,正是在这里被推入txsync{}的。
  6. 在无限循环中启动handleMsg(),当对方peer发出任何msg时,handleMsg()可以捕捉相应类型的消息并在己方进行处理。

建立新peer连接和传递Protocol[]

刚才提到,handle()函数以回调函数的形式被放入一个p2p.Protocol{}里,那么Protocol对象是如何交给新peer的呢?这部分细节,隐藏在新peer连接建立的过程中。

所有远端peer与己方之间的通信,都是通过p2p.Server{}来管理的,Server在整个客户端最早的启动步骤Node.Start()中被创建并启动,而node.Node是用来承载客户端中所有node.<Service>实现体的容器,下图简单示意了Node.Start()中与Server相关的一些步骤:


Node.Start()中首先会创建p2p.Server{},此时Server中的Protocol[]还是空的;然后将Node中载入的所有<Service>实现体中的Protocol都收集起来,一并交给Server对象,作为Server.Protocols列表;然后启动Server对象,并将Server对象作为参数去逐一启动每个<Service>实现体。

而由于eth.Ethereum对于<Service>.Protocols()的实现中,正是搜集了ProtocolManager.Protocols而成,所以ProtocolManager.Protocols最终被导入了p2p.Server.Protocols.

那么Server.Start()中做了什么呢? 下图是Server.Start()和run()函数体内,与新peer创建相关的主要逻辑:


可以看到,Server.Start()中启动一个单独线程(listenLoop())去监听某个端口有无主动发来的IP连接;另外一个单独线程启动run()函数,在无限循环里处理接收到的任何新消息新对象。在run()函数中,如果有远端peer发来连接请求(新的p2p.conn{}),则调用Server.newPeer()生成新的peer对象,并把Server.Protocols全交给peer。

综合这两部分代码逻辑,可以发现:

  1. ProtocolManager.Protocols 最终由Server赋予了每一个新连接上(新创建)的peer对象中,所以回调函数ProtocolManager.handle(),也会进入每一个新的远端peer对象中。而peer对象,需要接受目前客户端Node中所有<Service>的Protocols列表。
  2. 以太坊中每个peer接收新连接的过程,源于标准的TCP/IP监听来访连接的方式(listener)。而每个新连接上的peer,都会由p2p.Server交给ProtocolManager。


一点体会:

从上述逻辑流程中可以感受到,对于以太坊的p2p通信管理模块来说,管理Protocol才是其最重要的任务,尤其是通过Protocol中的回调函数的设定,可以在对方peer在发生任何事件时,己方有足够的逻辑进行响应。这也是这个核心结构体为何被命名为ProtocolManager,而不是PeerManager的原因。至于管理peer群的功能,基本上用一个列表或者map结构,或者peerSet{}就够了。

3. p2p通信协议族的结构设计

在上文的介绍中,出现了多处有关p2p通信协议的结构类型,比如eth.peer,p2p.Peer,Server等等。这里不妨对这些p2p通信协议族的结构一并作个总解。以太坊中用到的p2p通信协议族的结构类型,大致可分为三层:

  • 第一层处于pkg eth中,可以直接被eth.Ethereum,eth.ProtocolManager等顶层管理模块使用,在类型声明上也明显考虑了eth.Ethereum的使用特点。典型的有eth.peer{}, eth.peerSet{},其中peerSet是peer的集合类型,而eth.peer代表了远端通信对象和其所有通信操作,它封装更底层的p2p.Peer对象以及读写通道等。
  • 第二层属于pkg p2p,可认为是泛化的p2p通信结构,比较典型的结构类型包括代表远端通信对象的p2p.Peer{}, 封装自更底层连接对象的conn{},通信用通道对象protoRW{}, 以及启动监听、处理新加入连接或断开连接的Server{}。这一层中,各种数据类型的界限比较清晰,尽量不出现揉杂的情况,这也是泛化结构的需求。值得关注的是p2p.Protocol{},它应该是针对上层应用特意开辟的类型,主要作用包括容纳应用程序所要求的回调函数等,并通过p2p.Server{}在新连接建立后,将其传递给通信对象peer。从这个类型所起的作用来看,命名为Protocol还是比较贴切的,尽管不应将其与TCP/IP协议等既有概念混淆。
  • 第三层处于golang自带的网络代码包中,也可分为两部分:第一部分pkg net,包括代表网络连接的<Conn>接口,代表网络地址的<Addr>以及它们的实现类;第二部分pkg syscall,包括更底层的网络相关系统调用类等,可视为封装了网络层(IP)和传输层(TCP)协议的系统实现。

下列UML图描绘了上述三层p2p通信协议族中的一些主要结构,希望对于理解以太坊中p2p通信相关代码有所帮助。



小结:

诸如以太坊这种去中心化的数字货币运行系统,天生适用p2p通信架构。不过原理虽然简单,在系统架构的层面,依然有很多实现细节需要加以关注。

  1. eth.ProtocolManager中,会对每一个远端peer发起主动传输数据的操作,这组操作按照数据类型区分,可分为交易和区块;而若以发送数据方式来区分,亦可分为广播单项数据,和同步一组同类型数据。这样两两配对,即可形成4组主动传输数据的操作。
  2. ProtocolManager通过在p2p.Protocol{}对象中埋入回调函数,可以对远端peer的任何事件及状态更新作出响应。这些Protocol对象,会由p2p.Server传递给每一个新连接上的远端peer。
  3. 以太坊目前实现的p2p通信协议族的结构类型中,按照功能和作用,可分为三层:顶层pkg eth中的类型直接服务于当前以太坊系统(Ethereum,ProtocolManager等模块),中间层pkg p2p是泛化结构类型,底层包括golang语言包自带的pkg net, syscall等,封装了网络层和传输层协议的系统实现。
以太坊源码解读(9)以太坊的P2P模块解析——底层网络构建和启动 以太坊的底层p2pServer,大约可以分为三层: 1、底层:table对象、node对象,它们分别定义了底层的路由表以及本地节点的数据结构、搜索和验证;     1)database.go         //封装node数据库相关操作     2)node.go             //节点数据结构     3)ntp.go              //同步时间      4)t... 阅读详情

相关推荐

P2P网络数据处理流程

P2P网络数据处理流程 监听(ListenLoop)+拨号(Dial) –&gt; 建立连接(SetupConn) –&gt; Enc 握手(doEncHandshake) –&gt; 协议握手(doProtoHandshake) –&gt; 添加Peer Addpeer –&gt; Run Peer 1. Enc握手 doEncHandshake 监听时接收到Enc握手:receive...

qukuai的博客 706

以太坊P2P 流程 整体框架

以太坊底层P2P代码细节很多,深入进去,会丢失整体框架,所以按照自己的习惯,先明白框架结构,了然于胸,然后再深入细节,所以这一节就先用白话总结下整体的流程。 入口: 1. P2P层分为两个部分,一层是基于UDP的节点Node发现,二是基于TCP的节点Peer的消息交互。注意这里的两个英文单词,Node,是网络上的节点,Peer是已经连接的节点 2. 两个过程依次涉及两个大类NodeTable...

laorenmen的专栏 578

硬核干货 | 区块链的基石:以太坊的 P2P 网络实现

作者:Ann.OG 该文章由annchain团队原创首发,未经允许不得转载,否则将追究法律责任 编者按 作为区块链的底层传输方式,P2P技术帮助区块链成功实现了点对点的传播。而当下最为成功的区块链项目之一以太坊也使用了大量代码来实现P2P传输。本篇文章详细深入介绍了以太坊P2P的实现原理。 以太坊的 P2P 网络 以太坊的p2p网络主要有两部分构成:节点之间互相连接用于传输数据的tcp网络和节点之...

weixin_42934313的博客 1205

以太坊 p2p Server 原理及实现

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33922670的博客 376

以太坊源码之P2P网络及节点发现机制

本书用来描述以太坊网络发现的实现原理。很适合相关从事和学习以太坊技术的同学。

基于深度学习的道路裂缝检测识别研究(开题报告)

具体而言,将本研究提出的模型与其他先进的道路裂缝检测算法在相同的数据集上进行对比实验,通过对比实验结果,分析不同算法在准确率、召回率、F1值等指标上的优劣,以及在实际应用中的表现。通过对综述论文的学习了解,对计算机视觉、多模态相关领域的基础进行简要介绍,并在跨模态行人重识别研究领域归纳国内外研究现状和发展趋势,明确当前面临的问题和挑战,并针对当前存在的问题展开后续研究。第二,研究解决该问题的途径和方法。基于深度学习的道路裂缝检测识别研究,旨在通过构建和优化深度学习模型,实现对道路裂缝的自动识别和定位。

毕业作品网站 3826

以太坊p2p原理简单介绍

使用编译器 使用命令行编译器 注解 这一节并不适用于solcjs solc是 Solidity 源码库的构建目标之一,它是 Solidity 的命令行编译器。你可使用solc--help命令来查看它的所有选项的解释。该编译器可以生成各种输出,范围从简单的二进制文件、汇编文件到用于估计“gas”使用情况的抽象语法树(解析树)。如果你只想编译一个文件,你可以运行solc--bin...

跨链技术践行者 9299

告别‘Duang’的一声:手把手解决RK3588开发板PCIe初始化卡死问题(DTS修改实战)

本文详细介绍了解决RK3588开发板PCIe初始化卡死问题的完整过程,包括问题诊断、DTS文件修改及编译烧写步骤。通过禁用未使用的PCIe硬件资源,有效解决了启动卡死问题,为嵌入式开发者提供了实用的调试方法和经验总结。

weixin_30753873的博客 214

以太坊源码之--P2P网络源码剖析(1)

ethereum-p2p代码分析(v1.8.24) 本篇主要按p2p的主要逻辑进行代码分析 1、开始分析主要代码 1.1 server.Start() // Start starts running the server. // Servers can not be re-used after stopping. func (srv *Server) Start() (err error) { ...

fh667788123的博客 855

用STM32F103C8T6和TB6612驱动模块,从零搭建一辆能避障循迹的智能小车(附完整代码)

本文详细介绍了如何使用STM32F103C8T6和TB6612驱动模块从零搭建一辆能避障循迹的智能小车。内容涵盖硬件选型、电路设计、底层驱动配置以及智能行为算法实现,并附有完整代码示例,帮助开发者快速掌握嵌入式开发的核心技术。

weixin_42641741的博客 444

springcloud教程 -- 1.快速搭建入门级demo,看这一篇就够了

废话不多讲,跟紧我,开启你的SpringCloud初体验 首先回顾微服务的基本组成: [图片 here] 生产者:提供服务 消费者:消费服务 服务注册/发现中心:服务注册,发现,监控 所以,首先明白springcloud微服务的架构基础:生产者(client),消费者(client),服务注册/发现中心(server)

叶巨岩的博客 8万+

p2p项目过程中知识点

idea快捷方式 光标放到方法名上面,ctrl+alt+b 直接进入到方法中 Debug模式,F7进入到方法中,F8跳出方法,F9直接到下一个断点 templates switch…case … <div th:switch="${currentPage}"> <span th:case="1"> 首页 上一页 </span> <span...

ljf12138的博客 1441

别再为镜面物体检测发愁了!手把手教你用PMD相位偏折术增强2.5D形状图细节(附Python代码)

本文详细解析了PMD相位偏折术在工业视觉中镜面物体检测的应用,通过2.5D成像方案增强形状图细节。文章提供了Python代码示例,介绍了一种计算高效的局部特征增强算法,帮助解决产线环境中的噪声问题,提升缺陷识别准确率。

weixin_29299807的博客 346

以太坊源码分析---go-ethereum之p2p通信分析(2)

本文QQ空间链接:http://user.qzone.qq.com/29185807/blog/1519899372 上一篇分析了p2p模块的初始化与start。  继续上一篇分析。   先回顾下p2p的初始化 github.com/ethereum/go-ethereum/eth/backend.go中 函数 func New(config *Con

月牙寂 3206

大智慧L2实时api接口的逐笔委托功能执行代码分享

用过l2行情接口的投资者应该都了解大部分的接口都是有逐笔委托功能的,那么大智慧L2实时api接口也有着很强大的逐笔委托功能,投资者可以通过这个逐笔委托功能可以看到一个股票的每天出现的全部委托指令,那么在这个逐笔委托功能里包含了委托价格、委托时间、委托量和委托方向四个要素!那么接下来小编就分享一下大智慧L2实时api接口的逐笔委托功能执行代码!那么在这里提个醒:投资者可以在大智慧L2实时api接口进行设置过滤,在逐笔委托列表里,就仅仅只会显示超过设置委托量或委托额的委托单,而不再显示小单。

Qq_2037696191的博客 3729

Redhawk: 为什么STA CHECK中switch cell覆盖率为0(STA file中switch control pin没有timing window)?

如题,做dynamic analysis时,不需要switch cell的timing window信息,但是做low power analysis需要做上电时switch cell的timing window就是必须的了,本文对switch cell control pin没有timing window (STA CHECK覆盖率为零)的这种现象做分析。

m0_61544122的博客 1195

以太坊源码分析(14)P2P分析

#概述Kademlia(简称Kad)是一种分布式哈希表技术,用于建立p2p网络拓扑结构。基本原理就是以两个节点ID的异或值作为两节点间的距离d,每个节点都将其他节点的信息存储到称之为K桶的表结构中,该表结构按照d的为1的最高bit位分层(可理解为桶索引),每层中存储最多K个节点信息。如下: | I | 距离范围 | 邻居 ||:---:|:---------:|:---...

尹成的技术博客 1971

SAP GR(Group Reporting)合并报表内容及功能简介(五)-合并和抵消

随着合并和收购数量的显著增加,企业在全球经济中面临着诸多挑战。其中最常见的是法律实体与子公司之间缺乏透明度,导致无法以经济高效的方式对账法律实体与子公司之间的公司间交易,从而造成结算出现重大延迟。公司间匹配和对账功能允许用户在关账过程中进行早期分析,以避免公司间差异,并缩短关账时的延迟。公司间匹配和对账功能交易级别匹配和实时对账基于各种组织维度(如公司、利润中心和合并单位)的灵活建模自动差异解决。应用内通信和工作流。与公司间抵销集成。

weixin_43853754的博客 4400

FlashP2P中的key交换

观察RTMPLITE和CUMULUS中的代码,可以发现FlashP2P中的key交换,有两种可能的模式。 首先,IHello和KEY交换没有关系,可以忽略。 RHello的cert,即rcert,可能有两个模式:4+64+9 bytes,这种是服务器返回的模式;而4+128 bytes是flash返回的模式,即后面128字节是pub key。 IIKeying的skic,用来计算secret

OSSRS 1154

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

以太坊p2p网络(二):以太坊P2P节点发现算法原理剖析

以太坊底层分布式网络即P2P网络,使用了经典的Kademlia网络,简称kad。 一、核心数据结构 NodeTable类负责以太坊的节点发现,NodeTable采用kademlia(KAD)算法进行节点发现 NodeTable维护一个网络节点列表,此列表为当前可用节点,供上层使用 由于NodeID经过sha3生成出的Hash为256位。列表有256-1=255项,其中-1是因为刨除了当前节点(本...

码墨 3962

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

以太坊 p2p网络——kademlia协议(一)

    Kademlia协议(以下简称Kad),是一种分布式哈希表(DHT,Distributed Hash Table)技术,不过和其他DHT实现技术比较,如Chord、CAN、Pastry等,Kad通过独特的以异或算法(XOR)为距离度量基础,建立了一种全新的DHT拓扑结构,相比于其他算法,大大提高了路由查询速度。     在Kademlia网络中,所有信息均以的哈希表条目形式加 以存储,这...

The future is already here it's just not evenly distributed。 3096

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

以太坊p2p网络(五):P2P模块TCP连接池网络通信机制源码分析

上节中通过设置静态节点BootstrapNodes节点来发现更多全网的其他节点,这部分只是发现节点并找出其中可以ping通的节点,但是还没有进行使用,还没建立TCP连接进行数据传输,协议处理等。 这里主要分析P2P系统的TCP连接池的建立,以及是怎么跟其他节点通信的。 一、TCP监听 P2P网络服务启动时调用Server.Start(),其后面部分代码: p2p/server.go里面的Start...

码墨 1550

p2p通信原理及实现

p2p通信原理及实现 【转载自优快云 香烟头】 1.简介   当今部署的中间件大多都是在C/S架构上设计的,其中相对隐匿的客户机主动向周知的服务端(拥有静态IP地址和DNS名称)发起链接请求。大多数中间件实现了一种非对称的通讯模型,即内网中的主机可以初始化对外的链接,而外网的主机却不能初始化对内网的链接,除非经过中间件管理员特殊配置。在中间件为常见的NAPT的情况下(也是本文主要讨论的),内网中的客户端没有单独的公网IP地址,而是通过NAPT转换,和其他同一内网用户共享一个公网IP。这种内网主机隐藏在中间

LateLinux的博客 3846
上一篇: [以太坊源代码分析] IV. 椭圆曲线密码学和以太坊中的椭圆曲线数字签名算法应用
teaspring
博客等级 码龄19年 350粉丝 24原创
评论 33
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值