图说比特币 Part 1
ke_chain · · 809 次点击 · · 开始浏览1.1引言
这个系列使用golang从零开始写一个比特币轻量化节点。最终达到和实际的比特币网络进行交易和SPV(Simplified Payment Verification)。
注意:大部分代码都源自BTCD,实际上也是一个BTCD源码分析文章。最终实现以下功能:
- 连接到比特币的网络(包括 mainnet, testnet, simnet)
- 加入到比特币网络("version handshake")
- 向其他节点获取blockchain state
- 下载blockhain heads
- 实现SPV(Simplified Payment Verification)
- 交易比特币
注:阅读前请确认已经对比特币的区块链结构已经有初步的了解。
1.2代码地址
1.3搭建测试网络
编程初期我们使用BCTD自带的测试网络。测试网络的配置如下:
# btcd.conf
[Application Options]
datadir=./btcd/data
listen=127.0.0.1:9333
simnet=1
nobanning=1
debuglevel=debug
-
listen是测试网络的ip -
simnet代表模拟网络(Simulation Network) -
nobanning不要禁止任何节点 -
debuglevel=debug输出日志信息
启动终端输入命令: btcd --configfile ./btcd.conf 即可启动测试网络。
1.4 节点建立连接
比特币系统中,节点通过进行初始 "握手",建立连接。
Version:版本消息(关键内容:版本号,当前节点区块链的区块高度)
Verack:确认已收到消息
part 1 的最终效果就是与比特币网络发送和接受消息,建立连接。
1.5代码结构
1.6 时序图
1.7 通信协议
追求妹子的第一步是了解对方想要什么,比如刚认识的时候首先看看颜值,颜值不行的基本就是冷处理备胎好人卡三连了。节点间通信也是一样,一开始的时候先看看版本,版本不行的也是被拒绝的下场。
// #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 VersionsServices代表节点支持的服务。暂时使用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())
1.8测试:
结果如下:
$ go run ./
INFO[0000] version70013
INFO[0000] verack
1.9总结:
关键内容是message的解构,有消息头和消息组成。
最终发送的消息字节序列格式:
BYTES(Msg.magic) + BYTES(Msg.Command()) + BYTES(Msg.length) + BYTES(Msg.checksum) + BYTES(Msg.BtcEncode())
参考资料:
BTCD
比特币消息协议
Tinybit
《比特币白皮书》
《解构区块链》
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
1.1引言
这个系列使用golang从零开始写一个比特币轻量化节点。最终达到和实际的比特币网络进行交易和SPV(Simplified Payment Verification)。
注意:大部分代码都源自BTCD,实际上也是一个BTCD源码分析文章。最终实现以下功能:
- 连接到比特币的网络(包括 mainnet, testnet, simnet)
- 加入到比特币网络("version handshake")
- 向其他节点获取blockchain state
- 下载blockhain heads
- 实现SPV(Simplified Payment Verification)
- 交易比特币
注:阅读前请确认已经对比特币的区块链结构已经有初步的了解。
1.2代码地址
1.3搭建测试网络
编程初期我们使用BCTD自带的测试网络。测试网络的配置如下:
# btcd.conf
[Application Options]
datadir=./btcd/data
listen=127.0.0.1:9333
simnet=1
nobanning=1
debuglevel=debug
-
listen是测试网络的ip -
simnet代表模拟网络(Simulation Network) -
nobanning不要禁止任何节点 -
debuglevel=debug输出日志信息
启动终端输入命令: btcd --configfile ./btcd.conf 即可启动测试网络。
1.4 节点建立连接
比特币系统中,节点通过进行初始 "握手",建立连接。
Version:版本消息(关键内容:版本号,当前节点区块链的区块高度)
Verack:确认已收到消息
part 1 的最终效果就是与比特币网络发送和接受消息,建立连接。
1.5代码结构
1.6 时序图
1.7 通信协议
追求妹子的第一步是了解对方想要什么,比如刚认识的时候首先看看颜值,颜值不行的基本就是冷处理备胎好人卡三连了。节点间通信也是一样,一开始的时候先看看版本,版本不行的也是被拒绝的下场。
// #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 VersionsServices代表节点支持的服务。暂时使用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())
1.8测试:
结果如下:
$ go run ./
INFO[0000] version70013
INFO[0000] verack
1.9总结:
关键内容是message的解构,有消息头和消息组成。
最终发送的消息字节序列格式:
BYTES(Msg.magic) + BYTES(Msg.Command()) + BYTES(Msg.length) + BYTES(Msg.checksum) + BYTES(Msg.BtcEncode())