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

> Compare two RLP data structures for equality

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

<Tabs />

## BrandedRlp Type

```typescript theme={null}
type BrandedRlp =
  | { type: "bytes"; value: Uint8Array }
  | { type: "list"; value: BrandedRlp[] }
```

### Bytes Comparison

Compares byte-by-byte:

```typescript theme={null}
import { Rlp } from 'tevm'

const a = { type: 'bytes', value: new Uint8Array([1, 2, 3]) }
const b = { type: 'bytes', value: new Uint8Array([1, 2, 3]) }
Rlp.equals(a, b)
// => true

// Different length
const c = { type: 'bytes', value: new Uint8Array([1, 2]) }
Rlp.equals(a, c)
// => false

// Different values
const d = { type: 'bytes', value: new Uint8Array([1, 2, 4]) }
Rlp.equals(a, d)
// => false

// Empty bytes
const empty1 = { type: 'bytes', value: Bytes() }
const empty2 = { type: 'bytes', value: Bytes() }
Rlp.equals(empty1, empty2)
// => true
```

### List Comparison

Compares recursively:

```typescript theme={null}
import { Rlp } from 'tevm'

const list1 = {
  type: 'list',
  value: [
    { type: 'bytes', value: new Uint8Array([1]) },
    { type: 'bytes', value: new Uint8Array([2]) }
  ]
}

const list2 = {
  type: 'list',
  value: [
    { type: 'bytes', value: new Uint8Array([1]) },
    { type: 'bytes', value: new Uint8Array([2]) }
  ]
}

Rlp.equals(list1, list2)
// => true

// Different length
const list3 = {
  type: 'list',
  value: [
    { type: 'bytes', value: new Uint8Array([1]) }
  ]
}
Rlp.equals(list1, list3)
// => false

// Different order
const list4 = {
  type: 'list',
  value: [
    { type: 'bytes', value: new Uint8Array([2]) },
    { type: 'bytes', value: new Uint8Array([1]) }
  ]
}
Rlp.equals(list1, list4)
// => false
```

### Nested Comparison

Deeply nested structures are compared recursively:

```typescript theme={null}
import { Rlp } from 'tevm'

const nested1 = {
  type: 'list',
  value: [
    { type: 'bytes', value: new Uint8Array([1]) },
    {
      type: 'list',
      value: [
        { type: 'bytes', value: new Uint8Array([2]) },
        { type: 'bytes', value: new Uint8Array([3]) }
      ]
    }
  ]
}

const nested2 = {
  type: 'list',
  value: [
    { type: 'bytes', value: new Uint8Array([1]) },
    {
      type: 'list',
      value: [
        { type: 'bytes', value: new Uint8Array([2]) },
        { type: 'bytes', value: new Uint8Array([3]) }
      ]
    }
  ]
}

Rlp.equals(nested1, nested2)
// => true
```

## Usage Patterns

### Transaction Comparison

Compare decoded transactions:

```typescript theme={null}
import { Rlp } from 'tevm'

const tx1Bytes = new Uint8Array([...])
const tx2Bytes = new Uint8Array([...])

const tx1 = Rlp.decode(tx1Bytes)
const tx2 = Rlp.decode(tx2Bytes)

if (Rlp.equals(tx1.data, tx2.data)) {
  console.log('Transactions are identical')
}
```

### Deduplication

Deduplicate RLP data structures:

```typescript theme={null}
import { Rlp } from 'tevm'

function deduplicate(items: BrandedRlp[]): BrandedRlp[] {
  const unique: BrandedRlp[] = []

  for (const item of items) {
    const isDuplicate = unique.some(existing =>
      Rlp.equals(existing, item)
    )
    if (!isDuplicate) {
      unique.push(item)
    }
  }

  return unique
}

const items = [
  { type: 'bytes', value: new Uint8Array([1]) },
  { type: 'bytes', value: new Uint8Array([2]) },
  { type: 'bytes', value: new Uint8Array([1]) },  // Duplicate
]

const unique = deduplicate(items)
// => [{ type: 'bytes', value: [1] }, { type: 'bytes', value: [2] }]
```

### Cache Key Generation

Use equality for cache lookups:

```typescript theme={null}
import { Rlp } from 'tevm'

class RlpCache {
  private cache: Array<{ key: BrandedRlp; value: any }> = []

  get(key: BrandedRlp): any | undefined {
    const entry = this.cache.find(e => Rlp.equals(e.key, key))
    return entry?.value
  }

  set(key: BrandedRlp, value: any): void {
    // Remove existing entry if present
    this.cache = this.cache.filter(e => !Rlp.equals(e.key, key))
    this.cache.push({ key, value })
  }
}
```

### Test Assertions

Compare expected vs actual in tests:

```typescript theme={null}
import { Rlp } from 'tevm'
import { expect } from 'vitest'

test('encodes transaction correctly', () => {
  const tx = [
    new Uint8Array([0x00]),
    new Uint8Array([0x01])
  ]

  const encoded = Rlp.encode(tx)
  const decoded = Rlp.decode(encoded)

  const expected = {
    type: 'list',
    value: [
      { type: 'bytes', value: new Uint8Array([0x00]) },
      { type: 'bytes', value: new Uint8Array([0x01]) }
    ]
  }

  expect(Rlp.equals(decoded.data, expected)).toBe(true)
})
```

### Merkle Proof Verification

Compare proof nodes:

```typescript theme={null}
import { Rlp } from 'tevm'

function verifyProof(
  leaf: BrandedRlp,
  proof: BrandedRlp[],
  root: BrandedRlp
): boolean {
  let current = leaf

  for (const node of proof) {
    // Hash current with proof node
    const combined = {
      type: 'list' as const,
      value: [current, node]
    }
    current = hashRlp(combined)
  }

  return Rlp.equals(current, root)
}
```

## Performance

### Comparison Algorithm

```typescript theme={null}
// Conceptual implementation
function equals(a: BrandedRlp, b: BrandedRlp): boolean {
  // Different types
  if (a.type !== b.type) {
    return false
  }

  // Bytes comparison
  if (a.type === 'bytes' && b.type === 'bytes') {
    if (a.value.length !== b.value.length) return false
    for (let i = 0; i < a.value.length; i++) {
      if (a.value[i] !== b.value[i]) return false
    }
    return true
  }

  // List comparison (recursive)
  if (a.type === 'list' && b.type === 'list') {
    if (a.value.length !== b.value.length) return false
    for (let i = 0; i < a.value.length; i++) {
      if (!equals(a.value[i], b.value[i])) return false
    }
    return true
  }

  return false
}
```

### Complexity

* **Time**: O(n) where n is total number of bytes in all data structures
* **Space**: O(d) where d is recursion depth (for nested lists)
* **Early exit**: Returns false on first mismatch

### Short-circuit Optimization

Comparison short-circuits on first difference:

```typescript theme={null}
import { Rlp } from 'tevm'

// Large lists with difference at start
const list1 = {
  type: 'list',
  value: [
    { type: 'bytes', value: new Uint8Array([1]) },
    ...Array(1000).fill({ type: 'bytes', value: new Uint8Array([2]) })
  ]
}

const list2 = {
  type: 'list',
  value: [
    { type: 'bytes', value: new Uint8Array([99]) },  // Different
    ...Array(1000).fill({ type: 'bytes', value: new Uint8Array([2]) })
  ]
}

// Returns false after checking only first element
Rlp.equals(list1, list2)
// => false (fast - doesn't check all 1000 elements)
```

### Alternative: Encoded Comparison

For faster comparison, compare encoded bytes:

```typescript theme={null}
import { Rlp } from 'tevm'

function fastEquals(a: BrandedRlp, b: BrandedRlp): boolean {
  const aEncoded = Rlp.encode(a)
  const bEncoded = Rlp.encode(b)

  if (aEncoded.length !== bEncoded.length) return false

  for (let i = 0; i < aEncoded.length; i++) {
    if (aEncoded[i] !== bEncoded[i]) return false
  }

  return true
}

// Faster for deeply nested structures
// But requires encoding overhead
```

## See Also

* [encode](/primitives/rlp/encode) - Encode data to RLP
* [decode](/primitives/rlp/decode) - Decode RLP bytes
* [validate](/primitives/rlp/validate) - Validate RLP structure
* [Types](/primitives/rlp/types) - RLP type system
