Skip to content

Instantly share code, notes, and snippets.

@axic
Created April 27, 2016 22:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save axic/f6454322cb770ea55466d9cce501ab56 to your computer and use it in GitHub Desktop.
Save axic/f6454322cb770ea55466d9cce501ab56 to your computer and use it in GitHub Desktop.
A very old proposal from November 2015

Ethereum Object Notation (ETON)

A simple ABI structure to replace JSON's object when passed between contracts. It is especially useful when interacting with outside oracles, where a JSON would be converted into this notation.

A JSON supports the following object types:

  • number (double precision floating point)
  • string (double quoted unicode string)
  • boolean (true or false)
  • array (ordered sequence)
  • null
  • object (another JSON object)

ETON supports the following types:

Compared to JSON, there is no support for null or untyped arrays.

Option 1

Note: although the structure shares similarities with the Contract ABI and while it aims to be consistent as closely as possible, it is still optimised towards a serialised representation of larger data. This structure is considered a type as opposed to the elements of it. In short this means that passing an ETON object in a contract will have to be considered a binary blob and handled similarly to bytes.

The ETON element type:

  • is a key-value mapping
  • key is always a string
  • value can be of variable type

The basic layout following the ABI is:

<number of elements, uint256>
  <key 1, string>
  <type 1, uint256>
  <value 1, variable>
  ...
  <key N, string>
  <type N, uint256>
  <value N, variable>

All elementary types are encoded as per the ABI specification. In case the ETON type is stored, a sub tree is created:

<number of elements, uint256>
  <key 1, string>
  <type 1, uint256>
  <number of elements, uint256>
    <key 1, string>
    <type 1, uint256>
    <value 1, variable>
    ...
    <key N, string>
    <type N, uint256>
    <value N, variable>    
  ...
  <key N, string>
  <type N, uint256>
  <value N, variable>

There is a depth limit of 4.

Elementary type codes

The contract ABI does not assign a numerical identifier to the elementary types as they are only referred to in a string format. For ETON such numerical identifiers must be defined as follows:

id encoding corresponding type
0x1000000 embedded ETON
0x2000000 bool
0x3000000 address
0x4000000 bytes
0x5000000 string
0x60000XX bytes
0x70000XX uint
0x80000XX int
0x900XXYY realx
0xA00XXYY urealx
id type
0x1 embedded ETON
0x2 bool
0x3 address
0x4 bytes
0x5 string
0x20 bytes1
0x21 bytes2
... ...
0x40 bytes32
0x200 uint8
0x201 uint16
... ...
0x220 uint256
0x300 int8
0x301 int16
... ...
0x320 int256
0x400 real8x8
0x401 real8x16
... ...
0x420 real16x8
... ...
0x4ff real128x128
0x500 ureal8x8
0x501 ureal8x16
... ...
0x520 ureal16x8
... ...
0x5ff ureal128x128

There are two special cases:

  • Variable-length array types

For these, the top bit (255th) is set in the identifier. Processing happens according to the ABI: the first data to follow is the array length encoded as uint256.

  • Fixed-size array types

For these, the second topmost bit (254th) is set in the identifier. Processing happens exactly as with variable-length arrays: the first data to follow is the array length encoded as uint256.

FIXME: probably only one such bit is needed and it should only treat them one way.

Note that an embedded ETON cannot be an array at the same time, setting any of the two top bits is invalid.

Examples:

  • string: 0000000000000000000000000000000000000000000000000000000000000003
  • string[]: 8000000000000000000000000000000000000000000000000000000000000003
  • string[N]: 4000000000000000000000000000000000000000000000000000000000000003
  • eton[] (invalid!): 8000000000000000000000000000000000000000000000000000000000000001

Solidity

The above structure is reminiscent of the struct in Solidity.

The following example construct in Solidity:

struct Backer {
  address addr;
  uint amount;
}

struct Project {
  uint raising;
  Backer[] backers;
}

Assuming there is one project raising 2 ETH, and two backers each donating 1 ETH, it can be translated into ETON as follows:

0000000000000000000000000000000000000000000000000000000000000001 (eton elements)
  0000000000000000000000000000000000000000000000000000000000000007 (key 1 - length of string)
  aabbccddee000000000000000000000000000000000000000000000000000007 (key 1 - "raising")
  00000000000000000000000000000000000000000000000000000000070000ff (type 1 - uint256)
  0000000000000000000000000000000000000000200000000000000000000000 (value 1 - 2 eth)

  0000000000000000000000000000000000000000000000000000000000000007 (key 1 - length of string)
  aabbccddee000000000000000000000000000000000000000000000000000007 (key 1 - "backers")
  0000000000000000000000000000000000000000000000000000000001000000 (type 1 - eton)
  0000000000000000000000000000000000000000000000000000000000000002 (value 1 - 2 eth)

Example JSON conversion

Take the following simple JSON:

{
   "ip": "8.8.8.8",
   "google": true
}

We assume that the value of ip is a string and the value of google is boolean. The resulting ETON is as follows (a healthy 320 bytes):

00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002697000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000007382e382e382e38000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006676f6f676c65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000001

Let's dissect it:

0000000000000000000000000000000000000000000000000000000000000002 (number of eton elements)
  0000000000000000000000000000000000000000000000000000000000000002 (key 1 - length of string)
  6970000000000000000000000000000000000000000000000000000000000000 (key 1 - "ip")
  0000000000000000000000000000000000000000000000000000000004000000 (type 1 - string)
  0000000000000000000000000000000000000000000000000000000000000007 (value 1 - length of string)
  382e382e382e3800000000000000000000000000000000000000000000000000 (value 1 - "8.8.8.8")
  0000000000000000000000000000000000000000000000000000000000000006 (key 2 - length of string)
  676f6f676c650000000000000000000000000000000000000000000000000000 (key 2 - "google")
  0000000000000000000000000000000000000000000000000000000002000000 (type 2 - bool)
  0000000000000000000000000000000000000000000000000000000000000001 (value 2 - true)

Option 2

In this case both key and values are restricted to strings. The encoding is reminiscent how the Solidity mapping construct could be encoded:

<number of elements, uint256>
  <key 1, string>
  <value 1, variable>
  ...
  <key N, string>
  <value N, variable>

In this option, the embedded ETON type cannot be supported, thus limiting the structure to one level.

I find this option less useful and versatile, than the above, but at the same time it is much simpler to parse and uses less memory space.

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