这个系列使用golang从零开始写一个比特币轻量化节点。最终达到和实际的比特币网络进行交易和SPV(Simplified Payment Verification)。
注意:大部分代码都源自BTCD,实际上也是一个**BTCD源码分析**文章。最终实现以下功能:
连接到比特币的网络(包括 mainnet, testnet, simnet)加入到比特币网络(“version handshake”)向其他节点获取blockchain state下载blockhain heads实现SPV(Simplified Payment Verification)交易比特币注:阅读前请确认已经对比特币的区块链结构已经有初步的了解。
图说比特币Part_1
编程初期我们使用BCTD自带的测试网络。测试网络的配置如下:
# btcd.conf [Application Options] datadir=./btcd/data listen=127.0.0.1:9333 simnet=1 nobanning=1 debuglevel=debug listen 是测试网络的ipsimnet 代表模拟网络(Simulation Network)nobanning 不要禁止任何节点debuglevel=debug 输出日志信息启动终端输入命令: btcd --configfile ./btcd.conf 即可启动测试网络。
比特币系统中,节点通过进行初始 “握手”,建立连接。 Version:版本消息(关键内容:版本号,当前节点区块链的区块高度) Verack:确认已收到消息
part 1 的最终效果就是与比特币网络发送和接受消息,建立连接。
追求妹子的第一步是了解对方想要什么,比如刚认识的时候首先看看颜值,颜值不行的基本就是冷处理备胎好人卡三连了。节点间通信也是一样,一开始的时候先看看版本,版本不行的也是被拒绝的下场。
// #msgversion.go type MsgVersion struct { // Version of the protocol the node is using. ProtocolVersion int32 // Bitfield which identifies the enabled services. Services ServiceFlag // Time the message was generated. This is encoded as an int64 on the wire. Timestamp time.Time // Address of the remote peer. AddrYou NetAddress // Address of the local peer. AddrMe NetAddress // Unique value associated with message that is used to detect self // connections. Nonce uint64 // The user agent that generated messsage. This is a encoded as a varString // on the wire. This has a max length of MaxUserAgentLen. UserAgent string // Last block seen by the generator of the version message. LastBlock int32 // Don't announce transactions to peer. DisableRelayTx bool }ProtocolVersion表示协议版本,版本号越大则代表版本越新。详见Protocol Versions
Services 代表节点支持的服务。暂时使用1表示全节点
UserAgent 类似于http协议的User-Agent ,包含节点软件的名称和版本
LastBlock 代表最新区块的高度
MsgVersion代表了需要发送的内容。 由于消息的底层是字节序列,所有我们需要约定好字节序列的格式。
// #message.go type messageHeader struct { magic BitcoinNet // 4 bytes command string // 12 bytes length uint32 // 4 bytes checksum [4]byte // 4 bytes } magic 表示网络类型,目前用SimNet表示测试网络。command 表示命令名称,目前用CmdVersion表示这是获取版本的命令。length 表示数据内容的长度。checksum 数据内容的双重哈希。数据内容的获取接口为下方的BtcEncode。 数据内容的最大长度的获取接口为下方的MaxPayloadLength。 命令名称的获取接口为下方的Command。
// #message.go type Message interface { BtcDecode(io.Reader, uint32, MessageEncoding) error BtcEncode(io.Writer, uint32, MessageEncoding) error Command() string MaxPayloadLength(uint32) uint32 }最终发送的消息字节序列格式:
BYTES(Msg.magic) + BYTES(Msg.Command()) + BYTES(Msg.length) + BYTES(Msg.checksum) + BYTES(Msg.BtcEncode())结果如下:
$ go run ./ INFO[0000] version70013 INFO[0000] verack关键内容是message的解构,有消息头和消息组成。
最终发送的消息字节序列格式:
BYTES(Msg.magic) + BYTES(Msg.Command()) + BYTES(Msg.length) + BYTES(Msg.checksum) + BYTES(Msg.BtcEncode())参考资料: BTCD 比特币消息协议 Tinybit 《比特币白皮书》 《解构区块链》
