# Understanding Subviews in Lodestar SSZ: A Beginner’s Guide

*What exactly are subviews?*

By [Lady_in_Stem](https://paragraph.com/@devsaisa) · 2025-10-05

---

If you’re exploring **Lodestar’s SSZ library** and you’ve come across terms like `view`, `subview`, or `TreeView`, you might be wondering — _what exactly is a subview and why do I need it?_

Let’s break it down step-by-step, starting from the basics.

* * *

Step 1: What is SSZ?
--------------------

**SSZ (Simple Serialize)** is Ethereum’s serialization format.  
It defines **how Ethereum’s consensus data (like blocks, states, attestations)** are stored, hashed, and transmitted.

In Lodestar (a TypeScript implementation of Ethereum’s consensus layer), SSZ data isn’t stored as plain JavaScript objects.  
Instead, Lodestar uses **Views** — special objects that represent SSZ data **along with its Merkle tree**.

This helps:

*   Make updates efficient (only re-hash the changed part of the tree)
    
*   Support proofs (Merkle branches)
    
*   Keep large data structures consistent
    

* * *

Step 2: What is a View?
-----------------------

A **View** is Lodestar’s in-memory representation of an SSZ value.

*   It behaves _like_ a normal JavaScript object (you can get/set properties).
    
*   But under the hood, it’s backed by a **Merkle tree** (a hash-based data structure).
    
    (If you are not sure what merkle trees are or merkleization , I will post a beginner friendly article explaining those concepts in details.)
    

There are two main kinds:

View Type

Description

**TreeView**

Tree-backed view; any changes are immediately committed to the tree.

**TreeViewDU**

“Delayed Update” view; changes are cached and committed only when you call `.commit()`.

You create views like this:

    import { ssz } from "@lodestar/types";
    
    const attestation = ssz.phase0.Attestation.defaultView();
    

Now `attestation` is a **View** of type `Attestation`.

* * *

Step 3: What is a Subview?
--------------------------

A **Subview** is a _nested view_ — a field inside another view that’s itself a complex SSZ object.  
Think of it as a **branch** inside a bigger Merkle tree.

Example:

    const attestation = ssz.phase0.Attestation.defaultView(); //the main view
    
    attestation.data      // ← This is a subview
    attestation.data.source  // ← Another subview
    attestation.signature // ← Not a subview (it's a byte vector)
    

Visually, you can think of it like this:

    Attestation (root view)
    ├── aggregationBits (basic type)
    ├── data (Subview)
    │   ├── source (Subview)
    │   │   ├── epoch (basic type)
    │   │   └── root (basic type)
    │   └── target (Subview)
    └── signature (basic type)
    

In Lodestar, **each nested SSZ type (like a container, list, or vector)** automatically becomes a subview.

* * *

Step 4: Why Do We Need Subviews?
--------------------------------

Subviews make it possible to **work with parts of large SSZ structures efficiently** — without touching or re-hashing the entire thing.

Let’s see what this means in practice.

### 1⃣ Work with Nested Data Efficiently

Instead of treating an entire object as a single blob, you can zoom into just one part.

    // Create an attestation view
    const att = ssz.phase0.Attestation.defaultView();
    
    // Change a nested field deep inside
    att.data.source.epoch = 10;
    

Under the hood, Lodestar:

*   Updates only the `source` branch of the tree
    
*   Re-hashes just the affected nodes
    
*   Updates the root automatically
    

No need to rebuild the whole object.

* * *

### 2⃣ Replace or Reuse Subtrees

Subviews let you **copy or replace** entire parts of a structure easily.

Example:

    const att1 = ssz.phase0.Attestation.defaultView();
    const att2 = ssz.phase0.Attestation.defaultView();
    
    // Copy `data` from att1 to att2
    att2.data = att1.data;
    

Here you replaced the entire `data` subtree — including `source`, `target`, and everything under it — in one line.  
This is much faster than serializing/deserializing plain JS objects.

* * *

### 3 Support for Merkle Proofs

Subviews are essential for **Merkle proofs**, since they represent subtrees.

For example:

    const proof = attestation.createProof([
      ['data', 'source', 'epoch']
    ]);
    

Here, Lodestar knows exactly how to navigate the tree to isolate `data → source → epoch` — because each is a subview pointing to a subtree.

* * *

Step 5: Subview Independence — View vs ViewDU
---------------------------------------------

There’s a subtle but important behavior difference between **TreeView** and **TreeViewDU** when it comes to subviews.

### TreeView (Immediate Update)

Each subview is **independent**.  
If you assign one subview to another, Lodestar copies the data, but they don’t stay linked.

    const c1 = C.toView({ a: [0, 0] });
    const c2 = C.toView({ a: [1, 1] });
    
    // Copies data — not linked
    c1.a = c2.a;
    
    // Changing c1 doesn’t affect c2
    c1.a.set(0, 5);
    console.log(c2.a.get(0)); // still 1
    

  

### TreeViewDU (Linked Cache)

In `TreeViewDU`, subviews share **mutable caches** for performance.  
So assigning one subview to another links them until you commit.

    const c1 = C.toViewDU({ a: [0, 0] });
    const c2 = C.toViewDU({ a: [1, 1] });
    
    // Now both reference the same cache
    c1.a = c2.a;
    
    // Mutations affect both
    c1.a.set(0, 5);
    console.log(c2.a.get(0)); // 5
    

That’s because DU views prioritize _speed and batching_ over isolation.  
Changes stay in cache until you finalize them with `.commit()`.

* * *

Step 6: When to Use Subviews
----------------------------

Use Case

Why Subviews Help

Large SSZ structures

Update or access only parts without rehashing the whole thing

Proof generation

Each subview corresponds to a Merkle subtree — easy to prove

State updates

Replace only a section of state efficiently

Data reuse

Copy a subtree (e.g. `att1.data = att2.data`)

Testing

Inspect or mutate inner structures directly

* * *

Example Recap
-------------

Here’s a quick end-to-end example showing subviews in action:

    import { ssz } from "@lodestar/types";
    
    // Create a tree-backed view
    const att = ssz.phase0.Attestation.defaultView();
    
    // Work with nested data (subviews)
    att.data.source.epoch = 5;
    att.data.target.epoch = 8;
    
    // Replace a subtree
    const newData = ssz.phase0.AttestationData.defaultView();
    newData.source.epoch = 10;
    att.data = newData;
    
    // Create a proof using subviews
    const proof = att.createProof([
      ['data', 'source', 'epoch'],
    ]);
    
    console.log(att.hashTreeRoot().toString());
    

* * *

In Summary
----------

Concept

Meaning

**View**

Lodestar’s representation of SSZ data in memory (tree-backed).

**Subview**

A nested view (a field that is itself an SSZ type).

**Why it matters**

Enables efficient updates, subtree reuse, and proofs.

**TreeView vs TreeViewDU**

Independent vs linked subviews (immediate vs delayed updates).

**Practical uses**

Efficient state management, proof generation, data reuse.

* * *

### Key Takeaway

> A **Subview** is just a “view within a view” — a nested SSZ structure you can access and manipulate independently.  
> It’s the bridge between Lodestar’s Merkle trees and the object-oriented way TypeScript developers write code.

* * *

Thank you for taking your time to read through this article and if you have any question feel free to reach out. More resources on SSZ here.

[![](https://paragraph.com/editor/youtube/play.png)](https://www.youtube.com/watch?v=p8g6gfzQnD0)

An old video but still important/relevant.

---

*Originally published on [Lady_in_Stem](https://paragraph.com/@devsaisa/understanding-subviews-in-lodestar-ssz-a-beginners-guide)*
