前言

笔者做了一段时间的区块链底层开发,深知架构设计的重要性。对于高手来说,没有的轮子是可以自己造的,造个大规模消息/任务队列都只是想不想写的事情。但在企业中开发,追求的是稳定、性能、成本等等,所以通常希望使用开源组件,二次开发。

解析过EKT项目,鉴于自己还不是高手,把自己认为有用的点都总结下。希望对来往的看官老爷有用。

懂分享的人,一定会快乐!

账户设计

和ETH类似,用了账户模型,结合Merkle树进行设计,通过记录nonce值防止双花攻击。

核心逻辑:

func GenerateKeyPair() (pubkey, privkey []byte) {key, err := ecdsa.GenerateKey(S256(), rand.Reader)if err != nil {panic(err)}pubkey = elliptic.Marshal(S256(), key.X, key.Y)return pubkey, math.PaddedBigBytes(key.D, 32)
}

EKT采用ECDSA(椭圆曲线数字签名算法)生成地址,secp256k1方法作为该算法参数。

工程中,ecdsa和sha3_256算是两个主流加密算法。ecdsa(椭圆曲线数字签名算法)是一种非对称公钥加密算法,也是数字签名算法类比中的佼佼者,用于防止数据串改和验证数据真实性,对标RSA算法。sha3_256是一种哈希算法,也叫摘要技术,防止数据被篡改。

ECDSA相比于RSA有如下特点:

  • ECDSA的加密密钥更短
  • ECDSA的加密运算更快而安全性和RSA相当
  • RSA的私钥和公钥是可以互换加解密的,但ECDSA只能私钥加密公钥解密

ECDSA的核心是利用数论中大数分解比较困难。笔者在微信公众号后台,列出一些推荐的扩展阅读,回复"ecdsa"可以获取到资源。

存储相关

EKT的数据库采用LevelDB和sync.map。LevelDB是Key-Value型数据库,用于数据持久化。sync.map是一种GO语言的数据结构,可用于缓存。EKT封装了sync.map,开发了自己的内存型K-V数据库。

早期,有两个核心的文件:db/levedb.go和db/MemKVDatabase.go。

在实际代码中,EKT将本地KV和内存KV组装在一起,构成混合型KV数据库。核心文件db/ComposedKVDatabase.go 代码:

type ComposedKVDatabase struct {mem     *MemKVDatabase    // 引用内存型K-V数据库levelDB *LevelDB          // 引用本地K-V数据库
}// 抽象该混合型KV数据库
func NewComposedKVDatabase(filePath string) *ComposedKVDatabase {return &ComposedKVDatabase{mem:     NewMemKVDatabase(),levelDB: NewLevelDB(filePath),}
}

该数据库只有三个常用方法:

  • Set(key, value []byte):插入数据
  • Get(key []byte):查找数据
  • Delete(key []byte):删除数据

因为采用线性结构的区块链基因,所以并不会涉及update。

随着代码的迭代,笔者实测后发现:数据存在丢失的情况。之后,EKT官方去掉了自己的内存型K-V数据库,仅保留了leveldb相关。

这里,再次证明,稳定性好的东西,实在不好做。

链结构相关

链的结构包含了14个元素,依赖了外部包:i_consensus/consensus.go, pool/TxPool.go, police.go, block_manager.go

type BlockChain struct {ChainId       int64Consensus     i_consensus.ConsensusType    // 确认采用DPoS,Pow, PoscurrentLocker sync.RWMutexcurrentBlock  BlockcurrentHeight int64Locker        sync.RWMutexStatus        intFee           int64Difficulty    []bytePool          *pool.TxPool                // 交易池BlockInterval time.DurationPolice        BlockPolice                 // 用于记录从其他节点过来的blockBlockManager  *BlockManager               // 区块管理器PackLock      sync.RWMutex
}

各字段的解释官方没有给出,之后通过对代码的详细分析,再给出精准定义。

简单提下创世过程。当主链在启动时发现没有区块的时候,将执行写创世区块的功能。

创世核心源码:

// 将创世块写入数据库
accounts := conf.EKTConfig.GenesisBlockAccounts
block = &blockchain.Block{Height:       0,Nonce:        0,Fee:          dpos.Blockchain.Fee,TotalFee:     0,PreviousHash: nil,CurrentHash:  nil,BlockBody:    blockchain.NewBlockBody(),Body:         nil,Timestamp:    0,Locker:       sync.RWMutex{},StatTree:     MPTPlus.NewMTP(db.GetDBInst()),StatRoot:     nil,TxTree:       MPTPlus.NewMTP(db.GetDBInst()),TxRoot:       nil,TokenTree:    MPTPlus.NewMTP(db.GetDBInst()),TokenRoot:    nil,
}// 为每个创世账户更新默克尔树根
for _, account := range accounts {block.CreateGenesisAccount(account)
}// 更新默克尔树根,改变StatRoot,使得block.StatRoot = block.StatTree.Root
block.UpdateMPTPlusRoot()// 计算当前区块Hash值
block.CaculateHash()// 持久化
dpos.Blockchain.SaveBlock(*block)

获取创世区块的账户(可以是多个账户),由主链启动时配置得到。生成首个区块的数据,做了一些改动后,写入数据库。

主链启动

经过对主链、共识机制的初始化,再运行共识模块的Run()即可启动。

主要有两步:

  1. 从本地数据库中恢复当前节点已同步的区块
  2. 同步区块

其中,同步区块方面有3个核心步骤:

  • 从其他节点同步,执行dpos.SyncHeight(Height)
  • 当区块同步失败,尝试3次,3次之后判断是否超级节点
  • 如果当前节点同步失败,且是超级节点,则通过投票结果来同步区块,执行dpos.startDelegateThread()进入打包区块的流程

主网启动流程图如下:

数据同步与恢复

一般是刚启动的节点从其他节点同步数据。

  • 第一步:GetRound()获取当前打包节点信息
  • 第二步:循环向各个节点发送请求,执行getBlockHeader()获取区块数据
  • 第三步:再请求该区块的投票结果,执行getVotes()获取投票结果
  • 第四步:执行Validate()校验投票结果的完整性和真实性,不合法重复第二步
  • 第五步:校验合法后,执行getBlockEvents()获取交易明细数据,再执行ValidateNextBlock()验证交易明细数据和区块数据是否合法,不合法重复第二步
  • 第六步:以上都合法,执行RecieveVoteResult()写入区块

流程图如下:

后续会对RecieveVoteResult()单独分析,该函数集成的功能较多,包括:验证投票、管理区块、改变状态、记录打包间隔、写区块等功能。

本地数据恢复流程,一图可以描述,不再多说。

结语

这篇文章的内容已经足够长且多。如果反响不错,会继续深入share一些有价值的点。

真正理解,还需要多多阅读源码。

技术篇:关于EKT的一些设计相关推荐

  1. 一文读懂微信之父张小龙:失败天才、颠覆者、独裁者、人性操控师

    本文内容原载于<博客天下>总第136期,网络版原文首发于钛媒体(原文链接:tmtpost.com/62285.html),原文撰稿:杨林.王万圆.苏雄.甘韵仪. 1.背景和概述 2010年 ...

  2. Python爬虫及其它函数知识读记及简单用法,持续更新中...

    Python爬虫相关函数知识读记及简单用法,持续更新中- requests [riˈkwests] n. 请求,要求( request的名词复数 ): 需要: 所请求的事物: 申请书 函数或单词- 音 ...

  3. 别做梦了,社交产品哪有那么容易成功

    本文原文由作者"蒲凡"原创发表于微信公众号"互联网指北",感谢原作者的分享. 1.引言 原文是我一年前写过的文章.当时子弹短信.多闪和马桶MT相继发布的时候,不 ...

  4. Visual Basic开发实战1200例(第I卷)pdf

    网盘下载:网盘下载 <visual basic开发实战1200例>包括第i卷.第ii卷共计1200个例子,本书是第i卷,共计600个例子. 本书以开发人员在项目开发中经常遇到的问题和必须掌 ...

  5. 5G消息能取代IM?一文读懂5G消息的前世今生!

    本文引用了公众号"鲜枣课堂"的<5G消息(RCS),到底是什么?>和公众号"InfoQ"的<5G消息来了,它会干掉微信还是变成另一个飞信?&g ...

  6. 云社区 博客 博客详情 如何设计实时数据平台(技术篇)

    https://github.com/BriData/DBus [摘要] 实时数据平台(RTDP,Real-time Data Platform)是一个重要且常见的大数据基础设施平台.在上篇(设计篇) ...

  7. Fusion设计平台概念-synopsys芯片设计技术篇(三)

    总共包括synopsys若干讲芯片相关知识.作为自己的记录专题,感兴趣点击链接看完整视频. 本节课程 如何基于革命性Fusion设计平台应对市场和工艺的挑战 链接地址:http://www.lezhi ...

  8. 社交APP的架构设计(技术篇)

  9. 简单明了!OLTP场景下的数据分布式设计原则

    来自:DBAplus社群 作者介绍 温卫斌,就职于中国民生银行信息科技部,目前负责分布式技术平台设计与研发,主要关注分布式数据相关领域. 前言 最近几年做分布式项目,很多工作是关于OLTP(联机交易系 ...

最新文章

  1. centos7安装mysql 依赖检测失败:_gcc-centos7安装mysqlworkbench依赖检测失败
  2. 使用tap和tun设备的方法
  3. linux编译安装memcached
  4. Memcached总结
  5. Log4j的使用说明
  6. Mac上关于shell使用Python3和C++11声明
  7. php软件开发--mysql数据库进阶
  8. asp.net上传图片,上传图片
  9. HBase 1.3(NOSQL) 发布,性能大幅提升
  10. 合约战事风云 |链捕手
  11. 不知道为什么想起以前的事总是那么的心痛
  12. java 获取一年内周六周日日期
  13. 如何屏幕高清录像?--QVE屏幕录制
  14. 怎样建立产品体系?(五)- 产品生命周期
  15. 惊蛰恰逢“龙抬头”,流感高峰季来袭,你准备好了吗?
  16. java 错误1335_安装JAVA的JDK时出现,错误1335? – 手机爱问
  17. 心得分享——c语言如何将多个字符串赋值给字符串数组(即c语言如何输入并储存多个字符串)
  18. 深度学习三十问!一位算法工程师经历30+场CV面试后总结的常见问题合集(含答案)...
  19. 字车移动同步喷墨算法
  20. 在WPF中制作正圆形公章

热门文章

  1. zigbee 源码 01-温湿度DHT11
  2. 再读SLA理论,时刻不忘记
  3. png文件格式的详解:
  4. 通过sql对比两个表的一致性
  5. 团体程序设计天梯赛-练习集 L1-035 情人节
  6. java 微信支付功能
  7. 你做的分析,业务早知道了,怎么办?【实操版】
  8. 每次开机Edge浏览器自动启动怎么办
  9. H3C iNode智能客户端 破解
  10. 数据库基础面试题-中级32道