MurAll uses a proprietary image encoder/decoder tailored to getting the most image data into an Ethereum transaction while saving gas (and therefore money) for the artist, allowing for class leading visuals for an on-chain art experience.
Ethereum data storage
Ethereum has 2 main places for on-chain data storage:
- Contract storage - storage of the Ethereum smart contracts, holding the state of the blockchain.
- Log storage - storage for logs from the Etherum smart contract executions.
Traditional data storage for storing on-chain data and keeping it modifiable. However it is the most expensive storage, costing 20 000 gas for every 32 bytes.
Log storage, on the other hand, costs 375 gas for each topic plus 8 gas per byte of the LOG operations data, which is a LOT cheaper.
Storing 32 bytes in contract storage would cost 20 000 gas
Storing 32 bytes in log storage would cost 375 gas + (8 gas * 32 bytes) = 631 gas
But storing in log storage comes with the caveat that the log operation is immutable and not accessible from within contract storage.
MurAll data storage
Let's look at the properties of log storage:
- The data is immutable - Perfect for our use case where the image data is not to be altered.
- It is part of every node on the network — meaning it is as decentralised and as secure as any data in the contract storage and thus will be as accessible and resilient as the contract storage
- It consumes a lot less gas — not only does this reduce the cost of the transactions, it also means we can fit larger amounts of image data than what is possible in contract storage due to the gas limits of Ethereum transactions
It can be concluded that log storage is perfect for MurAll 🚀
Processing image data
Digital images at their core are collections of pixels, which can be broken down into 2 main components: color and position. Thus, MurAll tries to fit as much information as possible about the colour and the position of the pixels into the transaction data that is passed to the smart contract at the time of minting.
Transaction data is a collection of 32-byte objects, because that is the most optimal when dealing with EVM.
For the color data, MurAll uses RGB565, which needs only 2 bytes for representing a color.
This means that 16 colors are packed per 32 byte object.
Also a color index is created of 256 colors as an array of 8 32-byte objects.
The canvas (2048 x 1024) is divided into groups of 32 pixels from left to right, top to bottom.
The full transaction data sent as part of the drawing onto MurAll consists of
- colorIndex - the color index; up to 256 RGB565 colours, 2 bytes each, packing up to 16 colours into each 32 bytes
- pixelData - pixel groups without transparency; 32 pixels, 1 byte each, referencing the colour from the index 0–255
- pixelGroups - group indexes, where these groups are located on MurAll; 2 bytes per index, up to 16 indexes packed into 32 bytes
- transparentPixelGroups - pixel groups containing transparency; 32 pixels, 1 byte each, referencing the colour from the index 0–255
- transparentPixelGroupIndexes - group indexes, where the groups with transparency are located on MurAll; 2 bytes per index, up to 16 indexes packed into 32 bytes
- metadata - image metadata, consisting of name (up to 32 characters), number (3 byes), series id (3 bytes), and whether the image contains alpha (1 bit). Everything except the name is packed into a 32-byte object.
Fill function - Contract storage for MurAll NFTs
Some may really want to push the image data onto smart contract storage no matter the cost.
For that, MurAll has the fill function.
Once the user clicks the fill button, the data is written piece by piece to the contract storage, until the process runs out of gas. The next fill transaction will continue writing the data where it left off from the previous transaction. It may take quite a few transactions depending on the size of the image, and thus it may cost a lot, but if the artist is truly driven to do it no matter the cost, then it is entirely possible.