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.
Try it Live
Run RLP examples in the interactive playground
BrandedRlp Type
type BrandedRlp =
| { type: "bytes"; value: Uint8Array }
| { type: "list"; value: BrandedRlp[] }
Bytes Comparison
Compares byte-by-byte:
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:
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:
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:
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:
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:
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:
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:
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)
}
Comparison Algorithm
// 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:
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:
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