技术篇:关于EKT的一些设计
前言
笔者做了一段时间的区块链底层开发,深知架构设计的重要性。对于高手来说,没有的轮子是可以自己造的,造个大规模消息/任务队列都只是想不想写的事情。但在企业中开发,追求的是稳定、性能、成本等等,所以通常希望使用开源组件,二次开发。
解析过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()即可启动。
主要有两步:
- 从本地数据库中恢复当前节点已同步的区块
- 同步区块
其中,同步区块方面有3个核心步骤:
- 从其他节点同步,执行dpos.SyncHeight(Height)
- 当区块同步失败,尝试3次,3次之后判断是否超级节点
- 如果当前节点同步失败,且是超级节点,则通过投票结果来同步区块,执行dpos.startDelegateThread()进入打包区块的流程
主网启动流程图如下:
数据同步与恢复
一般是刚启动的节点从其他节点同步数据。
- 第一步:GetRound()获取当前打包节点信息
- 第二步:循环向各个节点发送请求,执行getBlockHeader()获取区块数据
- 第三步:再请求该区块的投票结果,执行getVotes()获取投票结果
- 第四步:执行Validate()校验投票结果的完整性和真实性,不合法重复第二步
- 第五步:校验合法后,执行getBlockEvents()获取交易明细数据,再执行ValidateNextBlock()验证交易明细数据和区块数据是否合法,不合法重复第二步
- 第六步:以上都合法,执行RecieveVoteResult()写入区块
流程图如下:
后续会对RecieveVoteResult()单独分析,该函数集成的功能较多,包括:验证投票、管理区块、改变状态、记录打包间隔、写区块等功能。
本地数据恢复流程,一图可以描述,不再多说。
结语
这篇文章的内容已经足够长且多。如果反响不错,会继续深入share一些有价值的点。
真正理解,还需要多多阅读源码。
技术篇:关于EKT的一些设计相关推荐
- 一文读懂微信之父张小龙:失败天才、颠覆者、独裁者、人性操控师
本文内容原载于<博客天下>总第136期,网络版原文首发于钛媒体(原文链接:tmtpost.com/62285.html),原文撰稿:杨林.王万圆.苏雄.甘韵仪. 1.背景和概述 2010年 ...
- Python爬虫及其它函数知识读记及简单用法,持续更新中...
Python爬虫相关函数知识读记及简单用法,持续更新中- requests [riˈkwests] n. 请求,要求( request的名词复数 ): 需要: 所请求的事物: 申请书 函数或单词- 音 ...
- 别做梦了,社交产品哪有那么容易成功
本文原文由作者"蒲凡"原创发表于微信公众号"互联网指北",感谢原作者的分享. 1.引言 原文是我一年前写过的文章.当时子弹短信.多闪和马桶MT相继发布的时候,不 ...
- Visual Basic开发实战1200例(第I卷)pdf
网盘下载:网盘下载 <visual basic开发实战1200例>包括第i卷.第ii卷共计1200个例子,本书是第i卷,共计600个例子. 本书以开发人员在项目开发中经常遇到的问题和必须掌 ...
- 5G消息能取代IM?一文读懂5G消息的前世今生!
本文引用了公众号"鲜枣课堂"的<5G消息(RCS),到底是什么?>和公众号"InfoQ"的<5G消息来了,它会干掉微信还是变成另一个飞信?&g ...
- 云社区 博客 博客详情 如何设计实时数据平台(技术篇)
https://github.com/BriData/DBus [摘要] 实时数据平台(RTDP,Real-time Data Platform)是一个重要且常见的大数据基础设施平台.在上篇(设计篇) ...
- Fusion设计平台概念-synopsys芯片设计技术篇(三)
总共包括synopsys若干讲芯片相关知识.作为自己的记录专题,感兴趣点击链接看完整视频. 本节课程 如何基于革命性Fusion设计平台应对市场和工艺的挑战 链接地址:http://www.lezhi ...
- 社交APP的架构设计(技术篇)
- 简单明了!OLTP场景下的数据分布式设计原则
来自:DBAplus社群 作者介绍 温卫斌,就职于中国民生银行信息科技部,目前负责分布式技术平台设计与研发,主要关注分布式数据相关领域. 前言 最近几年做分布式项目,很多工作是关于OLTP(联机交易系 ...
最新文章
- centos7安装mysql 依赖检测失败:_gcc-centos7安装mysqlworkbench依赖检测失败
- 使用tap和tun设备的方法
- linux编译安装memcached
- Memcached总结
- Log4j的使用说明
- Mac上关于shell使用Python3和C++11声明
- php软件开发--mysql数据库进阶
- asp.net上传图片,上传图片
- HBase 1.3(NOSQL) 发布,性能大幅提升
- 合约战事风云 |链捕手
- 不知道为什么想起以前的事总是那么的心痛
- java 获取一年内周六周日日期
- 如何屏幕高清录像?--QVE屏幕录制
- 怎样建立产品体系?(五)- 产品生命周期
- 惊蛰恰逢“龙抬头”,流感高峰季来袭,你准备好了吗?
- java 错误1335_安装JAVA的JDK时出现,错误1335? – 手机爱问
- 心得分享——c语言如何将多个字符串赋值给字符串数组(即c语言如何输入并储存多个字符串)
- 深度学习三十问!一位算法工程师经历30+场CV面试后总结的常见问题合集(含答案)...
- 字车移动同步喷墨算法
- 在WPF中制作正圆形公章