作者肉山大魔王iii
很久没和你们一起做实践的环节了,不晓得诸位是否也手发痒了呢?
明天给你们带来的是基于Golang编撰的区块链公链demo,也就是模仿比特币的功能所编撰的区块链公链demo。主要应用到了密码学,共识算法,对等网路,区块链防篡改结构等相关知识linux git中文乱码,并把各个知识点结合到一起,编撰成了简单建立的可运行公链demo。
话不多说,一起试试吧!
程序特征
主要模块
命令调度模块
启动程序后,控制台捕捉用户输入信息,通过对用户的输入解析出命令以及追随在命令后的值。依照不同命令对程序进行相关操作。
UTXO交易生成模块
交易转帐模块基于UTXO模型,但并没有引入比特币脚本,脚本处直接使用数字签名的字节链表进行代替。当用户A汇款给用户B时,须要用户A使用公钥对"输入"(包含了用户A所拥有的"输出"交易hash、索引等信息)进行数字签名,生成交易后发送给其他节点,其他节点则使用用户A的私钥对其进行签名验证。
因为UTXO的特殊结构,天然的防止了重放功击,并不须要像以太坊帐户系统一样添加nonce值,而且为了防止UTXO的重复估算问题,在上一笔转帐未打包进区块之前暂不支持同一地址的再度汇款
支持一笔交易多笔转帐linux git中文乱码,并为了优化汇款查询速率创建了UTXO数据表专门用于储存所有区块链中未耗费的输出。
密码学加揭秘模块
1、单向散列函数:sha256ripemd-160
主要用于将整体区块通过估算转换为固定宽度的字符串,便捷进行数据校准
2、编解码算法:base58
因为公钥原始宽度过长不利于记忆,使用base58编码对公钥、地址进行可视化编码
3、非对称加密:椭圆曲线算法(crypto/ellipticp256)
通过助记词文本提取7对英文熟语作为种子,通过使用椭圆曲线算法生成公公钥秘钥对,公钥用于对交易数据进行数字签名,私钥对签名进行验证来确保发起人身分。
私钥通过一系列运算生成地址,地址用于查询余额,以及接收汇款Token
地址生成规则如下:
以前有个疑惑,为什么比特币生成地址要如此麻烦,既然非对称加密只拥有私钥是难以倒推出公钥的,为什么不直接使用私钥当地址,而是对私钥进行hash多次来取得地址,直至近来看了篇文章才明白,该文章提及量子计算机是可以破解椭圆曲线加密的常用linux系统,其可以通过私钥快速找寻到公钥信息。并且量子计算机很难逆转Hash算法(或则说须要2的80次方个步骤来破解Hash),所以你的比特币置于一个未支付过的地址中(依据UTXO交易模型,输出存的是私钥Hash而不是私钥,这同样解释了为什么UTXO输入存的是私钥而输出存的是私钥Hash)是相当安全的。也就是说已有耗费的地址在面对量子计算机面前是不安全的,没有耗费的地址有较强的抗量子性。
区块生成、验证
基于POW共识算法生成区块,首先按照难度值(可在配置文件里定义)来定义挖矿难度(一串大数),通过调用go自身的随机数包crypto/rand来不断的变换随机数nonce(上个版本用的nonce值自身累加的方式,并且分叉的机率太大),不断哈希区块自身来使最终估算下来的区块自身hash值大于当前定义的挖矿难度则获得出块权力。
出块节点可获得奖励代币并拥有记帐权,出块后像全网进行广播。其余P2P节点收到区块后首先对区块自身hash进行验证,其次检验区块里的prehash与本地的前区块hash是否一致,最后存入本地数据库中。
数据持久化模块
持久化层基于KV型数据库blot多封装了一层,主要插口为put、view、delete。每次调用插口会单独打开、关闭数据库的句柄,所以不会出现被其他线程占用的情况。数据库分别构建了三个表BlockBucket(用于储存区块的详尽信息)、AddrBucket(用于储存本地皮夹数据)、UTXOBucket(用于储存未消费UTXO数据)
P2P网路通信模块
使用适宜局域网轮询的mdns技术,因为所使用的包在windows下存在找不到网路的bug,所以本程序建议在linux/mac下运行。
节点启动后会手动在局域网中找寻其他对等节点,发觉后会储存在节点池中(存于显存),节点之间相互通讯的数据前十二个字节默认为命令,按照命令不同来对本地的区块链相关信息进行反馈
主要运行原理为分发区块与收到交易后的挖矿:
获取区块流程:
互相对比区块高度
获取缺位的区块hash
通过区块hash来接收缺位的整个区块
区块验证,存入数据库
挖矿流程:
通过某个节点发送交易数据到全网节点
节点接收到交易,对交易进行签名验证,余额验证
验证通过后存入交易池,满足交易池大小后开始挖矿
挖矿成功,全网广播区块高度
发送区块到其他节点
其他节点进行区块验证,存入数据库
日志输出模块
使用自制的log包,程序启动后会默认在当前目录下(可在配置文件设置)生成log+端标语的日志文件,所有程序形成的debug信息就会复印到此日志文件中,建议开启一个窗口进行实时窃听以便捷观察节点之间的交互,以及区块生成的详尽步骤
【日志包特征】:
主要使用的工具包
程序运行教程
1.下载后编译
本demo建议在linux/mac下运行,否则会出现助记词乱码,找不到对等网路的问题。
git clone https://github.com/corgi-kx/blockchain_golang.git
go build -mod=vendor -o chain main.go
2.打开多个窗口
为了简化操作,在同一台笔记本中启动不同端口来模拟P2P节点(三个窗口用于启动程序,三个窗口用于实时查看日志)
实机操作时,假若出现找不到其他节点情况可能是防火墙问题,请关掉防火墙后在试
3.更改配置文件
主要更改本地窃听ip,本地窃听端口。其他的默认即可。
不建议调小难度阈值,防止形成区块分叉情况linux mint,demo暂未对区块分叉做处理。
vi config.yaml
blockchain: #挖矿难度值,越大越难挖 mine_difficulty_value: 24 #挖矿奖励代币数量 token_reward_num: 25 #交易池大小(满足多少条交易才开始进行挖矿) trade_pool_length: 2 #日志存放路径 log_path: "./" #中文助记词种子路径 chinese_mnemonic_path: "./chinese_mnemonic_world.txt"network: #本地监听IP listen_host: "192.168.0.164" #本地监听端口 listen_port: "9000" #节点组唯一标识名称(如果节点间名称不同会找不到网络) rendezvous_string: "meetme" #网络传输流的协议id(如果节点间id不同发送不了数据) protocol_id: "/chain/1.1.0"
4.启动节点,创建皮夹,生成创世区块
启动节点1
./chain
通过命令,先生成三个皮夹地址
> generateWallet助记词:["肺段","生地","齿槽","几维","中葡","芒鱼","光华"]私钥:6HrLjHE4Qm31dZFGjemwNLZM3iqnxoSUqKb5VtEKbWzh地址:12BwtcVWimms9rrKxxoCev68woGyMYS4sk> generateWallet助记词:["扭伤","剪创","肌病","下陷","广发","浊音","斜疝"]私钥:7yBRSB46q8ZeEiYbwZDSvKzzsh1MYAygeo2i689uEMAf地址:1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS> generateWallet助记词:["心室","缺缸","瓣胃","黑茶","份额","张铜","回游"]私钥:872CCeLS8bDrC7bdSoFrgUSWm57eqTdypEhKbErYC9xi地址:1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD
生成创世区块(赋于第一个地址100Tokens)
> genesis -a 12BwtcVWimms9rrKxxoCev68woGyMYS4sk -v 100已成生成创世区块
日志1实时查看日志(可以看见挖矿过程)
tail -f log9000.txt
5.同步区块
节点2、节点3依次更改配置文件的端标语为9001,9002,启动这两个节点来同步创世区块;
这时节点1的日志检测到网路中存在的其他节点。
节点2、节点3启动后会手动同步创世区块
6.进行转账操作
每位节点设置挖矿奖励地址(也可以不设置,不设置的情况下,节点挖到矿后不会形成奖励);
节点1设置挖矿奖励地址:
> setRewardAddr -a 12BwtcVWimms9rrKxxoCev68woGyMYS4sk已设置地址12BwtcVWimms9rrKxxoCev68woGyMYS4sk为挖矿奖励地址!
节点2设置挖矿奖励地址:
> setRewardAddr -a 1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS已设置地址1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS为挖矿奖励地址!
节点3设置挖矿奖励地址:
> setRewardAddr -a 1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD已设置地址1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD为挖矿奖励地址!
节点1进行转账操作(创世地址像其他两个地址每位汇款10Tokens)。
> transfer -from ["12BwtcVWimms9rrKxxoCev68woGyMYS4sk","12BwtcVWimms9rrKxxoCev68woGyMYS4sk"] -to ["1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS","1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD"] -amount [10,10]已执行转帐命令
7.查看余额
三个节点中,由节点2挖到区块,里所应该节点2获得挖矿奖励25Tokens
此时在任意节点敲入getBalance查看余额命令,可以查看三个地址的余额信息
> getBalance -a 12BwtcVWimms9rrKxxoCev68woGyMYS4sk地址:12BwtcVWimms9rrKxxoCev68woGyMYS4sk的余额为:80> getBalance -a 1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS地址:1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS的余额为:35> getBalance -a 1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD地址:1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD的余额为:10
8.查看区块详尽信息
任意节点输入printAllBlock命令查看区块信息
区块1为创世区块,只有赋于12BwtcVWimms9rrKxxoCev68woGyMYS4sk的100UTXO输出
可以看见区块2:
第一笔交易,地址12BwtcVWimms9rrKxxoCev68woGyMYS4sk先花掉创世区块额度为100的UTXO,给自身生成一个90UTXO,给地址1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS生成10UTXO。
第二笔交易地址12BwtcVWimms9rrKxxoCev68woGyMYS4sk使用第一笔交易输出的90额度的UTXO,给自身生成一个80UTXO以及给地址1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD生成10UTXO。
第三笔交易为挖矿奖励交易,所以只有输出,没有输入,给地址1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS生成25UTXO(在配置文件中设置的25奖励额度)
> printAllBlock ========================================================================================================本块hash 00000008acfb9a8dcf3bb923f4eb6f2ddfc27dcaff861ea6848a9074ca46d85b ------------------------------交易数据------------------------------ 本次交易id: 988ecbe7f374855aa94addb873f22960cf43646bdaeb562533f3e683478270db tx_input: 交易id: bb717bd6717c8cae3829875187b97f256859277ad4a52ac57cdbc132895ca154 索引: 0 签名信息: 8c8b0628ceadebbc9e97b490a40a23494d3f8286f1af045f1e1f18d529c49a90afa194799182c264ee15871b5dd35c773e5dd46427fc8e2c268356ce09f6b60b 公钥: 8e0f1fe7d6177f11027818663048392cee8952cefcf1ceeec8edc84e176f46cedd338575f709b412eeab904d7027056354038f8aef7a1940f45264f7116ba793 地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk tx_output: 金额: 90 公钥Hash: 0d0a1aeb1baf838828a54ac97b09524f0b0c3210 地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk --------------- 金额: 10 公钥Hash: 6eb2d1846217aa089dfa26e3147b767e1de0b08d 地址: 1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS 本次交易id: 443b4a4f04204bd8ed2bdfcc096642a27457c27aa47c2ee81486d7440b059521 tx_input: 交易id: 988ecbe7f374855aa94addb873f22960cf43646bdaeb562533f3e683478270db 索引: 0 签名信息: 2a064297227ba07c7ea92eebb1d43f3fe4dfbd6c7e78be8ec2d1d30e20fa51500c8bdb591c11908a877aeef61b4c64f9a851cc44af441cbe6893e1b80e42032c 公钥: 8e0f1fe7d6177f11027818663048392cee8952cefcf1ceeec8edc84e176f46cedd338575f709b412eeab904d7027056354038f8aef7a1940f45264f7116ba793 地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk tx_output: 金额: 80 公钥Hash: 0d0a1aeb1baf838828a54ac97b09524f0b0c3210 地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk --------------- 金额: 10 公钥Hash: 8fa79c32a067830be3b16ade637d370e1d1e6e0d 地址: 1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD 本次交易id: 2420c67272ab7832d6148a36a6b38166862d12e265f184439e6ab2e606b01245 tx_input: tx_output: 金额: 25 公钥Hash: 6eb2d1846217aa089dfa26e3147b767e1de0b08d 地址: 1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS --------------------------------------------------------------------时间戳 2019-11-18 03:23:57 PM区块高度 2随机数 2808567053068705071上一个块hash 0000007d7b7c7b540d9d1b0d1d06b6936e1bc613f6ab7de1ae0275cdaef4e4a4========================================================================================================本块hash 0000007d7b7c7b540d9d1b0d1d06b6936e1bc613f6ab7de1ae0275cdaef4e4a4 ------------------------------交易数据------------------------------ 本次交易id: bb717bd6717c8cae3829875187b97f256859277ad4a52ac57cdbc132895ca154 tx_input: 交易id: 索引: -1 签名信息: 公钥: 地址: tx_output: 金额: 100 公钥Hash: 0d0a1aeb1baf838828a54ac97b09524f0b0c3210 地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk --------------------------------------------------------------------时间戳 2019-11-18 10:43:41 AM区块高度 1随机数 8604076799988393002上一个块hash 0000000000000000000000000000000000000000000000000000000000000000========================================================================================================
9.其他
你也可以在节点2,节点3发起汇款,不过首先须要通过助记词导出皮夹信息,反例如下:
importMnword -m ["扭伤","剪创","肌病","下陷","广发","浊音","斜疝"]
文章评论