How to synchronise all nodes in a blockchain

Viewed 555

There are two parts to what I'm trying to do here - 1. Create a blockchain structure and 2. Enable P2P communication between 3 nodes. Part 1 can easily be done as there multiple sources online on how to code a blockchain structure. Here's what I've done for Part 1:

# Creating "getdata" request payload
def create_payload_getdata(tx_id):
    count = 1
    type = 1
    hash = bytearray.fromhex(tx_id)
    payload = struct.pack("<bb32s", count, type, hash)
    return payload

# Print req/res data
def print_response(command, req_data, res_data):
    print("")
    print("Command: "+command)
    print("Request:")
    print(binascii.hexlify(req_data))
    print("Response")
    print(binascii.hexlify(res_data))

if __name__ == '__main__':
    # magic value for the main network
    magic_value = 0xd9b4bef9
    tx_id = "fc57704eff327aecfadb2cf3774edc919ba69aba624b836461ce2be9c00a0c20"
    peer_ip_address = '104.199.184.15'
    peer_tcp_port = 8333
    buffer_size = 1024

    # Create Request Objects
    ver_payload = create_payload_ver(peer_ip_address)
    ver_msg = create_message(magic_value, 'version', ver_payload)
    ver_ack_msg = create_message_verack()
    get_data_payload = create_payload_getdata(tx_id)
    get_data_msg = create_message(magic_value, "getdata", get_data_payload)

    # Establish TCP connection
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((peer_ip_address, peer_tcp_port))

    # Send message "version"
    s.send(ver_msg)
    res_data = s.recv(buffer_size)
    print_response("version", ver_msg, res_data);

    # Send msg "verack"
    s.send(ver_ack_msg)
    res_data = s.recv(buffer_size)
    print_response("verack", ver_ack_msg, res_data)

    # Send msg "getdata"
    s.send(get_data_msg)
    res_data = s.recv(buffer_size)
    print_response("getdata", get_data_msg, res_data)

    s.close()

However, for Part 2, I'm not sure how I can get all 3 nodes to synchronise their own blockchain when a change in the blockchain occurs (i.e adding a block to the block chain). All 3 nodes can serve as a client and server, but never both at the same time. For example, in the figure below, Node 1 is the Client while Node 2 is the Server. Node 3 will not be taking part in the transaction, but it will update its own blockchain once the transaction between Node 1 and Node 2 is complete.

enter image description here

A simple code snippet on how to synchronise the blockchain between 3 nodes, or even a link directing to a blockchain synchronisation implementing sockets in Python would be helpful.

1 Answers

Well bitcoin starts by asking the peer for inventories. This is a hash and a height of a block. The peer checks if they have this block already and checks it is the same as the checkpoints they are using, if they do not yet have the block corresponding to this inventory and the hash is the same as their checkpoints then they save the inventory. They keep asking for inventories until they have an inventory all the way up to the chain tip. At this point they recursively ask for each block corresponding to the inventories they have saved. Once they get the block they validate it and save it - updating the UTXO set and txindex (if enabled) as they go. This is called IBD and is done when the node has been offline. When a node is online and a block is found the peer that found the block will "rumor" the block with all the peers it has. Basically it sends the hash and the height (yes the inventory of the block) to all its connected peers, if a peer does not have that block yet then it asks for the block data and gets the block. Then all the peers do the same, they send the inventory of the new block to all their connected peers (other than the peer(s) that they received the block from).

I don't know of any simple to follow syncing code in python (though a google search should wield results (search for toy cryptocurrency python), it is not in python and works for DAG based blockchains instead but i am in the process of writing the following syncing code (it is not finished and is horribly messy). It is written in rust and uses my self made rust p2p lib build on top of tcpstreams/sockets

TLDR; New nodes ask for a list of the hashes of blocks since the last block they have, they then save this and ask for the corresponding block from the peer. Existing nodes send a hash and height pair to connected nodes when they hear about a new block, when a node receives this they check if they have the block - if they haven't then they ask for the block data, validate the block, save it and enact it. They then send the same hash and height pair to all their connected nodes.

I hope this helps answer your question!

Related