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
Flattening Order
flatten uses depth-first traversal:
import { Rlp } from 'tevm'
const nested = {
type: 'list' ,
value: [
{ type: 'bytes' , value: new Uint8Array ([ 1 ]) }, // #1
{
type: 'list' ,
value: [
{ type: 'bytes' , value: new Uint8Array ([ 2 ]) }, // #2
{ type: 'bytes' , value: new Uint8Array ([ 3 ]) } // #3
]
},
{ type: 'bytes' , value: new Uint8Array ([ 4 ]) } // #4
]
}
const flat = Rlp . flatten ( nested )
// => [
// { type: 'bytes', value: [1] }, // #1
// { type: 'bytes', value: [2] }, // #2
// { type: 'bytes', value: [3] }, // #3
// { type: 'bytes', value: [4] } // #4
// ]
Usage Patterns
Extract all byte values from transaction:
import { Rlp } from 'tevm'
const txBytes = new Uint8Array ([ ... ])
const decoded = Rlp . decode ( txBytes )
// Flatten to get all fields
const fields = Rlp . flatten ( decoded . data )
// Access individual fields
const [ nonce , gasPrice , gas , to , value , data , v , r , s ] = fields . map ( f => f . value )
console . log ( 'Nonce:' , nonce )
console . log ( 'To:' , to )
console . log ( 'Signature r:' , r )
Extract all nodes from Merkle proof:
import { Rlp } from 'tevm'
const proofBytes = new Uint8Array ([ ... ])
const decoded = Rlp . decode ( proofBytes )
// Flatten to get all nodes
const nodes = Rlp . flatten ( decoded . data ). map ( n => n . value )
console . log ( `Proof has ${ nodes . length } nodes` )
// Verify each node
for ( const node of nodes ) {
verifyNode ( node )
}
Extract all data from event logs:
import { Rlp } from 'tevm'
const logBytes = new Uint8Array ([ ... ])
const decoded = Rlp . decode ( logBytes )
// Flatten to get all byte values
const allData = Rlp . flatten ( decoded . data )
// First item is address
const address = allData [ 0 ]. value
// Topics follow
const topics = allData . slice ( 1 , - 1 ). map ( t => t . value )
// Last item is data
const data = allData [ allData . length - 1 ]. value
console . log ( 'Address:' , address )
console . log ( 'Topics:' , topics )
console . log ( 'Data:' , data )
Count Byte Values
Count total byte values in nested structure:
import { Rlp } from 'tevm'
function countByteValues ( rlpData : BrandedRlp ) : number {
return Rlp . flatten ( rlpData ). length
}
const nested = {
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 count = countByteValues ( nested )
console . log ( `Contains ${ count } byte values` ) // 3
Extract all hash values from trie:
import { Rlp } from 'tevm'
function extractHashes ( trieNode : BrandedRlp ) : Uint8Array [] {
return Rlp . flatten ( trieNode )
. map ( item => item . value )
. filter ( bytes => bytes . length === 32 ) // Filter 32-byte hashes
}
const trieBytes = new Uint8Array ([ ... ])
const decoded = Rlp . decode ( trieBytes )
const hashes = extractHashes ( decoded . data )
console . log ( `Found ${ hashes . length } hashes` )
Search for Value
Search for specific byte value in nested structure:
import { Rlp } from 'tevm'
function findValue (
rlpData : BrandedRlp ,
target : Uint8Array
) : boolean {
const flattened = Rlp . flatten ( rlpData )
for ( const item of flattened ) {
if ( item . value . length === target . length ) {
if ( item . value . every (( b , i ) => b === target [ i ])) {
return true
}
}
}
return false
}
const nested = { ... }
const target = new Uint8Array ([ 1 , 2 , 3 ])
if ( findValue ( nested , target )) {
console . log ( 'Found target value' )
}
Calculate Total Data Size
Calculate total bytes in nested structure:
import { Rlp } from 'tevm'
function calculateTotalBytes ( rlpData : BrandedRlp ) : number {
return Rlp . flatten ( rlpData ). reduce (
( sum , item ) => sum + item . value . length ,
0
)
}
const nested = { ... }
const totalBytes = calculateTotalBytes ( nested )
console . log ( `Total: ${ totalBytes } bytes` )
Return Type
flatten returns an array of BytesData:
type BytesData = {
type : "bytes"
value : Uint8Array
}
// Example
const flat : BytesData [] = Rlp . flatten ( data )
// Access values
for ( const item of flat ) {
console . log ( 'Type:' , item . type ) // Always "bytes"
console . log ( 'Value:' , item . value ) // Uint8Array
}
Algorithm
Conceptual implementation:
function flatten ( data : BrandedRlp ) : BytesData [] {
const result : BytesData [] = []
function visit ( d : BrandedRlp ) {
if ( d . type === 'bytes' ) {
result . push ( d )
} else {
// Recursively visit list items
for ( const item of d . value ) {
visit ( item )
}
}
}
visit ( data )
return result
}
Depth-first Traversal
Input:
┌─────────────────────┐
│ List │
│ ├─ Bytes [1] │ <-- Visit #1
│ └─ List │
│ ├─ Bytes [2] │ <-- Visit #2
│ └─ Bytes [3] │ <-- Visit #3
└─────────────────────┘
Output:
[
{ type: 'bytes', value: [1] }, // #1
{ type: 'bytes', value: [2] }, // #2
{ type: 'bytes', value: [3] } // #3
]
Complexity
Time : O(n) where n is total number of items
Space : O(n) for result array + O(d) for recursion depth
flatten is more convenient than manual extraction:
import { Rlp } from 'tevm'
const decoded = Rlp . decode ( bytes )
// Using flatten (simple)
const values = Rlp . flatten ( decoded . data ). map ( item => item . value )
// Manual extraction (verbose)
const values : Uint8Array [] = []
function extract ( data : BrandedRlp ) {
if ( data . type === 'bytes' ) {
values . push ( data . value )
} else {
for ( const item of data . value ) {
extract ( item )
}
}
}
extract ( decoded . data )
Caching
Cache flattened results for repeated access:
import { Rlp } from 'tevm'
class FlatCache {
private cache = new Map < string , BytesData []>()
flatten ( data : BrandedRlp ) : BytesData [] {
const key = Rlp . encode ( data ). toString ()
let cached = this . cache . get ( key )
if ( ! cached ) {
cached = Rlp . flatten ( data )
this . cache . set ( key , cached )
}
return cached
}
}
See Also