Skip to main content

Try it Live

Run AccessList examples in the interactive playground

Conversions

Encoding and decoding AccessList to/from RLP bytes.

AccessList.toBytes()

Encode access list to RLP bytes.
AccessList.toBytes(list: BrandedAccessList): Uint8Array
Parameters:
  • list: Access list to encode
Returns: RLP-encoded bytes Example:
const list = AccessList([
  { address: addr1, storageKeys: [key1, key2] },
  { address: addr2, storageKeys: [] }
]);

const bytes = list.toBytes();
// Can be included in transaction encoding
RLP Structure:
[
  [address1, [key1, key2]],
  [address2, []],
  ...
]
Encoding Rules:
  • Top-level list of items
  • Each item is [address, keys] pair
  • Address encoded as 20-byte string
  • Keys encoded as list of 32-byte strings
  • Empty storageKeys encoded as empty list []

AccessList.fromBytes()

Decode RLP bytes to access list.
AccessList(bytes: Uint8Array): BrandedAccessList
Parameters:
  • bytes: RLP-encoded access list
Returns: Decoded BrandedAccessList Throws:
  • Error if not RLP list
  • Error if item not [address, keys] pair
  • Error if address not 20 bytes
  • Error if storage key not 32 bytes
Example:
const bytes = tx.accessListBytes;
const list = AccessList(bytes);

// Use decoded list
console.log(list.addressCount());
console.log(list.storageKeyCount());
Validation:
  • Validates RLP structure
  • Validates byte lengths
  • Does not validate address checksums
  • Does not deduplicate

Patterns

Round-trip Encoding

const original = AccessList([
  { address: addr, storageKeys: [key1, key2] }
]);

const bytes = original.toBytes();
const decoded = AccessList(bytes);

// Should be equivalent
console.assert(original.length === decoded.length);

Transaction Integration

// Encode for transaction
const tx = {
  to: contractAddress,
  data: callData,
  accessList: list.toBytes()
};

// Decode from transaction
const receivedTx = await provider.getTransaction(txHash);
const accessList = AccessList(receivedTx.accessList);

Safe Decoding

function safeFromBytes(bytes: Uint8Array): BrandedAccessList | null {
  try {
    const list = AccessList(bytes);
    AccessList.assertValid(list);
    return list;
  } catch (err) {
    console.error('Failed to decode access list:', err);
    return null;
  }
}

Serialize for Storage

// Store in database
const serialized = Hex.fromBytes(list.toBytes()).slice(2);
await db.store('access_list', serialized);

// Retrieve from database
const stored = await db.get('access_list');
const bytes = Hex.toBytes(stored);
const list = AccessList(bytes);

Network Transmission

// Send over network
const bytes = list.toBytes();
await socket.send(bytes);

// Receive from network
const received = await socket.receive();
const list = AccessList(received);

Compare Encoded Size

function compareEncodedSizes(lists: BrandedAccessList[]) {
  return lists.map(list => ({
    list,
    addresses: list.addressCount(),
    keys: list.storageKeyCount(),
    encodedSize: list.toBytes().length
  })).sort((a, b) => a.encodedSize - b.encodedSize);
}

RLP Format Details

Empty List

const empty = AccessList.create();
const bytes = empty.toBytes();
// RLP: [0xc0] (empty list)

Single Address, No Keys

const list = AccessList([
  { address: addr, storageKeys: [] }
]);
const bytes = list.toBytes();
// RLP: [[[address], []]]

Single Address, Single Key

const list = AccessList([
  { address: addr, storageKeys: [key] }
]);
const bytes = list.toBytes();
// RLP: [[[address], [[key]]]]

Multiple Items

const list = AccessList([
  { address: addr1, storageKeys: [key1, key2] },
  { address: addr2, storageKeys: [] },
  { address: addr3, storageKeys: [key3] }
]);
const bytes = list.toBytes();
// RLP: [
//   [[addr1], [[key1], [key2]]],
//   [[addr2], []],
//   [[addr3], [[key3]]]
// ]

Size Calculations

Encoded Size Formula

itemSize = 1 + 20 + 1 + (32 × numKeys) + overhead
totalSize = sum(itemSize) + listOverhead
Overhead:
  • RLP list prefix: 1-9 bytes
  • Item tuple prefix: 1 byte
  • Keys list prefix: 1 byte
Examples:
// Empty list: ~1 byte
// 1 address, 0 keys: ~23 bytes
// 1 address, 1 key: ~56 bytes
// 1 address, 2 keys: ~89 bytes
// 2 addresses, 1 key each: ~112 bytes

Size Analysis

function analyzeEncodedSize(list: BrandedAccessList) {
  const bytes = list.toBytes();
  const addresses = list.addressCount();
  const keys = list.storageKeyCount();

  return {
    totalBytes: bytes.length,
    addresses,
    keys,
    avgBytesPerAddress: bytes.length / addresses || 0,
    avgBytesPerKey: bytes.length / keys || 0
  };
}

Error Handling

Encoding Errors

try {
  const bytes = list.toBytes();
} catch (err) {
  // Encoding should never fail for valid AccessList
  // If it does, list structure is corrupted
  console.error('Encoding failed:', err);
}

Decoding Errors

try {
  const list = AccessList(bytes);
} catch (err) {
  if (err.message.includes('expected list')) {
    // Invalid RLP structure
  } else if (err.message.includes('address')) {
    // Invalid address length or structure
  } else if (err.message.includes('storage key')) {
    // Invalid key length
  } else {
    // Other RLP decoding error
  }
}

Validation After Decoding

const list = AccessList(bytes);

// Additional validation
try {
  AccessList.assertValid(list);
} catch (err) {
  // Structure is valid RLP but fails semantic checks
  throw new Error(`Invalid access list: ${err.message}`);
}

Best Practices

  1. Validate before encoding
    AccessList.assertValid(list);
    const bytes = list.toBytes();
    
  2. Always validate after decoding
    const list = AccessList(bytes);
    AccessList.assertValid(list);
    
  3. Handle encoding errors gracefully
    try {
      return list.toBytes();
    } catch (err) {
      console.error('Failed to encode:', err);
      return AccessList.create().toBytes();
    }
    
  4. Deduplicate before encoding
    const optimized = list.deduplicate();
    const bytes = optimized.toBytes();
    
  5. Cache encoded results
    class CachedAccessList {
      private list: BrandedAccessList;
      private cachedBytes?: Uint8Array;
    
      constructor(list: BrandedAccessList) {
        this.list = list;
      }
    
      toBytes(): Uint8Array {
        if (!this.cachedBytes) {
          this.cachedBytes = this.list.toBytes();
        }
        return this.cachedBytes;
      }
    }
    

Performance

OperationComplexityNotes
toBytesO(n×m)Encodes all items
fromBytesO(n×m)Decodes all items
Optimization:
  • Cache encoded bytes if encoding multiple times
  • Deduplicate before encoding to minimize size
  • Reuse decoded lists instead of re-decoding

See Also