
Suppose a new user wants to boot Nockchain and verify for himself or herself the network's state.
That requires getting a copy of the current network's consensus. A new instance of Nockchain can either boot from scratch and catch up by hearing about every block that has been mined from its peers, or it can start from a “jammed” (serialized) state noun. In either case, much of the time on the network is spent simply listening for a new heaviest block.
The heaviest chain means the chain with the most accumulated proofpower, not simply the longest chain with the most blocks. That protects the network against attacks which would quickly seek a new longest chain while ignoring transactions and established blocks.
Blocks and Block Propagation
A block consists of a set of transactions and a header. Briefly, a header consists of a reference to a previous parent block and a random nonce which satisfies the validity constraints of the ZK proof puzzle. (How a valid header is identified, including the nonce, will be discussed in an upcoming article on the ZK proof puzzle.) Transactions are drawn from the miner's mempool, or the collection of queued transactions received from peer nodes. We will cover transactions in an upcoming article as well, so here we focus here on blocks.
Essentially, a miner runs a process to mine while at the same time it listens for a new heaviest block. (The miner wants to win the current round and gain the block reward, but also wants to start mining on a new heaviest chain as soon as possible in the event that someone else gets there first.)
To establish the new heaviest block, a miner needs to do one more thing than solve the proof puzzle first: It needs to propagate the block to be validated by other nodes.
Validity Checking
While a solution of the proof puzzle indicates that the proof is valid, the transactions in the mempool need to be checked for inclusion and validity, then cleared if the block is correct. New blocks are held as pending until their source transactions can be validated as well.
When transactions are heard, they are checked for signatures and valid inputs. Once all transactions arrive, then the block can be validated and accepted as a heavier block on the chain.
Chain Selection
Nockchain follows Nakamoto consensus with its Zero Knowledge Proof of Work (ZKPoW) protocol. That includes the “heaviest chain” rule, which states that the chain with the most accumulated computational work—as measured by the committed proofpower—is considered the valid and correct chain. This rule is in place to prevent forks and attacks, as an adversary would need to control more than 50% of the network's total computational power to create a heavier competing chain, which is currently infeasible for large networks. Thus this mechanism ensures that the network converges on a single, immutable version of the blockchain.
Since miners are competing to mine the next block by finding the single valid proof puzzle solution, it is unlikely but possible that two miners both find the solution before they know about each other. In that case, a chain split has occurred and portions of the network may (should!) begin to mine on different blocks temporarily. (Nodes and miners are instructed to work on the heaviest chain they observe, which means they will extend the chain with the most proofpower.) Since the heaviest chain is determined by the total proofpower invested, eventually one chain will get ahead of the other decisively and all lighter chains will be discarded. (Their transactions will be rebroadcast for inclusion in future blocks.) This mechanism ensures that the network achieves eventual consistency, with chainwide consensus being restored as the blockchain grows and the probability of a deep reorganization becomes negligible.
In other words, a watching node simply handles a fork by holding its heaviest chain as canonical; transactions that are not included in the known blocks of that heaviest chain remain in the mempool and are communicated around the network to peers. This elegantly simple rule is fundamental to the Nockchain's design (as to other PoW chains), allowing it to maintain liveness even during temporary disagreements until the fork is resolved.
When a block is heard, it's first checked to see if it is already known (a duplicate). The block's digest (its cryptographic hash) and zero-knowledge proof are verified before any further validation. Its parent hash is checked to see on whom it relies. If it is a child of the current heaviest block, then it is validated (including checking included transactions) and mining begins anew on top of it. (The mempool is also cleared of transactions which have already been successfully included.) If it is a child of an older parent, then it is discarded as a lighter chain. If it is a child of a block that hasn't been heard yet, then it may be a side chain that hasn't become heaviest or an out-of-order block from the future of the heaviest chain; in either case, blocks must have known parents or trigger catchup. In the case of a reorganization (when a new heaviest chain of multiple blocks is heard), then ancestor blocks are requested to fill out the missing information. (While this matters philosophically to chain splits, it is an active part of catching up to the network for a new instance.)
State transitions occur at two levels: the global chain state (including the set of validated blocks, the current unspent transaction output set, and transaction indices), which evolves as blocks are added and confirmed; and the individual node state, which can be changed at particular block heights when protocol upgrades are approved by miners adopting the associated software update.
Networking
From an operational standpoint, the Nockchain network consists of users and miners. Connections are maintained between nodes as peer-to-peer channels using libp2p, a networking library. From a practical standpoint, users and miners typically run three kinds of Nockchain instances:
- Mining instances actively compete to produce proofs.
- Backbone or service instances stabilize the network.
- Watcher instances maintain a copy of the current blockchain state (e.g. for wallet or application support).
Miners increase proof generation capacity, and because proofs are lightweight the transaction throughput increases. Block sizes can also be adjusted elastically to prevent congestion on the network and allow smooth scaling as thousands of miners come online.
Backbone and service instances are optimized to support many peer-to-peer connections for users without congesting, and both act as connecting nodes without centralizing mining and facilitate public watcher instances.
Watcher instances include local users running their own nodes to verify the network's state. Public watcher instances enable light client support by exposing the latest chain data for use by wallets, web clients, and other applications. (Succinct proofs and chain consistency guarantees mean that the full chain history is not necessary to verify the current state.)
Since Nakamoto consensus provides a simple rule to determine the canonical chain and establish consensus, efficient peer synchronization is crucial to stabilizing the network and its consensus state. Nockchain uses the established libp2p protocol to communicate transactions and blocks between peers and synchronize the mempool and the chain. Connections with libp2p are bidirectional so the network topology can cleanly propagate changes without bottlenecks.