Network Synchronization

Synchronizing blockchain state across network nodes.

Advanced⏱️ 55 min📚 Prerequisites: 1

Network Synchronization

Network sync ensures all nodes have the same blockchain state. New nodes need to download and verify the entire blockchain.

Sync Process

  1. Initial Handshake: Connect to peers
  2. Get Best Block: Find highest block height
  3. Request Blocks: Download blocks in batches
  4. Validate Blocks: Verify each block
  5. Update State: Apply blocks to local state
  6. Catch Up: Continue until synced

Sync Strategies

Full Sync

Download and validate every block:

RUST
fn full_sync(node: &mut Node, target_height: u64) {
    let mut current_height = node.blockchain.height();
    
    while current_height < target_height {
        let blocks = request_blocks(current_height, 100);
        for block in blocks {
            if validate_block(&block) {
                node.blockchain.add_block(block);
                current_height += 1;
            }
        }
    }
}

Fast Sync

Download block headers first, then bodies:

  • Faster initial sync
  • Verify headers first
  • Download bodies in parallel

Light Sync

Only download block headers:

  • For light clients
  • Verify headers only
  • Request full blocks when needed

State Sync

RUST
struct SyncState {
    current_height: u64,
    target_height: u64,
    is_syncing: bool,
    blocks_downloaded: u64,
}

impl SyncState {
    fn progress(&self) -> f64 {
        if self.target_height == 0 {
            return 0.0;
        }
        (self.current_height as f64 / self.target_height as f64) * 100.0
    }
}

Fork Resolution During Sync

  • Multiple chains: Request from multiple peers
  • Compare: Find common ancestor
  • Choose: Select longest valid chain
  • Reorganize: Switch to better chain if found

Optimization

  • Parallel downloads: Download from multiple peers
  • Batch requests: Request multiple blocks at once
  • Caching: Cache verified blocks
  • Checkpointing: Trust checkpoints for faster sync

Code Examples

Sync State

Tracking synchronization progress

RUST
struct SyncState {
    current_height: u64,
    target_height: u64,
    is_syncing: bool,
}
impl SyncState {
    fn new() -> Self {
        SyncState {
            current_height: 0,
            target_height: 0,
            is_syncing: false,
        }
    }
    fn start_sync(&mut self, target: u64) {
        self.target_height = target;
        self.is_syncing = true;
        println!("Starting sync to height {}", target);
    }
    fn update_progress(&mut self, new_height: u64) {
        self.current_height = new_height;
        if self.current_height >= self.target_height {
            self.is_syncing = false;
            println!("Sync complete!");
        } else {
            let progress = (self.current_height as f64 / self.target_height as f64) * 100.0;
            println!("Sync progress: {:.1}% ({}/{})",
                    progress, self.current_height, self.target_height);
        }
    }
    fn is_complete(&self) -> bool {
        !self.is_syncing && self.current_height >= self.target_height
    }
}
fn main() {
    let mut sync = SyncState::new();
    sync.start_sync(1000);
    sync.update_progress(250);
    sync.update_progress(500);
    sync.update_progress(750);
    sync.update_progress(1000);
    println!("Sync complete: {}", sync.is_complete());
}

Explanation:

Sync state tracks the synchronization progress. It monitors current height, target height, and calculates progress percentage.

Block Request

Requesting blocks from peers

RUST
struct BlockRequest {
    from_height: u64,
    count: u64,
}
struct SyncManager {
    current_height: u64,
    target_height: u64,
}
impl SyncManager {
    fn new() -> Self {
        SyncManager {
            current_height: 0,
            target_height: 0,
        }
    }
    fn request_blocks(&self, batch_size: u64) -> BlockRequest {
        let remaining = self.target_height - self.current_height;
        let count = remaining.min(batch_size);
        BlockRequest {
            from_height: self.current_height + 1,
            count,
        }
    }
    fn process_blocks(&mut self, blocks_received: u64) {
        self.current_height += blocks_received;
        println!("Processed {} blocks. Current height: {}",
                blocks_received, self.current_height);
    }
}
fn main() {
    let mut manager = SyncManager {
        current_height: 100,
        target_height: 1000,
    };
    let request = manager.request_blocks(100);
    println!("Requesting {} blocks from height {}",
            request.count, request.from_height);
    manager.process_blocks(100);
}

Explanation:

Block requests are made in batches for efficiency. The sync manager tracks what blocks are needed and requests them from peers.

Exercises

Sync Progress

Create a sync manager that tracks progress!

Medium

Starter Code:

RUST
struct SyncManager {
    current: u64,
    target: u64,
}
fn main() {
    let mut sync = SyncManager::new();
    sync.target = 1000;
    sync.update_progress(500);
    println!("Progress: {}%", sync.get_progress_percentage());
}