Skip to main content

Try it Live

Run RLP examples in the interactive playground

RLP WASM Implementation

High-performance WebAssembly RLP encoder compiled from Zig for performance-critical operations.

Overview

The WASM implementation provides accelerated RLP encoding methods compiled from Zig. Currently supports encoding operations with significant performance improvements over JavaScript. Features:
  • Fast encoding - Compiled Zig code for maximum performance
  • Memory efficient - Zero-copy operations where possible
  • Type safe - TypeScript bindings with full type safety
  • Drop-in replacement - Compatible with JavaScript API
Currently Available:
  • encodeBytes - Encode byte arrays
  • encodeUint - Encode 256-bit unsigned integers
  • toHex / fromHex - Hex conversion utilities

Setup

WASM module loads automatically when available:
import * as RlpWasm from 'tevm/Rlp.wasm'

// WASM methods available immediately
const encoded = RlpWasm.encodeBytes(new Uint8Array([1, 2, 3]))

encodeBytes

Encode byte arrays using WASM.

    Performance

    WASM encodeBytes significantly faster than JavaScript:
    import { Rlp } from 'tevm'
    import * as RlpWasm from 'tevm/Rlp.wasm'
    
    // Benchmark encoding 10,000 byte arrays
    const items = Array({ length: 10000 }, () =>
      new Uint8Array(100).fill(0x42)
    )
    
    // JavaScript implementation
    console.time('JS encode')
    for (const item of items) {
      Rlp.encodeBytes(item)
    }
    console.timeEnd('JS encode')
    // JS encode: ~50ms
    
    // WASM implementation
    console.time('WASM encode')
    for (const item of items) {
      RlpWasm.encodeBytes(item)
    }
    console.timeEnd('WASM encode')
    // WASM encode: ~10ms (5x faster)
    

    encodeUint

    Encode 256-bit unsigned integers.

      encodeUintFromBigInt

      Encode bigint directly to RLP.

        Hex Utilities

        Convert between RLP bytes and hex strings.

          Architecture

          //! RLP encoding implementation in Zig
          //! Compiled to WebAssembly for browser/Node.js use
          
          const std = @import("std");
          const Hex = @import("../Hex/Hex.zig");
          
          /// Maximum recursion depth
          pub const MAX_RLP_DEPTH: u32 = 32;
          
          /// Encode byte array to RLP
          pub fn encodeBytes(allocator: Allocator, bytes: []const u8) ![]u8 {
              // Efficient implementation with minimal allocations
          }
          
          /// Encode u256 value to RLP
          pub fn encodeUint(allocator: Allocator, value: [32]u8) ![]u8 {
              // Optimized integer encoding
          }
          
          Source: Rlp.zig:1-1489

          Benefits

          Performance:
          • Compiled to optimized WASM bytecode
          • No JIT warmup time
          • Predictable performance characteristics
          Memory:
          • Manual memory management for efficiency
          • Zero-copy operations where possible
          • Minimal allocations
          Safety:
          • Zig’s compile-time safety checks
          • No undefined behavior
          • Bounds checking in debug mode

          When to Use WASM

          Use WASM implementation for: High-throughput encoding:
          import * as RlpWasm from 'tevm/Rlp.wasm'
          
          // Encoding many transactions
          async function encodeBatch(transactions: Transaction[]) {
            return Promise.all(
              transactions.map(async (tx) => {
                const fields = await prepareFields(tx)
                return fields.map(field => RlpWasm.encodeBytes(field))
              })
            )
          }
          
          Large data structures:
          import * as RlpWasm from 'tevm/Rlp.wasm'
          
          // Encoding block with many transactions
          function encodeBlock(block: Block) {
            return {
              header: block.header.map(field => RlpWasm.encodeBytes(field)),
              transactions: block.transactions.map(tx =>
                tx.fields.map(field => RlpWasm.encodeBytes(field))
              ),
              uncles: block.uncles.map(uncle =>
                uncle.map(field => RlpWasm.encodeBytes(field))
              )
            }
          }
          
          Performance-critical paths:
          import * as RlpWasm from 'tevm/Rlp.wasm'
          
          // Real-time transaction signing
          async function signTransaction(tx: Transaction) {
            // Use WASM for encoding (faster)
            const encoded = encodeTransactionFields(tx).map(field =>
              RlpWasm.encodeBytes(field)
            )
          
            // Sign encoded data
            const signature = await sign(encoded)
          
            return { encoded, signature }
          }
          

          Fallback to JavaScript

          WASM loader handles fallback automatically:
          import * as RlpWasm from 'tevm/Rlp.wasm'
          
          // Uses WASM if available, falls back to JS
          const encoded = RlpWasm.encodeBytes(data)
          
          // Check WASM availability
          if (typeof WebAssembly !== 'undefined') {
            console.log('WASM available')
          } else {
            console.log('Using JavaScript fallback')
          }
          

          Limitations

          Current WASM implementation has limitations: No decoding yet:
          // Available: encoding
          import * as RlpWasm from 'tevm/Rlp.wasm'
          const encoded = RlpWasm.encodeBytes(data)
          
          // Not available: decoding (use JS)
          import { Rlp } from 'tevm'
          const decoded = Rlp.decode(encoded)
          
          No list encoding:
          // Not available: encodeList (use JS)
          import { Rlp } from 'tevm'
          const encoded = Rlp.encodeList([bytes1, bytes2])
          
          32-byte constraint for uint:
          // Must be exactly 32 bytes
          const value = Bytes32()
          RlpWasm.encodeUint(value)  // OK
          
          const wrong = Bytes16()
          RlpWasm.encodeUint(wrong)  // Error
          

          Future Enhancements

          Planned WASM features:
          • decode - WASM decoding implementation
          • encodeList - WASM list encoding
          • stream encoding - Streaming encode support
          • parallel encoding - Multi-threaded encoding for large data

          Override Patterns

          Replace JavaScript methods with WASM:
          import { Rlp } from 'tevm'
          import * as RlpWasm from 'tevm/Rlp.wasm'
          
          // Override encodeBytes with WASM version
          const originalEncodeBytes = Rlp.encodeBytes
          Rlp.encodeBytes = RlpWasm.encodeBytes
          
          // Now Rlp.encodeBytes uses WASM
          const encoded = Rlp.encodeBytes(new Uint8Array([1, 2, 3]))
          
          // Restore original
          Rlp.encodeBytes = originalEncodeBytes
          
          Or create hybrid encoder:
          import { Rlp } from 'tevm'
          import * as RlpWasm from 'tevm/Rlp.wasm'
          
          function encodeBytes(data: Uint8Array): Uint8Array {
            // Use WASM for large data
            if (data.length > 1000) {
              return RlpWasm.encodeBytes(data)
            }
          
            // Use JS for small data (less overhead)
            return Rlp.encodeBytes(data)
          }