Reflection · on-chain

Reflective AI on-chain

Van Arman put the whole of it on the blockchain, and kept it there at a fidelity Ethereum was never built to carry. The two ambitions pull against each other, and most of what follows comes of resolving them.

The process itself

A painting robot works in passes. It lays a ground, makes a mark, photographs what the mark did and answers it, and the loop between those steps is what Van Arman calls 'Reflective AI.' Ordinarily that loop leaves nothing behind. The canvas is photographed when it is finished, and everything that happened on the way to it is gone.

In Reflection the passes are themselves the artwork. Each piece names its own, in sequence, within the file:

9  background        15 circles
10 bytegan 20x20     16 touchups
11 ganStrokes        17 lighten
12 skull             18 darken
13 background binary 19 highlight
                     20 skull flourish

Twenty-one passes are numbered in all, the drawing ones above and the remainder establishing colour and clipping. Seven fade in across an eight-second loop, at two seconds, then at 3.2, 3.6, 4.0, 4.4, 5.2 and six. Each piece therefore rebuilds itself in the order the robot built it. No recording is being played back. The sequence is the file, and the file is what the contract holds.

Seven fades is not a diminished file. The artist's exhibition renders for the Francisco Carolinum carry twenty to twenty-six, added to the content layers with the minted seven left untouched, and only six of those renders exist. A minted piece carrying seven is the work as it was composed.

Resolution

The second achievement is that the work committed to the chain is not a small one. A single piece is ninety-two kilobytes of pure vector, some nine hundred drawing elements of which eight hundred and seventy-three are paths, and it embeds no raster image at all. There is no bitmap within it to degrade: the piece is geometry, and renders as precisely on a gallery wall as on a telephone.

Drawing elements in one piece
~900
Of those, vector paths
873
Embedded raster images
0
The artwork file
92 KB

The difficulty follows from that. Ethereum limits any single contract to 24,576 bytes of code, and the limit is enforced by consensus. One Reflection comes to nearly four times it. A piece this size cannot be held in a contract at all.

One piece, thirty-one contracts

It is therefore not held in one. Tracing what a call to tokenURI genuinely reads, across twelve pieces distributed through the collection, returns the same structure each time.

Contracts read to render one piece
31
Common to every piece
13
Particular to that piece
18
Largest single data contract
22,499 B · 91.5% of the limit
Contracts in the collection
~136

Thirteen contracts form the engine and are shared by all nine hundred and ninety-nine. The remaining eighteen hold that particular painting, drawn from a common bank. All of this apparatus exists for a single reason: it is what the detail costs once no contract may exceed twenty-four kilobytes.

The figure for the collection is a floor, not a count. Thirty-nine of the pooled contracts appeared only once across twelve samples, which happens when a population has not yet been fully sampled, and a wider run of twenty pieces put the total nearer 144. What can be said with confidence is the order of magnitude.

Composed on mint

Bytecode read during a call comes to between 152 and 181 kilobytes, and the file returned is about ninety-two. Those quantities are close because nothing is being made at the moment of asking. Van Arman's process ran once, at mint, and what it produced was written across the bank, to be reassembled on every call.

That is what makes the works immutable. There is no seed to run again, no model to reload and no version that might drift. The mirrored copies this site serves are byte-identical to what the chain returns, and anyone can check it.

Why the bytecode does not answer

The obvious way to find the remaining contracts is to read the entry contract's bytecode and look for addresses in it. That method fails, and it looks convincing while it does. The bytecode runs to 7.3 kilobytes and holds sixteen twenty-byte values that could be addresses. None of the sixteen is a contract the call reads. The real addresses sit in storage arrays written after deployment, so they were never in the code to find, and only a trace of a live call will show them.

# the contracts one call reads — requires an endpoint allowing debug_traceCall
curl -s -X POST https://eth.merkle.io \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"debug_traceCall","params":[{
       "to":"0x5137cfB461d24040F5ce6B85D860c47A24f85412",
       "data":"0xc87b56dd0000000000000000000000000000000000000000000000000000000000000000"
      },"latest",{"tracer":"prestateTracer"}]}'

The contracts are the returned accounts carrying a code field. Accounts without one are touched in passing and hold nothing.

Verification

A call to tokenURI returns a data URI of base64 JSON, whose image field is a second data URI of base64 SVG. That is the artwork. No gateway is involved, and nothing outside Ethereum has to still exist.

# tokenURI(uint256) is 0xc87b56dd, followed by the token id in thirty-two bytes
curl -s -X POST https://ethereum-rpc.publicnode.com \
  -H 'Content-Type: application/json' -H 'User-Agent: Mozilla/5.0' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{
       "to":"0x5137cfB461d24040F5ce6B85D860c47A24f85412",
       "data":"0xc87b56dd0000000000000000000000000000000000000000000000000000000000000000"
      },"latest"]}'

Two details spare an afternoon. A User-Agent must be sent, since certain endpoints refuse the default one, and cloudflare-eth should be avoided, as it returns an internal error on responses of this size while a small call such as eth_blockNumber succeeds there and reveals nothing.

Token ids run from 0 to 998 where the artist's list runs from 1 to 999, so a token id is the list number less one. Token 0 is 'cogito ergo sum.'

ReflectionShareable GIFssovrn.art