Picture bitcoin Part 5: how to concurrence gracefully?


Note: for the sake of brevity, this article only deals with some key codes and structures. Recommended download source code, see the detailed implementation.


Part 1 completes the “handshake”, Part 2 completes the “heartbeat” information, Part 3 loads the matching file, and Part 4 completes the operation of the local database.

Next, we will get the blockheads of other nodes and store them locally.

1.2 code address

Picturesque bitcoin Part 5: how to concurrence gracefully?

1.3 environment preparation

Install btcwallet

  1. cd ~/.tmp

  2. git clone https://github.com/btcsuite/btcwallet

  3. cd btcwallet

  4. go install -v . ./cmd/...

Creating wallets

Next, create two wallets: one for miner and one for Alice

  1. btcwallet -C ./btcwallet.conf --create

Note: btcwallet.conf And other configuration files are in the source code.

Enter the private passphrase for your new wallet:

Confirm passphrase:

Do you want to add an additional layer of encryption for public data? (n/no/y/yes) [no]: no

Do you have an existing wallet seed you want to use? (n/no/y/yes) [no]: no

Your wallet generation seed is:


Once you have stored the seed in a safe and secure location, enter "OK" to continue: OK

Creating the wallet...

[INF] WLLT: Opened wallet

You need to enter four options to create. The password is set to 1, then no, no, OK

  1. Start two terminals, start btcd server and wallet server respectively

// Console window 1

$ btcd --configfile ./btcd.conf

// Console window 2

$ btcwallet -C ./btcwallet.con
  1. Create wallet user

$ btcctl -C ./btcctl-wallet.conf walletpassphrase 1 3600

$ btcctl -C ./btcctl-wallet.conf createnewaccount alice

$ btcctl -C ./btcctl-wallet.conf listaccounts


"alice": 0,

"default": 0,

"imported": 0

  1. Check the addresses of miner and Alice

// Unlock your wallet first

$ btcctl -C ./btcctl-wallet.conf walletpassphrase 1 3600

$ btcctl -C ./btcctl-wallet.conf getnewaddress


$ btcctl -C ./btcctl-wallet.conf getnewaddress alice

  1. Restart btcd server with miner address

$ btcd --configfile ./btcd.conf --miningaddr=MINER_ADDRESS
  1. Generate test blocks and transactions

$ btcctl -C ./btcctl.conf generate 100

[...a hundred of hashes...]

$ btcctl -C ./btcctl-wallet.conf getbalance


1.4 getheaders communication protocol


Added inprotocol version 31800.

The “getheaders” message requests a “headers” message that provides block headers starting from a particular point in the block chain. It allows a peer which has been disconnected or started for the first time to get the headers it hasn’t seen yet.

The “getheaders” message is nearly identical to the “getblocks” message, with one minor difference: the inv reply to the “getblocks” message will include no more than 500 block header hashes; the headers reply to the “getheaders” message will include as many as 2,000 block headers.

By sending the getheaders message, you can get the block header.

type  MsgGetHeaders  struct {

ProtocolVersion uint32

BlockLocatorHashes []*chainhash.Hash

HashStop chainhash.Hash


1.5 Share Memory By Communicating

Go’s concurrency primitives – goroutines and channels – provide an elegant and distinct means of structuring concurrent software.Instead of explicitly using locks to mediate access to shared data, Go encourages the use of channels to pass references to data between goroutines. This approach ensures that only one goroutine has access to the data at a given time.

Golang processing concurrent usegoroutines and channelsIt’s simple and intuitive.

Golang passedchannelsPass a reference to the data to ensure that there is only one at a timegoroutineYou can access the data.

The traditional synchronization method is to use lock

func Poller(res *Resources) {

for {

// get the least recently-polled Resource

// and mark it as being polled


var r *Resource

for _, v := range res.data {

if v.polling {



if r == nil || v.lastPolled < r.lastPolled {

r = v



if r != nil {

r.polling = true



if r == nil {



// poll the URL

// update the Resource's polling and lastPolled


r.polling = false

r.lastPolled = time.Nanoseconds()




The implementation of golang is as follows:

type Resource string

func Poller(in, out chan *Resource) {

for r := range in {

// poll the URL

// send the processed Resource to out

out <- r



1.6 getting headers

Picture bitcoin Part 5: how to concurrence gracefully?Picture bitcoin Part 5: how to concurrence gracefully?

As shown in the figure above, theheadersThere are sixgoroutine

adoptchannel:newPeers,newPeerMsg,outputQueueAnd so on.

1.7 testing

$ go run ./ --configfile ./configke.conf

reference material:

Share Memory By Communicating

Bitcoin Protocol documentation

This work adoptsCC agreementReprint must indicate the author and the link of this article