wire_common

btcd/wire/common.go

基于chan的buf管理

type binaryFreeList chan []byte //数字缓冲区
type scriptFreeList chan []byte //脚本缓冲区

这里的思路还是比较巧妙的,使用了chan的方式来管理[]byte,减少了不断的分配[]byte,同时使用chan来规避锁的问题.
我不知道go内部chan写入读出是否要用到锁,但是至少规避了List的管理.

Borrow 方法: 如果有可用的缓冲区则取走,否则分配
Return 方法:将用完的缓冲区通过chan放回去,为下次Borrow做准备.

这里面预设了最大的缓冲区大小,总的来说还是满巧妙的.

VarInt编码

0-0xfd 直接是0xfd,
0xfd-maxuint16 0xfd+ 两个字节的数值本身
maxuint16-maxuint32 0xfe+加四字节数值本身
maxuint32-maxuint64 0xff+8字节数值本身

实际上这类似于以太坊的RLP编码思路,

VarBytes,VarString编码方式

VarInt编码的长度+数据本身

比特币的消息通信

消息往来

    Peer A Sends                          Peer B Responds
----------------------------------------------------------------------------
getaddr message (MsgGetAddr)          addr message (MsgAddr)
getblocks message (MsgGetBlocks)      inv message (MsgInv)
inv message (MsgInv)                  getdata message (MsgGetData)
getdata message (MsgGetData)          block message (MsgBlock) -or-
                                      tx message (MsgTx) -or-
                                      notfound message (MsgNotFound)
getheaders message (MsgGetHeaders)    headers message (MsgHeaders)
ping message (MsgPing)                pong message (MsgHeaders)* -or-
                                      (none -- Ability to send message is enough)

读取消息

pver是消息版本信息,(BIP定义了很多版本),目前是FeeFilterVersion 70013
btcnet 有四种情况,分别如下

	// MainNet represents the main bitcoin network.
	MainNet BitcoinNet = 0xd9b4bef9

	// TestNet represents the regression test network.
	TestNet BitcoinNet = 0xdab5bffa

	// TestNet3 represents the test network (version 3).
	TestNet3 BitcoinNet = 0x0709110b

	// SimNet represents the simulation test network.
	SimNet BitcoinNet = 0x12141c16
	// Use the most recent protocol version supported by the package and the
	// main bitcoin network.
	pver := wire.ProtocolVersion
	btcnet := wire.MainNet

	// Reads and validates the next bitcoin message from conn using the
	// protocol version pver and the bitcoin network btcnet.  The returns
	// are a wire.Message, a []byte which contains the unmarshalled
	// raw payload, and a possible error.
	msg, rawPayload, err := wire.ReadMessage(conn, pver, btcnet)
	if err != nil {
		// Log and handle the error
	}

发送消息

	// Use the most recent protocol version supported by the package and the
	// main bitcoin network.
	pver := wire.ProtocolVersion
	btcnet := wire.MainNet

	// Create a new getaddr bitcoin message.
	msg := wire.NewMsgGetAddr()

	// Writes a bitcoin message msg to conn using the protocol version
	// pver, and the bitcoin network btcnet.  The return is a possible
	// error.
	err := wire.WriteMessage(conn, msg, pver, btcnet)
	if err != nil {
		// Log and handle the error
	}

消息类型验证

	// Assumes msg is already a valid concrete message such as one created
	// via NewMsgVersion or read via ReadMessage.
	switch msg := msg.(type) {
	case *wire.MsgVersion:
		// The message is a pointer to a MsgVersion struct.
		fmt.Printf("Protocol version: %v", msg.ProtocolVersion)
	case *wire.MsgBlock:
		// The message is a pointer to a MsgBlock struct.
		fmt.Printf("Number of tx in block: %v", msg.Header.TxnCount)
	}