Skip to content

calldata.encode silently accepts lossy JavaScript values #229

Open

Description

@maho0638

Summary

calldata.encode currently accepts two JavaScript value classes that cannot be represented losslessly:

  1. Unsafe integer numbers. Number.isInteger() accepts values outside JavaScript's safe-integer range, then BigInt(data) encodes the already-rounded Number. The API also accepts bigint, so unsafe Numbers should be rejected and callers should use bigint for exact integers.
  2. Strings with unpaired UTF-16 surrogates. TextEncoder replaces an unpaired surrogate with U+FFFD instead of failing. That means decode(encode(value)) !== value, and distinct map keys can collapse to the same UTF-8 bytes.

Example key collision:

new Map([
  ["\\uD800", null],
  ["\\uFFFD", true],
]);

Those are distinct JavaScript strings, but TextEncoder emits the same EF BF BD bytes for both keys. The GenVM Python reference encoder raises on an unpaired surrogate instead of replacing it.

Expected

  • reject number values for which Number.isSafeInteger(value) is false and direct callers to bigint;
  • reject unpaired UTF-16 surrogates in calldata string values and map keys;
  • preserve normal Unicode, including valid surrogate pairs such as emoji.

This prevents silent wire-value changes before calldata reaches GenVM.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions