> ## Documentation Index
> Fetch the complete documentation index at: https://voltaire.tevm.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# RLP Serialization

> JSON serialization with toJSON and fromJSON for persistence

<Card title="Try it Live" icon="play" href="https://playground.tevm.sh?example=primitives/rlp.ts">
  Run RLP examples in the interactive playground
</Card>

# 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.

<Tabs>
  <TabItem label="Signature">
    ```typescript theme={null}
    function toJSON(data: BrandedRlp): unknown
    ```

    **Parameters:**

    * `data: BrandedRlp` - RLP data structure

    **Returns:**

    * `unknown` - JSON-serializable representation (object with type and value)

    Source: [toJSON.js:14-26](https://github.com/evmts/voltaire/blob/main/src/primitives/Rlp/BrandedRlp/toJSON.js#L14-L26)
  </TabItem>

  <TabItem label="Usage">
    ```typescript theme={null}
    import { Rlp } from 'tevm'

    // Convert bytes data
    const bytes = { type: 'bytes', value: new Uint8Array([1, 2, 3]) }
    const json = Rlp.toJSON(bytes)
    // => { type: 'bytes', value: [1, 2, 3] }

    // Convert list data
    const list = {
      type: 'list',
      value: [
        { type: 'bytes', value: new Uint8Array([1]) },
        { type: 'bytes', value: new Uint8Array([2]) }
      ]
    }
    const json = Rlp.toJSON(list)
    // => {
    //   type: 'list',
    //   value: [
    //     { type: 'bytes', value: [1] },
    //     { type: 'bytes', value: [2] }
    //   ]
    // }

    // Convert nested structures
    const nested = {
      type: 'list',
      value: [
        { type: 'bytes', value: new Uint8Array([1]) },
        {
          type: 'list',
          value: [{ type: 'bytes', value: new Uint8Array([2]) }]
        }
      ]
    }
    const json = Rlp.toJSON(nested)

    // Stringify for storage
    const jsonString = JSON.stringify(json)
    localStorage.setItem('rlpData', jsonString)

    // Instance method
    const rlpData = new Rlp(new Uint8Array([1, 2, 3]))
    const json = rlpData.toJSON()
    ```
  </TabItem>
</Tabs>

### JSON Format

`toJSON` converts Uint8Array to number arrays while preserving structure:

```typescript theme={null}
// 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.

<Tabs>
  <TabItem label="Signature">
    ```typescript theme={null}
    function fromJSON(json: unknown): BrandedRlp
    ```

    **Parameters:**

    * `json: unknown` - JSON object from toJSON

    **Returns:**

    * `BrandedRlp` - RLP data structure

    **Throws:**

    * `Error('UnexpectedInput')` - Invalid JSON format
    * `Error('UnexpectedInput')` - Bytes value not array
    * `Error('UnexpectedInput')` - List value not array
    * `Error('UnexpectedInput')` - Invalid type field

    Source: [fromJSON.js:16-47](https://github.com/evmts/voltaire/blob/main/src/primitives/Rlp/BrandedRlp/fromJSON.js#L16-L47)
  </TabItem>

  <TabItem label="Usage">
    ```typescript theme={null}
    import { Rlp } from 'tevm'

    // Restore bytes data
    const json = { type: 'bytes', value: [1, 2, 3] }
    const data = Rlp.fromJSON(json)
    // => { type: 'bytes', value: Uint8Array([1, 2, 3]) }

    // Restore list data
    const listJson = {
      type: 'list',
      value: [
        { type: 'bytes', value: [1] },
        { type: 'bytes', value: [2] }
      ]
    }
    const list = Rlp.fromJSON(listJson)

    // Restore from storage
    const jsonString = localStorage.getItem('rlpData')
    const json = JSON.parse(jsonString)
    const data = Rlp.fromJSON(json)

    // Validate and restore
    try {
      const data = Rlp.fromJSON(untrustedJson)
    } catch (error) {
      console.error('Invalid RLP JSON:', error.message)
    }
    ```
  </TabItem>
</Tabs>

### Validation

`fromJSON` validates structure:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
// 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)
```

<Aside type="caution">
  JSON serialization converts Uint8Array to number arrays. For large byte arrays, this significantly increases size. Consider RLP encoding for efficient storage.
</Aside>

## Related

* [Types](/primitives/rlp/types) - RLP type system
* [Utilities](/primitives/rlp/utilities) - Helper methods
* [Encoding](/primitives/rlp/encoding) - Binary encoding
* [Decoding](/primitives/rlp/decoding) - Binary decoding
