Account Model & State
The vProgs account model draws inspiration from Solana’s design: accounts hold state data, and transactions pre-declare the accounts they will read and write. This pre-declaration is the key enabler of parallel processing on Kaspa’s BlockDAG – the system can identify non-conflicting transactions and process them concurrently without risking state corruption.
Core Design
Accounts as State Containers
In the vProgs model, an account is a stateful data container owned by a specific vProg. Each vProg p owns an exclusive set of accounts S_p:
- Accounts hold arbitrary state data relevant to the owning vProg
- Write access to
S_pis exclusive to vProgp– no other program can modify these accounts - Read access is permissioned across programs, enabling cross-vProg composability
- Each account has a well-defined state at every point in the global sequence
T
Sovereign Ownership
The exclusivity of account ownership is a foundational security property:
vProg A vProg B vProg C
+-----------+ +-----------+ +-----------+
| Account 1 | | Account 4 | | Account 7 |
| Account 2 | | Account 5 | | Account 8 |
| Account 3 | | Account 6 | | Account 9 |
+-----------+ +-----------+ +-----------+
S_a S_b S_c
- Write: only A - Write: only B - Write: only C
- Read: A, B, C (*) - Read: A, B, C (*) - Read: A, B, C (*)
(*) Cross-vProg reads require concise witnesses
This design means:
- No shared mutable state between programs – eliminates reentrancy attack classes
- Independent failure domains – a bug in vProg A cannot corrupt vProg B’s state
- Per-vProg resource regulation – each program controls its own gas scales and STORM constants
- Parallel proving – provers for different vProgs can operate without coordination
Transaction Structure
Each transaction x specifies three sets:
| Set | Symbol | Description |
|---|---|---|
| Read set | r(x) |
Accounts the transaction will read |
| Write set | w(x) |
Accounts the transaction will modify |
| Witness set | pi(x) |
Dependency resolution data (concise witnesses) |
A critical constraint: w(x) must be a subset of r(x) – every account that is written must also be read. This ensures that the transaction has full context for any state it modifies.
Pre-Declaration Benefits
Declaring read/write sets upfront provides several architectural advantages:
- Parallel scheduling: Non-conflicting transactions (disjoint write sets) can be processed concurrently on the BlockDAG
- Deterministic conflict detection: The sequencing layer can identify and correctly serialize conflicting operations
- Scope computation: Provers can determine exactly which state they need to access
- Gas estimation: Resource costs can be calculated before execution
- MEV resistance: Deterministic scheduling reduces front-running opportunities
Computation DAG
The account model gives rise to a Computation DAG (CD) – a directed acyclic graph that tracks dependencies between account states across time.
Vertices and Edges
- Vertices:
v = (a, t)– represent accounta’s state at timetin the global sequence - Hyperedges: Transactions connect input vertices (reads) to output vertices (writes)
Time --> t1 t2 t3 t4
Acct A: v(A,t1) ---------> v(A,t3) ----------> v(A,t4)
\ /
\ tx_2 / tx_3
\ /
Acct B: v(B,t1) -> v(B,t2) ----+
tx_1
tx_1: reads A,B; writes B
tx_2: reads A; writes A
tx_3: reads A,B; writes A
Dynamic dependency relationships form naturally as transactions reference each other’s outputs. This graph structure is what enables:
- Scope computation – tracing backward to find what state a prover needs
- Proof anchoring – compressing history at proven checkpoints
- Parallelism identification – finding non-conflicting transaction sets
State Compression via Proof Anchoring
When a ZK proof is submitted and verified, it creates a trustless anchor point in the computation DAG. This enables:
- Historical vertex deletion: State before the anchor can be pruned
- Reduced scope computation: Future transactions only need to trace back to the nearest anchor
- Efficient state verification: The anchor’s state commitment is cryptographically guaranteed
Before anchoring:
v1 -> v2 -> v3 -> v4 -> v5 -> v6 -> v7 -> v8
[------- full scope for proving v8 ---------]
After anchoring at v5 (ZK proof verified):
[pruned] -> [anchor v5] -> v6 -> v7 -> v8
[-- reduced scope for v8 --]
State Commitments
Each vProg’s state is periodically committed to L1 via a hierarchical Merkle structure:
C_p^t = MerkleRoot(
state_root_step_1,
state_root_step_2,
...
state_root_step_n
)
Where each state_root_step_i is the Merkle root of all account states in S_p at step i since the last proof submission.
Concise Witnesses
This hierarchical structure enables concise witnesses – compact Merkle inclusion proofs that attest to a specific account’s state at a specific time. A concise witness proves:
“Account
ain vProgphad statesat timet”
…with a proof size logarithmic in the number of accounts and steps.
Concise witnesses are the mechanism that enables synchronous composability: when vProg_A needs to read state from vProg_B, it provides a concise witness as part of the transaction’s witness set pi(x).
Parallelism on the BlockDAG
The pre-declared read/write sets interact with Kaspa’s BlockDAG structure to enable parallel processing:
Conflict Detection
Two transactions x and y conflict if their write sets overlap:
conflict(x, y) <=> w(x) intersection w(y) != empty set
Non-conflicting transactions can be processed in any order or in parallel. Conflicting transactions must be serialized.
DAG-Aware Scheduling
The BlockDAG naturally enables parallel block production. With pre-declared account sets:
- Miners include transactions in parallel blocks
- DagKnight provides precise ordering of these parallel blocks
- Conflicting transactions in parallel blocks are correctly serialized by consensus
- Non-conflicting transactions execute in parallel, regardless of block ordering
Block 1 (miner A): Block 2 (miner B):
tx_1: w={acct_1} tx_2: w={acct_3} <-- no conflict,
tx_3: w={acct_2} tx_4: w={acct_4} parallel OK
Block 3 (miner C):
tx_5: w={acct_1} <-- conflicts with
tx_1, serialized
by DagKnight
Scaling Properties
The parallelism scales with the number of independent account domains:
- A network with 1000 active vProgs, each with disjoint accounts, can process 1000 streams of transactions in parallel
- Cross-vProg reads do not create write conflicts (read-only access)
- Only cross-vProg writes (which are forbidden – write access is exclusive) would create inter-program conflicts
Resource Management
Each vProg autonomously controls its own resource economy:
Gas Scales
Custom pricing for computation within a vProg. A compute-intensive vProg (e.g., ZK proof aggregation) can set higher gas prices than a simple token transfer vProg.
STORM Constants
Regulate state growth and throughput per vProg:
- Storage growth rate – how fast accounts can be created
- Throughput caps – maximum transactions per epoch
- State size limits – bounds on total account data
Storage Costs
Transactions requiring permanent storage must compensate per the vProg’s defined scales. This internalizes the externality of state bloat – the vProg’s users pay for the state they consume.
Base Network Fee Proposal
In anticipation of the advanced capabilities introduced by vProgs, developers are actively discussing a 100x increase to the standard minimum network fee. This proposed change is designed to better secure the network against spam by making it significantly more expensive for attackers to flood blocks with low-value or arbitrary transactions.
Core developers are actively debating this minimum fee policy to balance micropayment viability with network abuse prevention. The current proposal is viewed as a temporary measure against spam rather than a long-term fee solution, and importantly, it can be adjusted by miners without requiring a hardfork.
Phase 1 vs. Phase 2 Account Model
Phase 1: Standalone (Current Target)
In Phase 1, the L1 has no notion of individual accounts within a vProg:
- L1 is aware only of the overall vProg entity through its L1 covenant
- The “degenerate” CD commit scheme groups activity by programs/subnets, not accounts
- Each vProg is modeled as a single KIP-21 lane
- Account-level state management is entirely internal to the vProg
Phase 2: Full Account Model
In Phase 2, the L1 gains awareness of per-account state:
- Extended Computation DAG with per-account vertices
- Cross-vProg atomic transactions via concise witnesses
- Account-level read/write declarations in transactions
- Full synchronous composability
The transition from Phase 1 to Phase 2 does not change the KIP-21 outer machinery – only the lane-local update rules change from program-level to account-level.
Comparison to Other Models
| Property | EVM (Ethereum) | Solana | vProgs |
|---|---|---|---|
| State model | Global shared state | Account-based with pre-declaration | Account-based with pre-declaration |
| Write access | Any contract can call any other | Programs own accounts | Exclusive write per vProg |
| Read access | Unrestricted | Unrestricted | Permissioned via concise witnesses |
| Execution | On-chain re-execution | On-chain parallel execution | Off-chain, ZK-verified |
| Conflict handling | Serial (single thread) | Parallel (non-conflicting) | Parallel (BlockDAG + pre-declaration) |
| Reentrancy risk | Yes (shared mutable state) | Mitigated (program ownership) | Eliminated (exclusive write + ZK) |
| State bloat | Global problem | Global problem | Per-vProg regulation |
Further Reading
- Execution Model – how off-chain computation produces proofs
- Synchronous Composability – how concise witnesses enable cross-vProg reads
- L1 Sequencing (KIP-21) – how lanes map to vProg state
- Formal backbone model for vProg computation DAG
- Concrete proposal for synchronously composable vProgs