Expression syntax
Pointer expressions operate on the domain of bytes representing unsigned integers.
- Explore
- View source
- Playground
- YAML
- JSON
$schema: "https://json-schema.org/draft/2020-12/schema"
$id: "schema:ethdebug/format/pointer/expression"
title: ethdebug/format/pointer/expression
description: |
A schema for describing expressions that evaluate to values.
## Two sorts of value: integers and bytes
Every expression evaluates to a value of one of two sorts:
- an **integer** — an unbounded, non-negative integer. It has a numeric
value but **no width**. Arithmetic is ordinary integer arithmetic.
- **bytes** — a finite sequence of bytes with a definite **width** (its
byte length).
The two sorts are produced by different forms:
- **Integers** are produced by a JSON-number literal, the `$wordsize`
constant, a variable or lookup (`.offset` / `.length` / `.slot`) that
denotes an index or count, an arithmetic operation (`$sum`,
`$difference`, `$product`, `$quotient`, `$remainder`), and a
hexadecimal literal that has an **odd** number of digits (which has no
whole-byte width — see `Literal`).
- **Bytes** are produced by a hexadecimal literal with an **even** number
of digits (its width is the number of bytes written), `$read` (its
width is the length of the region read), and the resize forms
`$sizedN` / `$wordsized` (whose width is `N` / the word size).
## Coercion and the width-bearing requirement
Where an **integer** is expected — arithmetic operands, a list `count`, a
segment `slot` / `offset` / `length` — a bytes value is accepted and read
as the non-negative integer its bytes encode (big-endian).
Where **bytes** are expected — the operands of `$concat` and `$keccak256`,
whose results depend on operand widths — the operand **must** be
width-bearing. A bare integer (a JSON number, an odd-digit hex literal,
`$wordsize`, an arithmetic result, or a lookup) is **not** valid there:
give it a width first with `$sizedN` or `$wordsized`. There is no
implicit widening; the resize forms are the only bridge from an integer
to bytes.
oneOf:
- $ref: "#/$defs/Literal"
- $ref: "#/$defs/Variable"
- $ref: "#/$defs/Constant"
- $ref: "#/$defs/Arithmetic"
- $ref: "#/$defs/Lookup"
- $ref: "#/$defs/Read"
- $ref: "#/$defs/Keccak256"
- $ref: "#/$defs/Concat"
- $ref: "#/$defs/Resize"
$defs:
Literal:
title: Literal value
description: |
A literal value, written either as a JSON number or as a `0x`-prefixed
hexadecimal string.
Its sort follows its form:
- a JSON number is an **integer** (no width);
- a hexadecimal string with an **even** number of digits is **bytes**,
whose width is the number of bytes written (`"0x00"` is one zero
byte, `"0xdead"` is two bytes);
- a hexadecimal string with an **odd** number of digits has no
whole-byte width and is therefore an **integer**, equal to the value
its digits denote (`"0x1"` is the integer `1`, not bytes).
$ref: "schema:ethdebug/format/data/value"
examples:
- 5
- "0x0000000000000000000000000000000000000000000000000000000000000000"
Constant:
title: Constant value
type: string
enum:
- $wordsize
Variable:
title: Variable identifier
description: |
A string that matches an identifier used in an earlier declaration of
a scalar variable. This expression evaluates to the value of that
variable.
$ref: "schema:ethdebug/format/pointer/identifier"
Arithmetic:
title: Arithmetic operation
description: |
Ordinary integer arithmetic. Each operand is taken as an **integer**
(a bytes operand is read as the non-negative integer its bytes encode),
and the result is an **integer** with no width. To use an arithmetic
result where bytes are required, give it a width with `$sizedN` or
`$wordsized`.
type: object
properties:
"$sum":
description: |
A list of expressions to be added together.
$ref: "#/$defs/Operands"
"$difference":
description: |
A tuple of two expressions where the second is to be subtracted from
the first.
If the second operand is larger than the first, the result of this
arithmetic operation is defined to equal zero (`0`).
(i.e., `{ "$difference": [a, b] }` equals `a` minus `b`.)
$ref: "#/$defs/Operands"
minItems: 2
maxItems: 2
"$product":
description: |
A list of expressions to be multiplied.
$ref: "#/$defs/Operands"
"$quotient":
description: |
A tuple of two expressions where the first corresponds to the
dividend and the second corresponds to the divisor, for the purposes
of doing integer division.
(i.e., `{ "$quotient": [a, b] }` equals `a` divided by `b`.)
$ref: "#/$defs/Operands"
minItems: 2
maxItems: 2
"$remainder":
description: |
A tuple of two expressions where the first corresponds to the
dividend and the second corresponds to the divisor, for the purposes
of computing the modular-arithmetic remainder.
(i.e., `{ "$remainder": [a, b] }` equals `a` mod `b`.)
$ref: "#/$defs/Operands"
minItems: 2
maxItems: 2
additionalProperties: false
minProperties: 1
maxProperties: 1
examples:
- "$sum": [5, 3, 4]
- "$difference": [5, 3]
- "$product": [5, 3, 0]
- "$quotient": [5, 3]
- "$remainder":
- "$product":
- 2
- 2
- 2
- 2
- 3
Operands:
type: array
items:
$ref: "schema:ethdebug/format/pointer/expression"
Lookup:
title: Lookup region definition
description: |
An object of the form `{ ".<property-name>": "<region>" }`, to
denote that this expression is equivalent to the defined value for
the property named `<property-name>` inside the region referenced as
`<region>`. The value is an **integer** (a region's `.offset`,
`.length`, or `.slot`).
`<property-name>` **must** be a valid and present property on the
corresponding region, or it **must** correspond to an optional property
whose schema specifies a default value for that property.
type: object
patternProperties:
"^\\.(offset|length|slot)$":
$ref: "#/$defs/Reference"
additionalProperties: false
minProperties: 1
maxProperties: 1
examples:
- .offset: "array-count"
- .length: "array-item"
- .offset: $this
Read:
title: Read region bytes
description: |
An object of the form `{ "$read": "<region>" }`. The value of this
expression equals the raw bytes present in the running machine state
in the referenced region. The result is **bytes** whose width is the
length of the region read.
type: object
properties:
$read:
$ref: "#/$defs/Reference"
required:
- $read
additionalProperties: false
examples:
- $read: "struct-start"
Reference:
title: Region reference
description: |
A string value that **must** either be the `"name"` of at least one
region declared with `{ "name": "<region>" }` previously in some root
pointer representation, or it **must** be the literal value `"$this"`,
which indicates a reference to the region containing this expression.
If more than one region is defined with the same name, resolution is
defined as firstly resolving to the latest earlier sibling that declares
the matching name, then secondly resolving to the parent if it matches,
then to parent's earlier siblings, and so on.
type: string
oneOf:
- $ref: "schema:ethdebug/format/pointer/identifier"
- const: "$this"
description: |
Indicates a reference to the region containing this expression.
Keccak256:
title: Keccak256 hash
description: |
An object of the form `{ "$keccak256": [...values] }`, indicating
that this expression evaluates to the Solidity-style keccak256 hash
of the tightly-packed bytes encoded by `values`. The result is
**bytes** of width 32.
Because the hash is taken over the concatenation of the operands'
bytes, each operand **must** be width-bearing (bytes): a bare integer
is not valid here and must be given a width first with `$sizedN` or
`$wordsized`. This is why a mapping-slot computation word-sizes its key
and slot before hashing.
type: object
properties:
$keccak256:
title: Array of hashed values
type: array
items:
$ref: "schema:ethdebug/format/pointer/expression"
additionalProperties: false
required:
- $keccak256
examples:
- $keccak256:
- $wordsized: 0
- "0x00"
Concat:
title: Concatenate values
description: |
An object of the form `{ "$concat": [...values] }`, indicating that this
expression evaluates to the concatenation of bytes from each value.
The byte width of each operand is preserved; no padding is added or
removed between operands. The result is **bytes** whose width is the
sum of the operand widths.
Each operand **must** be width-bearing (bytes): a bare integer is not
valid here and must be given a width first with `$sizedN` or
`$wordsized`.
type: object
properties:
$concat:
title: Array of values to concatenate
type: array
items:
$ref: "schema:ethdebug/format/pointer/expression"
additionalProperties: false
required:
- $concat
examples:
- $concat:
- "0x00"
- "0x00"
- $concat:
- "0xdead"
- "0xbeef"
- $concat: []
Resize:
title: Resize data
description: |
A resize operation produces **bytes** of a definite width, and is the
bridge from an integer to bytes: give it an integer (or bytes) and it
yields bytes of the requested width.
A resize operation expression is either an object of the form
`{ "$sized<N>": <expression> }` or an object of the form
`{ "$wordsized": <expression> }`, where `<expression>` is an expression
whose value is to be resized, and, if applicable, where `<N>` is the
smallest decimal representation of an unsigned integer.
This object's value is evaluated as follows, based on the bytes width of
the value `<expression>` evaluates to and based on `<N>` (using the
value of `"$wordsize"` for `<N>` in the case of the latter form above):
- If the width equals `<N>`, this object evaluates to the same value as
`<expression>` (equivalent to the identity function or no-op).
- If the width is less than `<N>`, this object evaluates to the same value
as `<expression>` but with additional zero-bytes (`0x00`) prepended on
the left (most significant) side, such that the resulting bytes width
equals `<N>`.
- If the width exceeds `<N>`, this object evaluates to the same value
as `<expression>` but with a number of bytes removed from the left
(most significant) side until the bytes width equals `<N>`.
(These cases match the behavior that Solidity uses for resizing its
`bytesN`/`uintN` types.)
type: object
oneOf:
- title: Resize to literal number of bytes
type: object
patternProperties:
"^\\$sized([1-9]+[0-9]*)$":
$ref: "schema:ethdebug/format/pointer/expression"
additionalProperties: false
- title: Resize to word-size
type: object
patternProperties:
"^\\$wordsized$":
$ref: "schema:ethdebug/format/pointer/expression"
additionalProperties: false
minProperties: 1
maxProperties: 1
examples:
- $sized2: "0x00" # 0x0000
- $sized2: "0xffffff" # 0xffff
- $wordsized: "0x00" # 0x0000000000000000000000000000000000000000000000000000000000000000
examples:
- 0
- $sum:
- .offset: "array-start"
- .length: "array-start"
- 1
- $keccak256:
- 5
- .offset: "array-start"
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "schema:ethdebug/format/pointer/expression",
"title": "ethdebug/format/pointer/expression",
"description": "A schema for describing expressions that evaluate to values.\n\n## Two sorts of value: integers and bytes\n\nEvery expression evaluates to a value of one of two sorts:\n\n- an **integer** — an unbounded, non-negative integer. It has a numeric\n value but **no width**. Arithmetic is ordinary integer arithmetic.\n- **bytes** — a finite sequence of bytes with a definite **width** (its\n byte length).\n\nThe two sorts are produced by different forms:\n\n- **Integers** are produced by a JSON-number literal, the `$wordsize`\n constant, a variable or lookup (`.offset` / `.length` / `.slot`) that\n denotes an index or count, an arithmetic operation (`$sum`,\n `$difference`, `$product`, `$quotient`, `$remainder`), and a\n hexadecimal literal that has an **odd** number of digits (which has no\n whole-byte width — see `Literal`).\n- **Bytes** are produced by a hexadecimal literal with an **even** number\n of digits (its width is the number of bytes written), `$read` (its\n width is the length of the region read), and the resize forms\n `$sizedN` / `$wordsized` (whose width is `N` / the word size).\n\n## Coercion and the width-bearing requirement\n\nWhere an **integer** is expected — arithmetic operands, a list `count`, a\nsegment `slot` / `offset` / `length` — a bytes value is accepted and read\nas the non-negative integer its bytes encode (big-endian).\n\nWhere **bytes** are expected — the operands of `$concat` and `$keccak256`,\nwhose results depend on operand widths — the operand **must** be\nwidth-bearing. A bare integer (a JSON number, an odd-digit hex literal,\n`$wordsize`, an arithmetic result, or a lookup) is **not** valid there:\ngive it a width first with `$sizedN` or `$wordsized`. There is no\nimplicit widening; the resize forms are the only bridge from an integer\nto bytes.\n",
"oneOf": [
{
"$ref": "#/$defs/Literal"
},
{
"$ref": "#/$defs/Variable"
},
{
"$ref": "#/$defs/Constant"
},
{
"$ref": "#/$defs/Arithmetic"
},
{
"$ref": "#/$defs/Lookup"
},
{
"$ref": "#/$defs/Read"
},
{
"$ref": "#/$defs/Keccak256"
},
{
"$ref": "#/$defs/Concat"
},
{
"$ref": "#/$defs/Resize"
}
],
"$defs": {
"Literal": {
"title": "Literal value",
"description": "A literal value, written either as a JSON number or as a `0x`-prefixed\nhexadecimal string.\n\nIts sort follows its form:\n\n- a JSON number is an **integer** (no width);\n- a hexadecimal string with an **even** number of digits is **bytes**,\n whose width is the number of bytes written (`\"0x00\"` is one zero\n byte, `\"0xdead\"` is two bytes);\n- a hexadecimal string with an **odd** number of digits has no\n whole-byte width and is therefore an **integer**, equal to the value\n its digits denote (`\"0x1\"` is the integer `1`, not bytes).\n",
"$ref": "schema:ethdebug/format/data/value",
"examples": [
5,
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
},
"Constant": {
"title": "Constant value",
"type": "string",
"enum": [
"$wordsize"
]
},
"Variable": {
"title": "Variable identifier",
"description": "A string that matches an identifier used in an earlier declaration of\na scalar variable. This expression evaluates to the value of that\nvariable.\n",
"$ref": "schema:ethdebug/format/pointer/identifier"
},
"Arithmetic": {
"title": "Arithmetic operation",
"description": "Ordinary integer arithmetic. Each operand is taken as an **integer**\n(a bytes operand is read as the non-negative integer its bytes encode),\nand the result is an **integer** with no width. To use an arithmetic\nresult where bytes are required, give it a width with `$sizedN` or\n`$wordsized`.\n",
"type": "object",
"properties": {
"$sum": {
"description": "A list of expressions to be added together.\n",
"$ref": "#/$defs/Operands"
},
"$difference": {
"description": "A tuple of two expressions where the second is to be subtracted from\nthe first.\n\nIf the second operand is larger than the first, the result of this\narithmetic operation is defined to equal zero (`0`).\n\n(i.e., `{ \"$difference\": [a, b] }` equals `a` minus `b`.)\n",
"$ref": "#/$defs/Operands",
"minItems": 2,
"maxItems": 2
},
"$product": {
"description": "A list of expressions to be multiplied.\n",
"$ref": "#/$defs/Operands"
},
"$quotient": {
"description": "A tuple of two expressions where the first corresponds to the\ndividend and the second corresponds to the divisor, for the purposes\nof doing integer division.\n\n(i.e., `{ \"$quotient\": [a, b] }` equals `a` divided by `b`.)\n",
"$ref": "#/$defs/Operands",
"minItems": 2,
"maxItems": 2
},
"$remainder": {
"description": "A tuple of two expressions where the first corresponds to the\ndividend and the second corresponds to the divisor, for the purposes\nof computing the modular-arithmetic remainder.\n\n(i.e., `{ \"$remainder\": [a, b] }` equals `a` mod `b`.)\n",
"$ref": "#/$defs/Operands",
"minItems": 2,
"maxItems": 2
}
},
"additionalProperties": false,
"minProperties": 1,
"maxProperties": 1,
"examples": [
{
"$sum": [
5,
3,
4
]
},
{
"$difference": [
5,
3
]
},
{
"$product": [
5,
3,
0
]
},
{
"$quotient": [
5,
3
]
},
{
"$remainder": [
{
"$product": [
2,
2,
2,
2
]
},
3
]
}
]
},
"Operands": {
"type": "array",
"items": {
"$ref": "schema:ethdebug/format/pointer/expression"
}
},
"Lookup": {
"title": "Lookup region definition",
"description": "An object of the form `{ \".<property-name>\": \"<region>\" }`, to\ndenote that this expression is equivalent to the defined value for\nthe property named `<property-name>` inside the region referenced as\n`<region>`. The value is an **integer** (a region's `.offset`,\n`.length`, or `.slot`).\n\n`<property-name>` **must** be a valid and present property on the\ncorresponding region, or it **must** correspond to an optional property\nwhose schema specifies a default value for that property.\n",
"type": "object",
"patternProperties": {
"^\\.(offset|length|slot)$": {
"$ref": "#/$defs/Reference"
}
},
"additionalProperties": false,
"minProperties": 1,
"maxProperties": 1,
"examples": [
{
".offset": "array-count"
},
{
".length": "array-item"
},
{
".offset": "$this"
}
]
},
"Read": {
"title": "Read region bytes",
"description": "An object of the form `{ \"$read\": \"<region>\" }`. The value of this\nexpression equals the raw bytes present in the running machine state\nin the referenced region. The result is **bytes** whose width is the\nlength of the region read.\n",
"type": "object",
"properties": {
"$read": {
"$ref": "#/$defs/Reference"
}
},
"required": [
"$read"
],
"additionalProperties": false,
"examples": [
{
"$read": "struct-start"
}
]
},
"Reference": {
"title": "Region reference",
"description": "A string value that **must** either be the `\"name\"` of at least one\nregion declared with `{ \"name\": \"<region>\" }` previously in some root\npointer representation, or it **must** be the literal value `\"$this\"`,\nwhich indicates a reference to the region containing this expression.\n\nIf more than one region is defined with the same name, resolution is\ndefined as firstly resolving to the latest earlier sibling that declares\nthe matching name, then secondly resolving to the parent if it matches,\nthen to parent's earlier siblings, and so on.\n",
"type": "string",
"oneOf": [
{
"$ref": "schema:ethdebug/format/pointer/identifier"
},
{
"const": "$this",
"description": "Indicates a reference to the region containing this expression.\n"
}
]
},
"Keccak256": {
"title": "Keccak256 hash",
"description": "An object of the form `{ \"$keccak256\": [...values] }`, indicating\nthat this expression evaluates to the Solidity-style keccak256 hash\nof the tightly-packed bytes encoded by `values`. The result is\n**bytes** of width 32.\n\nBecause the hash is taken over the concatenation of the operands'\nbytes, each operand **must** be width-bearing (bytes): a bare integer\nis not valid here and must be given a width first with `$sizedN` or\n`$wordsized`. This is why a mapping-slot computation word-sizes its key\nand slot before hashing.\n",
"type": "object",
"properties": {
"$keccak256": {
"title": "Array of hashed values",
"type": "array",
"items": {
"$ref": "schema:ethdebug/format/pointer/expression"
}
}
},
"additionalProperties": false,
"required": [
"$keccak256"
],
"examples": [
{
"$keccak256": [
{
"$wordsized": 0
},
"0x00"
]
}
]
},
"Concat": {
"title": "Concatenate values",
"description": "An object of the form `{ \"$concat\": [...values] }`, indicating that this\nexpression evaluates to the concatenation of bytes from each value.\nThe byte width of each operand is preserved; no padding is added or\nremoved between operands. The result is **bytes** whose width is the\nsum of the operand widths.\n\nEach operand **must** be width-bearing (bytes): a bare integer is not\nvalid here and must be given a width first with `$sizedN` or\n`$wordsized`.\n",
"type": "object",
"properties": {
"$concat": {
"title": "Array of values to concatenate",
"type": "array",
"items": {
"$ref": "schema:ethdebug/format/pointer/expression"
}
}
},
"additionalProperties": false,
"required": [
"$concat"
],
"examples": [
{
"$concat": [
"0x00",
"0x00"
]
},
{
"$concat": [
"0xdead",
"0xbeef"
]
},
{
"$concat": []
}
]
},
"Resize": {
"title": "Resize data",
"description": "A resize operation produces **bytes** of a definite width, and is the\nbridge from an integer to bytes: give it an integer (or bytes) and it\nyields bytes of the requested width.\n\nA resize operation expression is either an object of the form\n`{ \"$sized<N>\": <expression> }` or an object of the form\n`{ \"$wordsized\": <expression> }`, where `<expression>` is an expression\nwhose value is to be resized, and, if applicable, where `<N>` is the\nsmallest decimal representation of an unsigned integer.\n\nThis object's value is evaluated as follows, based on the bytes width of\nthe value `<expression>` evaluates to and based on `<N>` (using the\nvalue of `\"$wordsize\"` for `<N>` in the case of the latter form above):\n- If the width equals `<N>`, this object evaluates to the same value as\n `<expression>` (equivalent to the identity function or no-op).\n- If the width is less than `<N>`, this object evaluates to the same value\n as `<expression>` but with additional zero-bytes (`0x00`) prepended on\n the left (most significant) side, such that the resulting bytes width\n equals `<N>`.\n- If the width exceeds `<N>`, this object evaluates to the same value\n as `<expression>` but with a number of bytes removed from the left\n (most significant) side until the bytes width equals `<N>`.\n\n(These cases match the behavior that Solidity uses for resizing its\n`bytesN`/`uintN` types.)\n",
"type": "object",
"oneOf": [
{
"title": "Resize to literal number of bytes",
"type": "object",
"patternProperties": {
"^\\$sized([1-9]+[0-9]*)$": {
"$ref": "schema:ethdebug/format/pointer/expression"
}
},
"additionalProperties": false
},
{
"title": "Resize to word-size",
"type": "object",
"patternProperties": {
"^\\$wordsized$": {
"$ref": "schema:ethdebug/format/pointer/expression"
}
},
"additionalProperties": false
}
],
"minProperties": 1,
"maxProperties": 1,
"examples": [
{
"$sized2": "0x00"
},
{
"$sized2": "0xffffff"
},
{
"$wordsized": "0x00"
}
]
}
},
"examples": [
0,
{
"$sum": [
{
".offset": "array-start"
},
{
".length": "array-start"
},
1
]
},
{
"$keccak256": [
5,
{
".offset": "array-start"
}
]
}
]
}
Literal values
An expression can be a literal value.
Literal values must be represented either as JSON numbers or as
0x-prefixed hexadecimal strings. Hexadecimal strings always represent a
literal string of bytes.
For convenience, this schema does not restrict hexadecimal string representations to those that specify an even-number of digits (i.e., those that specify complete byte pairs); odd numbers of hexadecimal digits are fine.
Hexadecimal string representations may omit leading zeroes; values are assumed to be left-padded to the bytes width appropriate for the context.
- Explore
- View source
- Playground
- YAML
- JSON
title: Literal value
description: |
A literal value, written either as a JSON number or as a `0x`-prefixed
hexadecimal string.
Its sort follows its form:
- a JSON number is an **integer** (no width);
- a hexadecimal string with an **even** number of digits is **bytes**,
whose width is the number of bytes written (`"0x00"` is one zero
byte, `"0xdead"` is two bytes);
- a hexadecimal string with an **odd** number of digits has no
whole-byte width and is therefore an **integer**, equal to the value
its digits denote (`"0x1"` is the integer `1`, not bytes).
$ref: "schema:ethdebug/format/data/value"
examples:
- 5
- "0x0000000000000000000000000000000000000000000000000000000000000000"
{
"title": "Literal value",
"description": "A literal value, written either as a JSON number or as a `0x`-prefixed\nhexadecimal string.\n\nIts sort follows its form:\n\n- a JSON number is an **integer** (no width);\n- a hexadecimal string with an **even** number of digits is **bytes**,\n whose width is the number of bytes written (`\"0x00\"` is one zero\n byte, `\"0xdead\"` is two bytes);\n- a hexadecimal string with an **odd** number of digits has no\n whole-byte width and is therefore an **integer**, equal to the value\n its digits denote (`\"0x1\"` is the integer `1`, not bytes).\n",
"$ref": "schema:ethdebug/format/data/value",
"examples": [
5,
"0x0000000000000000000000000000000000000000000000000000000000000000"
]
}
Variables
An expression can be a string value equal to the identifier for a known scalar variable introduced by some pointer representation.
For an example where scalar variables may appear, see the List collection schema.
- Explore
- View source
- Playground
- YAML
- JSON
title: Variable identifier
description: |
A string that matches an identifier used in an earlier declaration of
a scalar variable. This expression evaluates to the value of that
variable.
$ref: "schema:ethdebug/format/pointer/identifier"
{
"title": "Variable identifier",
"description": "A string that matches an identifier used in an earlier declaration of\na scalar variable. This expression evaluates to the value of that\nvariable.\n",
"$ref": "schema:ethdebug/format/pointer/identifier"
}
Arithmetic operations
An expression can be an object of the form { <op>: [...] }, where <op>
denotes an arithmetic operation.
- Explore
- View source
- Playground
- YAML
- JSON
title: Arithmetic operation
description: |
Ordinary integer arithmetic. Each operand is taken as an **integer**
(a bytes operand is read as the non-negative integer its bytes encode),
and the result is an **integer** with no width. To use an arithmetic
result where bytes are required, give it a width with `$sizedN` or
`$wordsized`.
type: object
properties:
"$sum":
description: |
A list of expressions to be added together.
$ref: "#/$defs/Operands"
"$difference":
description: |
A tuple of two expressions where the second is to be subtracted from
the first.
If the second operand is larger than the first, the result of this
arithmetic operation is defined to equal zero (`0`).
(i.e., `{ "$difference": [a, b] }` equals `a` minus `b`.)
$ref: "#/$defs/Operands"
minItems: 2
maxItems: 2
"$product":
description: |
A list of expressions to be multiplied.
$ref: "#/$defs/Operands"
"$quotient":
description: |
A tuple of two expressions where the first corresponds to the
dividend and the second corresponds to the divisor, for the purposes
of doing integer division.
(i.e., `{ "$quotient": [a, b] }` equals `a` divided by `b`.)
$ref: "#/$defs/Operands"
minItems: 2
maxItems: 2
"$remainder":
description: |
A tuple of two expressions where the first corresponds to the
dividend and the second corresponds to the divisor, for the purposes
of computing the modular-arithmetic remainder.
(i.e., `{ "$remainder": [a, b] }` equals `a` mod `b`.)
$ref: "#/$defs/Operands"
minItems: 2
maxItems: 2
additionalProperties: false
minProperties: 1
maxProperties: 1
examples:
- "$sum": [ 5, 3, 4 ]
- "$difference": [ 5, 3 ]
- "$product": [ 5, 3, 0 ]
- "$quotient": [ 5, 3 ]
- "$remainder":
- "$product":
- 2
- 2
- 2
- 2
- 3
{
"title": "Arithmetic operation",
"description": "Ordinary integer arithmetic. Each operand is taken as an **integer**\n(a bytes operand is read as the non-negative integer its bytes encode),\nand the result is an **integer** with no width. To use an arithmetic\nresult where bytes are required, give it a width with `$sizedN` or\n`$wordsized`.\n",
"type": "object",
"properties": {
"$sum": {
"description": "A list of expressions to be added together.\n",
"$ref": "#/$defs/Operands"
},
"$difference": {
"description": "A tuple of two expressions where the second is to be subtracted from\nthe first.\n\nIf the second operand is larger than the first, the result of this\narithmetic operation is defined to equal zero (`0`).\n\n(i.e., `{ \"$difference\": [a, b] }` equals `a` minus `b`.)\n",
"$ref": "#/$defs/Operands",
"minItems": 2,
"maxItems": 2
},
"$product": {
"description": "A list of expressions to be multiplied.\n",
"$ref": "#/$defs/Operands"
},
"$quotient": {
"description": "A tuple of two expressions where the first corresponds to the\ndividend and the second corresponds to the divisor, for the purposes\nof doing integer division.\n\n(i.e., `{ \"$quotient\": [a, b] }` equals `a` divided by `b`.)\n",
"$ref": "#/$defs/Operands",
"minItems": 2,
"maxItems": 2
},
"$remainder": {
"description": "A tuple of two expressions where the first corresponds to the\ndividend and the second corresponds to the divisor, for the purposes\nof computing the modular-arithmetic remainder.\n\n(i.e., `{ \"$remainder\": [a, b] }` equals `a` mod `b`.)\n",
"$ref": "#/$defs/Operands",
"minItems": 2,
"maxItems": 2
}
},
"additionalProperties": false,
"minProperties": 1,
"maxProperties": 1,
"examples": [
{
"$sum": [
5,
3,
4
]
},
{
"$difference": [
5,
3
]
},
{
"$product": [
5,
3,
0
]
},
{
"$quotient": [
5,
3
]
},
{
"$remainder": [
{
"$product": [
2,
2,
2,
2
]
},
3
]
}
]
}
Lookup region definition
An expression can reference properties defined for a particular region, such as
another region's "offset" or "length". Such expressions resolve to the
same value as the expression specified for that corresponding property.
- Explore
- View source
- Playground
- YAML
- JSON
title: Lookup region definition
description: |
An object of the form `{ ".<property-name>": "<region>" }`, to
denote that this expression is equivalent to the defined value for
the property named `<property-name>` inside the region referenced as
`<region>`. The value is an **integer** (a region's `.offset`,
`.length`, or `.slot`).
`<property-name>` **must** be a valid and present property on the
corresponding region, or it **must** correspond to an optional property
whose schema specifies a default value for that property.
type: object
patternProperties:
"^\\.(offset|length|slot)$":
$ref: "#/$defs/Reference"
additionalProperties: false
minProperties: 1
maxProperties: 1
examples:
- .offset: "array-count"
- .length: "array-item"
- .offset: $this
{
"title": "Lookup region definition",
"description": "An object of the form `{ \".<property-name>\": \"<region>\" }`, to\ndenote that this expression is equivalent to the defined value for\nthe property named `<property-name>` inside the region referenced as\n`<region>`. The value is an **integer** (a region's `.offset`,\n`.length`, or `.slot`).\n\n`<property-name>` **must** be a valid and present property on the\ncorresponding region, or it **must** correspond to an optional property\nwhose schema specifies a default value for that property.\n",
"type": "object",
"patternProperties": {
"^\\.(offset|length|slot)$": {
"$ref": "#/$defs/Reference"
}
},
"additionalProperties": false,
"minProperties": 1,
"maxProperties": 1,
"examples": [
{
".offset": "array-count"
},
{
".length": "array-item"
},
{
".offset": "$this"
}
]
}
Reading from the EVM
An expression can be an object of the form { "$read": "<region>" }, where
<region> references a particular region defined in some root pointer.
The value of such an expression is the concatenation of bytes present in the running machine state that correspond to the bytes addressed by the referenced region.
- Explore
- View source
- Playground
- YAML
- JSON
title: Read region bytes
description: |
An object of the form `{ "$read": "<region>" }`. The value of this
expression equals the raw bytes present in the running machine state
in the referenced region. The result is **bytes** whose width is the
length of the region read.
type: object
properties:
$read:
$ref: "#/$defs/Reference"
required:
- $read
additionalProperties: false
examples:
- $read: "struct-start"
{
"title": "Read region bytes",
"description": "An object of the form `{ \"$read\": \"<region>\" }`. The value of this\nexpression equals the raw bytes present in the running machine state\nin the referenced region. The result is **bytes** whose width is the\nlength of the region read.\n",
"type": "object",
"properties": {
"$read": {
"$ref": "#/$defs/Reference"
}
},
"required": [
"$read"
],
"additionalProperties": false,
"examples": [
{
"$read": "struct-start"
}
]
}
Keccak256 hashes
An expression can be an object of form { "$keccak256": [...] }, indicating
that the value of the expression is a Solidity-style, tightly-packed keccak256
hash of the concatenation of bytes specified by the list.
- Explore
- View source
- Playground
- YAML
- JSON
title: Keccak256 hash
description: |
An object of the form `{ "$keccak256": [...values] }`, indicating
that this expression evaluates to the Solidity-style keccak256 hash
of the tightly-packed bytes encoded by `values`. The result is
**bytes** of width 32.
Because the hash is taken over the concatenation of the operands'
bytes, each operand **must** be width-bearing (bytes): a bare integer
is not valid here and must be given a width first with `$sizedN` or
`$wordsized`. This is why a mapping-slot computation word-sizes its key
and slot before hashing.
type: object
properties:
$keccak256:
title: Array of hashed values
type: array
items:
$ref: "schema:ethdebug/format/pointer/expression"
additionalProperties: false
required:
- $keccak256
examples:
- $keccak256:
- $wordsized: 0
- "0x00"
{
"title": "Keccak256 hash",
"description": "An object of the form `{ \"$keccak256\": [...values] }`, indicating\nthat this expression evaluates to the Solidity-style keccak256 hash\nof the tightly-packed bytes encoded by `values`. The result is\n**bytes** of width 32.\n\nBecause the hash is taken over the concatenation of the operands'\nbytes, each operand **must** be width-bearing (bytes): a bare integer\nis not valid here and must be given a width first with `$sizedN` or\n`$wordsized`. This is why a mapping-slot computation word-sizes its key\nand slot before hashing.\n",
"type": "object",
"properties": {
"$keccak256": {
"title": "Array of hashed values",
"type": "array",
"items": {
"$ref": "schema:ethdebug/format/pointer/expression"
}
}
},
"additionalProperties": false,
"required": [
"$keccak256"
],
"examples": [
{
"$keccak256": [
{
"$wordsized": 0
},
"0x00"
]
}
]
}
Bytes concatenation
An expression can be an object of form { "$concat": [...] }, indicating
that the value of the expression is the concatenation of bytes from each
value in the list. The byte width of each operand is preserved; no padding
is added or removed between operands.
This is useful for building composite byte sequences, for example when constructing storage slot keys or preparing data for hashing.
- Explore
- View source
- Playground
- YAML
- JSON
title: Concatenate values
description: |
An object of the form `{ "$concat": [...values] }`, indicating that this
expression evaluates to the concatenation of bytes from each value.
The byte width of each operand is preserved; no padding is added or
removed between operands. The result is **bytes** whose width is the
sum of the operand widths.
Each operand **must** be width-bearing (bytes): a bare integer is not
valid here and must be given a width first with `$sizedN` or
`$wordsized`.
type: object
properties:
$concat:
title: Array of values to concatenate
type: array
items:
$ref: "schema:ethdebug/format/pointer/expression"
additionalProperties: false
required:
- $concat
examples:
- $concat:
- "0x00"
- "0x00"
- $concat:
- "0xdead"
- "0xbeef"
- $concat: []
{
"title": "Concatenate values",
"description": "An object of the form `{ \"$concat\": [...values] }`, indicating that this\nexpression evaluates to the concatenation of bytes from each value.\nThe byte width of each operand is preserved; no padding is added or\nremoved between operands. The result is **bytes** whose width is the\nsum of the operand widths.\n\nEach operand **must** be width-bearing (bytes): a bare integer is not\nvalid here and must be given a width first with `$sizedN` or\n`$wordsized`.\n",
"type": "object",
"properties": {
"$concat": {
"title": "Array of values to concatenate",
"type": "array",
"items": {
"$ref": "schema:ethdebug/format/pointer/expression"
}
}
},
"additionalProperties": false,
"required": [
"$concat"
],
"examples": [
{
"$concat": [
"0x00",
"0x00"
]
},
{
"$concat": [
"0xdead",
"0xbeef"
]
},
{
"$concat": []
}
]
}
Resize operations
In certain situations, e.g. keccak256 hashes, it's crucially important to be able to express the bytes width of particular expression values. This schema provides primitives to allow specifying an explicit bytes width for a particular sub-expression.
- Explore
- View source
- Playground
- YAML
- JSON
title: Resize data
description: |
A resize operation produces **bytes** of a definite width, and is the
bridge from an integer to bytes: give it an integer (or bytes) and it
yields bytes of the requested width.
A resize operation expression is either an object of the form
`{ "$sized<N>": <expression> }` or an object of the form
`{ "$wordsized": <expression> }`, where `<expression>` is an expression
whose value is to be resized, and, if applicable, where `<N>` is the
smallest decimal representation of an unsigned integer.
This object's value is evaluated as follows, based on the bytes width of
the value `<expression>` evaluates to and based on `<N>` (using the
value of `"$wordsize"` for `<N>` in the case of the latter form above):
- If the width equals `<N>`, this object evaluates to the same value as
`<expression>` (equivalent to the identity function or no-op).
- If the width is less than `<N>`, this object evaluates to the same value
as `<expression>` but with additional zero-bytes (`0x00`) prepended on
the left (most significant) side, such that the resulting bytes width
equals `<N>`.
- If the width exceeds `<N>`, this object evaluates to the same value
as `<expression>` but with a number of bytes removed from the left
(most significant) side until the bytes width equals `<N>`.
(These cases match the behavior that Solidity uses for resizing its
`bytesN`/`uintN` types.)
type: object
oneOf:
- title: Resize to literal number of bytes
type: object
patternProperties:
"^\\$sized([1-9]+[0-9]*)$":
$ref: "schema:ethdebug/format/pointer/expression"
additionalProperties: false
- title: Resize to word-size
type: object
patternProperties:
"^\\$wordsized$":
$ref: "schema:ethdebug/format/pointer/expression"
additionalProperties: false
minProperties: 1
maxProperties: 1
examples:
- $sized2: "0x00" # 0x0000
- $sized2: "0xffffff" # 0xffff
- $wordsized: "0x00" # 0x0000000000000000000000000000000000000000000000000000000000000000
{
"title": "Resize data",
"description": "A resize operation produces **bytes** of a definite width, and is the\nbridge from an integer to bytes: give it an integer (or bytes) and it\nyields bytes of the requested width.\n\nA resize operation expression is either an object of the form\n`{ \"$sized<N>\": <expression> }` or an object of the form\n`{ \"$wordsized\": <expression> }`, where `<expression>` is an expression\nwhose value is to be resized, and, if applicable, where `<N>` is the\nsmallest decimal representation of an unsigned integer.\n\nThis object's value is evaluated as follows, based on the bytes width of\nthe value `<expression>` evaluates to and based on `<N>` (using the\nvalue of `\"$wordsize\"` for `<N>` in the case of the latter form above):\n- If the width equals `<N>`, this object evaluates to the same value as\n `<expression>` (equivalent to the identity function or no-op).\n- If the width is less than `<N>`, this object evaluates to the same value\n as `<expression>` but with additional zero-bytes (`0x00`) prepended on\n the left (most significant) side, such that the resulting bytes width\n equals `<N>`.\n- If the width exceeds `<N>`, this object evaluates to the same value\n as `<expression>` but with a number of bytes removed from the left\n (most significant) side until the bytes width equals `<N>`.\n\n(These cases match the behavior that Solidity uses for resizing its\n`bytesN`/`uintN` types.)\n",
"type": "object",
"oneOf": [
{
"title": "Resize to literal number of bytes",
"type": "object",
"patternProperties": {
"^\\$sized([1-9]+[0-9]*)$": {
"$ref": "schema:ethdebug/format/pointer/expression"
}
},
"additionalProperties": false
},
{
"title": "Resize to word-size",
"type": "object",
"patternProperties": {
"^\\$wordsized$": {
"$ref": "schema:ethdebug/format/pointer/expression"
}
},
"additionalProperties": false
}
],
"minProperties": 1,
"maxProperties": 1,
"examples": [
{
"$sized2": "0x00"
},
{
"$sized2": "0xffffff"
},
{
"$wordsized": "0x00"
}
]
}
Region references
Regions can be referenced either by name (which must be a defined region),
or by use of the literal string value "$this" (which indicates that the
referenced region is the region containing the expression itself).
In cases where an expression is used outside the context of a particular
region definition, the use of "$this" is prohibited.
Individual properties may not be defined with any reference to themselves. Properties also may not be defined in terms of mutual reference to each other. (Don't make this harder than it has to be.)
- Explore
- View source
- Playground
- YAML
- JSON
title: Region reference
description: |
A string value that **must** either be the `"name"` of at least one
region declared with `{ "name": "<region>" }` previously in some root
pointer representation, or it **must** be the literal value `"$this"`,
which indicates a reference to the region containing this expression.
If more than one region is defined with the same name, resolution is
defined as firstly resolving to the latest earlier sibling that declares
the matching name, then secondly resolving to the parent if it matches,
then to parent's earlier siblings, and so on.
type: string
oneOf:
- $ref: "schema:ethdebug/format/pointer/identifier"
- const: "$this"
description: |
Indicates a reference to the region containing this expression.
{
"title": "Region reference",
"description": "A string value that **must** either be the `\"name\"` of at least one\nregion declared with `{ \"name\": \"<region>\" }` previously in some root\npointer representation, or it **must** be the literal value `\"$this\"`,\nwhich indicates a reference to the region containing this expression.\n\nIf more than one region is defined with the same name, resolution is\ndefined as firstly resolving to the latest earlier sibling that declares\nthe matching name, then secondly resolving to the parent if it matches,\nthen to parent's earlier siblings, and so on.\n",
"type": "string",
"oneOf": [
{
"$ref": "schema:ethdebug/format/pointer/identifier"
},
{
"const": "$this",
"description": "Indicates a reference to the region containing this expression.\n"
}
]
}