Skip to main content

Try it Live

Run RLP examples in the interactive playground

RLP Serialization

Convert RLP data structures to and from JSON for persistence, debugging, and transmission.

Overview

RLP serialization provides JSON conversion for:
  • Persistence - Save RLP structures to databases or files
  • Debugging - Human-readable representation
  • Transmission - Send over JSON APIs
  • Testing - Compare structures in test assertions

toJSON

Convert RLP data to JSON-serializable format.

    JSON Format

    toJSON converts Uint8Array to number arrays while preserving structure:
    // Bytes data: Uint8Array → number[]
    {
      type: 'bytes',
      value: [1, 2, 3]  // Array of numbers
    }
    
    // List data: recursive conversion
    {
      type: 'list',
      value: [/* JSON representations of items */]
    }
    

    fromJSON

    Convert JSON representation back to RLP data.

      Validation

      fromJSON validates structure:
      import { Rlp } from 'tevm'
      
      // Missing fields
      try {
        Rlp.fromJSON({ type: 'bytes' })
      } catch (error) {
        // Error: Invalid JSON format
      }
      
      // Invalid type
      try {
        Rlp.fromJSON({ type: 'invalid', value: [] })
      } catch (error) {
        // Error: Invalid type: invalid
      }
      
      // Bytes value not array
      try {
        Rlp.fromJSON({ type: 'bytes', value: 'not-array' })
      } catch (error) {
        // Error: Bytes value must be array
      }
      
      // List value not array
      try {
        Rlp.fromJSON({ type: 'list', value: 'not-array' })
      } catch (error) {
        // Error: List value must be array
      }
      

      Round-trip Serialization

      Convert to JSON and back produces equal structures:
      import { Rlp } from 'tevm'
      
      const original = {
        type: 'list',
        value: [
          { type: 'bytes', value: new Uint8Array([1, 2, 3]) },
          {
            type: 'list',
            value: [{ type: 'bytes', value: new Uint8Array([4, 5]) }]
          }
        ]
      }
      
      // Convert to JSON
      const json = Rlp.toJSON(original)
      
      // Convert back
      const restored = Rlp.fromJSON(json)
      
      // Should be equal
      console.log(Rlp.equals(original, restored))  // true
      

      Use Cases

      Database Storage

      Store RLP structures in JSON databases:
      import { Rlp } from 'tevm'
      
      // Save transaction
      async function saveTransaction(tx: BrandedRlp) {
        const json = Rlp.toJSON(tx)
        await db.transactions.insert({
          id: generateId(),
          data: json,
          createdAt: new Date()
        })
      }
      
      // Load transaction
      async function loadTransaction(id: string): Promise<BrandedRlp> {
        const record = await db.transactions.findById(id)
        return Rlp.fromJSON(record.data)
      }
      

      API Transmission

      Send RLP data over HTTP APIs:
      import { Rlp } from 'tevm'
      
      // Client: send RLP data
      async function submitData(data: BrandedRlp) {
        const json = Rlp.toJSON(data)
        const response = await fetch('/api/rlp', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(json)
        })
        return response.json()
      }
      
      // Server: receive RLP data
      app.post('/api/rlp', (req, res) => {
        try {
          const data = Rlp.fromJSON(req.body)
          // Process RLP data
          const result = processRlp(data)
          res.json({ success: true, result })
        } catch (error) {
          res.status(400).json({ error: error.message })
        }
      })
      

      Debugging

      Pretty-print RLP structures:
      import { Rlp } from 'tevm'
      
      function debugRlp(data: BrandedRlp) {
        const json = Rlp.toJSON(data)
        console.log('RLP Structure:')
        console.log(JSON.stringify(json, null, 2))
      }
      
      // Example output:
      // {
      //   "type": "list",
      //   "value": [
      //     {
      //       "type": "bytes",
      //       "value": [1, 2, 3]
      //     },
      //     {
      //       "type": "bytes",
      //       "value": [4, 5, 6]
      //     }
      //   ]
      // }
      

      Testing

      Compare RLP structures in tests:
      import { Rlp } from 'tevm'
      
      test('encodes transaction correctly', () => {
        const tx = buildTransaction(/* ... */)
        const encoded = Rlp.encode(tx)
        const decoded = Rlp.decode(encoded)
      
        // Compare using JSON (easier to debug failures)
        expect(Rlp.toJSON(decoded.data)).toEqual(Rlp.toJSON(tx))
      
        // Or use equals
        expect(Rlp.equals(decoded.data, tx)).toBe(true)
      })
      

      Caching

      Cache RLP structures as JSON:
      import { Rlp } from 'tevm'
      
      class RlpCache {
        private cache = new Map<string, string>()
      
        set(key: string, data: BrandedRlp) {
          const json = JSON.stringify(Rlp.toJSON(data))
          this.cache.set(key, json)
        }
      
        get(key: string): BrandedRlp | undefined {
          const json = this.cache.get(key)
          if (!json) return undefined
          return Rlp.fromJSON(JSON.parse(json))
        }
      
        has(key: string): boolean {
          return this.cache.has(key)
        }
      }
      

      Migration

      Convert between RLP versions:
      import { Rlp } from 'tevm'
      
      // Old format migration
      function migrateOldFormat(oldData: any): BrandedRlp {
        // Convert old format to JSON
        const json = convertOldToJson(oldData)
      
        // Parse as RLP
        return Rlp.fromJSON(json)
      }
      
      // Version upgrade
      function upgradeV1ToV2(v1Data: BrandedRlp): BrandedRlp {
        const json = Rlp.toJSON(v1Data)
      
        // Modify JSON structure
        const v2Json = transformV1ToV2(json)
      
        // Parse as new RLP
        return Rlp.fromJSON(v2Json)
      }
      

      Performance Considerations

      JSON vs Binary

      JSON serialization is less efficient than binary RLP:
      import { Rlp } from 'tevm'
      
      const data = {
        type: 'bytes',
        value: new Uint8Array([1, 2, 3])
      }
      
      // RLP encoding (efficient)
      const rlpBytes = Rlp.encode(data)
      console.log('RLP size:', rlpBytes.length)  // 4 bytes
      
      // JSON encoding (verbose)
      const json = JSON.stringify(Rlp.toJSON(data))
      console.log('JSON size:', json.length)  // ~40+ chars
      
      Use RLP for:
      • Network transmission
      • On-chain storage
      • Binary protocols
      Use JSON for:
      • Debugging
      • APIs where JSON expected
      • Database storage
      • Human interaction

      Tree-shaking

      Import only needed functions:
      // Import both
      import { toJSON, fromJSON } from 'tevm/BrandedRlp'
      
      const json = toJSON(data)
      const restored = fromJSON(json)
      
      // Or use namespace
      import { Rlp } from 'tevm'
      const json = Rlp.toJSON(data)