Benchmarking Parallel vs Serial Transaction Scheduling in Distributed Ledgers
⚠️ WARNING: This is a sample blog to demonstrate available writing features. (Feature: Blockquote / Callout)
During my research fellowship at the Indian Institute of Technology, Hyderabad, we investigated throughput bottlenecks imposed by serial transaction validation in distributed ledger technologies (DLTs).
Most early blockchain platforms process transactions strictly sequentially to prevent race conditions and double-spending. However, this creates an artificial bottleneck on modern multi-core server hardware. By decoupling independent transactions, distributed ledgers can execute state mutations concurrently without violating ACID guarantees1.
1. The Core Bottleneck: Serial Execution
(Feature: Display Math & Inline LaTeX)
In high-frequency ledger state transitions, two transactions that touch disjoint address spaces in the global Merkle state tree have zero data dependency on each other:
Executing only after finishes serializes independent memory writes and wastes CPU idle cycles. Under ideal concurrency with worker threads, Amdahl’s Law speedup is expressed as:
Where represents available execution cores and represents the batch of non-conflicting transactions assigned to core .
2. Architecture & Conflict Graph Scheduling
To achieve parallel execution without runtime lock contention, we developed a custom Transaction Processor on Hyperledger Sawtooth that executes across three coordinated pipeline stages:
- Explicit Address Declaration: Each transaction pre-declares all memory addresses it intends to read from (
inputs) and write to (outputs). - Conflict Graph Construction: The scheduler constructs a Directed Acyclic Graph (DAG) in time, where nodes represent transactions and directed edges represent state hazards (Read-After-Write, Write-After-Read, Write-After-Write).
- Concurrent Worker Dispatch: Independent sub-graphs with topological in-degree are dispatched concurrently across a thread pool.
(Feature: Monospace Preformatted Text / ASCII Diagram)
Incoming Block Batch
│
▼
┌──────────────────────┐
│ Address Parser & DAG │
└──────────┬───────────┘
│
┌─────┴────────────────────────┐
▼ ▼
[Tx 1 (Addr A, B)] [Tx 2 (Addr D, E)] <── No Conflict (In-Degree = 0)
│ (Writes B) │ (Writes D)
▼ ▼
[Tx 3 (Addr B, C)] [Tx 4 (Addr D, F)] <── Dependent (Queued)
3. Implementation Details
(Feature: Fenced Code Block with Syntax Highlighting)
Below is an excerpt from our custom Transaction Processor demonstrating deterministic state validation:
from sawtooth_sdk.processor.handler import TransactionHandler
from sawtooth_sdk.processor.exceptions import InvalidTransaction
class ParallelTransferHandler(TransactionHandler):
@property
def family_name(self):
return 'parallel_transfer'
@property
def namespaces(self):
return [self._namespace]
def apply(self, transaction, context):
"""Execute state transition atomically."""
header = transaction.header
payload = self._decode_payload(transaction.payload)
sender_address = header.inputs[0]
receiver_address = header.outputs[0]
# Verify disjoint address constraint
if sender_address == receiver_address:
raise InvalidTransaction("Self-transfers are invalid")
current_balance = self._get_state(context, sender_address)
if current_balance < payload['amount']:
raise InvalidTransaction("Insufficient balance for transfer")
# Commit state updates
context.set_state({
sender_address: current_balance - payload['amount'],
receiver_address: self._get_state(context, receiver_address) + payload['amount']
})
(Feature: Collapsible Disclosure Widget)
Click to view raw transaction payload schema (JSON)
{
"family": "parallel_transfer",
"version": "1.0",
"inputs": [
"1cf126a8027a442e92c5a083315a6b0c",
"1cf126a8027a442e92c5a083315a6b0d"
],
"outputs": [
"1cf126a8027a442e92c5a083315a6b0d"
],
"amount": 250
}
(Feature: Keyboard Input Tags)
To terminate the benchmark run during evaluation, send the interrupt signal via Ctrl + C in your terminal session.
# Execute 10,000 synthetic transactions across 8 worker cores
python3 benchmark_runner.py \
--workload=uniform \
--transactions=10000 \
--batch-size=128 \
--workers=8 \
--output=results_parallel.json
4. Experimental Results & Benchmarks
(Feature: Formatted Data Table with Column Alignments)
We measured transaction throughput (Transactions Per Second — TPS) and average commit latency across varying worker core allocations and contention levels:
| Worker Cores | Workload Pattern | Serial TPS | Parallel TPS | Latency (ms) | Speedup Factor |
|---|---|---|---|---|---|
| 1 Core | Uniform (Low Contention) | 420 | 418 | 48.2 ms | 1.00x |
| 2 Cores | Uniform (Low Contention) | 420 | 798 | 26.1 ms | 1.90x |
| 4 Cores | Uniform (Low Contention) | 420 | 1,420 | 15.3 ms | 3.38x |
| 8 Cores | Uniform (Low Contention) | 420 | 2,650 | 9.8 ms | 6.31x |
| 8 Cores | Skewed Hotspot (90% Contention) | 420 | 580 | 38.5 ms | 1.38x |
Key Observations
(Feature: Nested Unordered List)
- Linear Scaling in Low-Contention Scenarios:
- When transactions operate on independent state keys, throughput scales almost linearly up to 8 physical cores.
- Memory bus synchronization remains below 12% overhead.
- Contention Bottlenecks:
- Under heavy hotspot skew (e.g. 90% of transactions modifying the same token balance), dependency graph edges serialize execution, demonstrating that parallel scheduling benefits are bound by workload partitioning.
5. Engineering Roadmap & Checklist
(Feature: Task / Checklists)
Here is the tracking status of our transaction engine optimizations:
- Conflict Graph DAG generator with topological resolution
- Multi-threaded concurrent transaction dispatcher in Python & C++
- Zero-copy memory state caching layer for high-throughput reads
- Adaptive dynamic batching based on real-time address conflict heuristics
- Hardware-accelerated cryptographic signature validation with SIMD/AVX-512
6. Conclusion & Summary
Deterministic transaction scheduling shifts concurrency arbitration from runtime locks to compile-time dependency graphs, enabling modern ledgers to scale with multicore server hardware. This study validated that decoupled state machines can achieve over 6x throughput gains on modern hardware when transactions explicitly declare input and output namespaces.
(Feature: Footnotes)
Footnotes
-
ACID guarantees in distributed systems ensure Atomicity, Consistency, Isolation, and Durability across distributed consensus state updates. ↩