Skip to main content

Try it Live

Run RLP examples in the interactive playground

    Length Calculation Rules

    Single Byte < 0x80

    import { Rlp } from 'tevm'
    
    const byte = new Uint8Array([0x7f])
    Rlp.getEncodedLength(byte)
    // => 1 (no prefix)
    
    const high = new Uint8Array([0x80])
    Rlp.getEncodedLength(high)
    // => 2 (0x81 prefix + 1 byte)
    

    Short String (0-55 bytes)

    import { Rlp } from 'tevm'
    
    // Empty bytes: [0x80]
    const empty = Bytes()
    Rlp.getEncodedLength(empty)
    // => 1 (just prefix)
    
    // 3 bytes: [0x83, 1, 2, 3]
    const bytes = new Uint8Array([1, 2, 3])
    Rlp.getEncodedLength(bytes)
    // => 4 (1 prefix + 3 bytes)
    
    // 55 bytes: [0xb7, ...55 bytes]
    const max = new Uint8Array(55)
    Rlp.getEncodedLength(max)
    // => 56 (1 prefix + 55 bytes)
    

    Long String (56+ bytes)

    import { Rlp } from 'tevm'
    
    // 56 bytes: [0xb8, 56, ...56 bytes]
    const min = new Uint8Array(56)
    Rlp.getEncodedLength(min)
    // => 58 (1 prefix + 1 length + 56 bytes)
    
    // 256 bytes: [0xb9, 0x01, 0x00, ...256 bytes]
    const large = new Uint8Array(256)
    Rlp.getEncodedLength(large)
    // => 259 (1 prefix + 2 length + 256 bytes)
    
    // 65536 bytes: [0xba, 0x01, 0x00, 0x00, ...65536 bytes]
    const huge = new Uint8Array(65536)
    Rlp.getEncodedLength(huge)
    // => 65540 (1 prefix + 3 length + 65536 bytes)
    

    Short List (< 56 bytes total)

    import { Rlp } from 'tevm'
    
    // Empty list: [0xc0]
    const empty = []
    Rlp.getEncodedLength(empty)
    // => 1 (just prefix)
    
    // List with 2 single bytes: [0xc2, 0x01, 0x02]
    const list = [new Uint8Array([0x01]), new Uint8Array([0x02])]
    Rlp.getEncodedLength(list)
    // => 3 (1 prefix + 2 bytes)
    
    // List with short strings: [0xc7, 0x82, 1, 2, 0x83, 3, 4, 5]
    const strings = [
      new Uint8Array([1, 2]),     // 3 bytes encoded
      new Uint8Array([3, 4, 5])   // 4 bytes encoded
    ]
    Rlp.getEncodedLength(strings)
    // => 8 (1 prefix + 7 bytes payload)
    

    Long List (56+ bytes total)

    import { Rlp } from 'tevm'
    
    // List with 60 bytes total: [0xf8, 60, ...]
    const items = Array({ length: 30 }, () => new Uint8Array([0x01, 0x02]))
    Rlp.getEncodedLength(items)
    // => 62 (1 prefix + 1 length + 60 bytes)
    
    // List with 256 bytes total: [0xf9, 0x01, 0x00, ...]
    const large = Array({ length: 128 }, () => new Uint8Array([0x01, 0x02]))
    Rlp.getEncodedLength(large)
    // => 259 (1 prefix + 2 length + 256 bytes)
    

    Usage Patterns

    Pre-allocate Buffers

    Allocate exact buffer size before encoding:
    import { Rlp } from 'tevm'
    
    const data = [
      new Uint8Array([1, 2, 3]),
      new Uint8Array([4, 5, 6])
    ]
    
    // Calculate size first
    const size = Rlp.getEncodedLength(data)
    console.log(`Need ${size} bytes`)
    
    // Allocate buffer of exact size
    const buffer = new Uint8Array(size)
    
    // Then encode
    const encoded = Rlp.encode(data)
    // encoded.length === size
    

    Batch Size Estimation

    Estimate total size for batches:
    import { Rlp } from 'tevm'
    
    interface Transaction {
      nonce: bigint
      gasPrice: bigint
      gasLimit: bigint
      to: Uint8Array
      value: bigint
      data: Uint8Array
    }
    
    function estimateBatchSize(txs: Transaction[]): number {
      let totalSize = 0
    
      for (const tx of txs) {
        const fields = [
          bigintToBytes(tx.nonce),
          bigintToBytes(tx.gasPrice),
          bigintToBytes(tx.gasLimit),
          tx.to,
          bigintToBytes(tx.value),
          tx.data
        ]
    
        totalSize += Rlp.getEncodedLength(fields)
      }
    
      return totalSize
    }
    
    const txs = [tx1, tx2, tx3]
    const size = estimateBatchSize(txs)
    console.log(`Batch will be ${size} bytes`)
    

    Block Size Calculation

    Calculate block size before encoding:
    import { Rlp } from 'tevm'
    
    interface Block {
      header: BlockHeader
      transactions: Transaction[]
      uncles: BlockHeader[]
    }
    
    function calculateBlockSize(block: Block): number {
      const headerSize = Rlp.getEncodedLength(encodeBlockHeader(block.header))
      const txsSize = block.transactions.reduce(
        (sum, tx) => sum + Rlp.getEncodedLength(encodeTx(tx)),
        0
      )
      const unclesSize = block.uncles.reduce(
        (sum, uncle) => sum + Rlp.getEncodedLength(encodeBlockHeader(uncle)),
        0
      )
    
      return headerSize + txsSize + unclesSize
    }
    

    Network Message Sizing

    Check message sizes before sending:
    import { Rlp } from 'tevm'
    
    const MAX_MESSAGE_SIZE = 10 * 1024 * 1024  // 10 MB
    
    function canSendMessage(data: any[]): boolean {
      const size = Rlp.getEncodedLength(data)
      return size <= MAX_MESSAGE_SIZE
    }
    
    const messages = [...]
    if (canSendMessage(messages)) {
      const encoded = Rlp.encode(messages)
      send(encoded)
    } else {
      console.error('Message too large')
    }
    

    Merkle Tree Size

    Calculate merkle tree proof sizes:
    import { Rlp } from 'tevm'
    
    function calculateProofSize(proof: Uint8Array[]): number {
      return Rlp.getEncodedLength(proof)
    }
    
    const proof = [
      Bytes32().fill(0x01),  // Node 1
      Bytes32().fill(0x02),  // Node 2
      Bytes32().fill(0x03)   // Node 3
    ]
    
    const size = calculateProofSize(proof)
    console.log(`Proof is ${size} bytes`)
    

    Storage Estimation

    Estimate storage requirements:
    import { Rlp } from 'tevm'
    
    interface StorageEntry {
      key: Uint8Array
      value: Uint8Array
    }
    
    function estimateStorageSize(entries: StorageEntry[]): number {
      return entries.reduce((sum, entry) => {
        const encoded = [entry.key, entry.value]
        return sum + Rlp.getEncodedLength(encoded)
      }, 0)
    }
    
    const entries = [
      { key: new Uint8Array([1]), value: new Uint8Array([2, 3]) },
      { key: new Uint8Array([4]), value: new Uint8Array([5, 6]) }
    ]
    
    const size = estimateStorageSize(entries)
    console.log(`Storage will use ${size} bytes`)
    

    Algorithm

    Conceptual implementation:
    function getEncodedLength(data: Encodable): number {
      // Single byte < 0x80
      if (data instanceof Uint8Array) {
        if (data.length === 1 && data[0] < 0x80) {
          return 1
        }
    
        // Short string (0-55 bytes)
        if (data.length < 56) {
          return 1 + data.length
        }
    
        // Long string (56+ bytes)
        const lengthBytes = Math.ceil(Math.log2(data.length + 1) / 8)
        return 1 + lengthBytes + data.length
      }
    
      // List
      if (Array.isArray(data)) {
        // Calculate total payload length
        const totalLength = data.reduce(
          (sum, item) => sum + getEncodedLength(item),
          0
        )
    
        // Short list (< 56 bytes)
        if (totalLength < 56) {
          return 1 + totalLength
        }
    
        // Long list (56+ bytes)
        const lengthBytes = Math.ceil(Math.log2(totalLength + 1) / 8)
        return 1 + lengthBytes + totalLength
      }
    
      throw new Error('Invalid encodable data type')
    }
    

    Performance

    Zero Allocation

    getEncodedLength doesn’t allocate memory:
    import { Rlp } from 'tevm'
    
    const data = new Uint8Array(1000000)
    
    // Fast - no allocation
    const length = Rlp.getEncodedLength(data)
    
    // Slow - allocates 1MB+
    const encoded = Rlp.encode(data)
    

    vs Encoding

    Much faster than encoding + measuring:
    import { Rlp } from 'tevm'
    
    const data = [...]
    
    // Fast: O(n) where n is item count
    const size = Rlp.getEncodedLength(data)
    
    // Slow: O(n) + allocation overhead
    const encoded = Rlp.encode(data)
    const size = encoded.length
    

    Nested Structures

    Handles nested structures recursively:
    import { Rlp } from 'tevm'
    
    const nested = [
      new Uint8Array([1]),
      [
        new Uint8Array([2]),
        [
          new Uint8Array([3])
        ]
      ]
    ]
    
    // Recursively calculates size
    const size = Rlp.getEncodedLength(nested)
    

    See Also