The Ergo 'Box' model#
Ergo uses a transactional model similar to Bitcoin's Unspent Transaction Output (UTxO) model. In this model, transactions create and consume single-use entities called 'boxes'.
In ErgoScript, a 'box' is a versatile version of a UTXO. It represents not only the amount of cryptocurrency owned by an address, but also contains 'registers' for additional data. This data can range from simple values to complex structures, which can be used in transactions and smart contract execution.
This makes Ergo's box different from a traditional UTXO, which only represents an amount of unspent cryptocurrency associated with a certain address. In UTXO-based cryptocurrencies, each transaction consumes one or more UTXOs as inputs and creates one or more UTXOs as outputs, with the 'unspent' outputs being the 'coins' that can be spent in future transactions.
The term 'box' in Ergo's context captures the idea that these entities are like containers holding various types of information (value, tokens, custom data, etc.), beyond just the unspent transaction output balance. This makes the boxes in Ergo significantly more flexible and functional, enabling more complex operations, such as running scripts or smart contracts, directly on the blockchain.
Key Points#
- A box is an immutable unit, which can be created or removed, but never altered.
- The box is not just a simple coin; it houses data, code, and registers, with all of its contents exclusively stored in the registers.
- Four pre-defined registers contain the box's monetary value, its protection script, and the ID of the transaction that created the box.
- Each box has a unique ID, derived from the unique contents of the box, including the data of the transaction that created it.
- Boxes are integral to the Ergo protocol. The active box set is authenticated through a hash-based data structure, facilitating the development of lightweight full nodes, as detailed in this paper.
- A box can hold up to six additional registers with typed data, accessible by the script.
- Transactions consist of both input and output boxes.
An example box#
Consider the 'proof-of-no-premine' from the Ergo genesis state. This box contains the last block IDs from Bitcoin and Ethereum at the launch time, as well as the latest news headlines:
{
"boxId": "b8ce8cfe331e5eadfb0783bdc375c94413433f65e1e45857d71550d42e4d83bd",
"value": 1000000000,
"ergoTree": "10010100d17300",
"assets": [],
"creationHeight": 0,
"additionalRegisters": {
"R5": "0e42307864303761393732393334363864393133326335613261646162326535326132333030396536373938363038653437623064323632336337653365393233343633",
"R6": "0e464272657869743a20626f746820546f727920736964657320706c617920646f776e207269736b206f66206e6f2d6465616c20616674657220627573696e65737320616c61726d",
"R8": "0e45d094d0b8d0b2d0b8d0b4d0b5d0bdd0b4d18b20d0a7d0a2d09fd09720d0b2d18bd180d0b0d181d182d183d18220d0bdd0b02033332520d0bdd0b020d0b0d0bad186d0b8d18e",
"R7": "0e54e8bfb0e8af84efbc9ae5b9b3e8a1a1e38081e68c81e7bbade38081e58c85e5aeb9e28094e28094e696b0e697b6e4bba3e5ba94e5afb9e585a8e79083e58c96e68c91e68898e79a84e4b8ade59bbde4b98be98193",
"R4": "0e403030303030303030303030303030303
0303031346332653265376533336435316165376536366636636362363934326333343337313237623336633333373437"
}
}
Additional Box Functions#
Besides the registers, each box features a unique identification hash that can be referenced using the id
function. Box ids are computed by applying the blake2b256
hash function to the box's content, expressed as a Coll[Byte]
. You can directly access the un-hashed byte collection representing a box using the bytes
function. Note that each box’s content and id are cryptographically unique, meaning that no two boxes within the blockchain can share the same id or content bytes. This uniqueness is guaranteed by the inclusion of creationInfo
in each box, as transaction ids and associated output indexes must be unique to a given UTXO. The bytesWithoutRef
function can be used to retrieve a Coll[Byte]
that excludes such information.
Example#
{
// Retrieve the value and token multipliers from the registers of the current box
val valueMultiplier = SELF.R4[Int].get
val tokenMultiplier = INPUTS(1).R4[Int].get
// Check if the current box is the same as the first input box
if(SELF.id == INPUTS(0).id){
// If it is, check if the output box has the correct value and token amounts
val outputValue = OUTPUTS(0).value == SELF.value * valueMultiplier
val outputTokens = OUTPUTS(0).tokens(0)._2 == SELF.value * tokenMultiplier
// Return a Sigma proposition that is true only if both outputValue and outputTokens are true
sigmaProp(outputValue && outputTokens)
}else{
// If the current box is not the same as the first input box, check if the output goes to a specified address
val outputGoesToCheese = {
// Create a public key that corresponds to a specific address
PK("9etXmP7D3ZkWssDopWcWkCPpjn22RVuEyXoFSbVPWAvvzDbcDXE").propBytes
== OUTPUTS(0).propositionBytes
}
// Return a Sigma proposition that is true only if outputGoesToCheese is true
sigmaProp(outputGoesToCheese)
}
}
Additional Resources#
- See the Box Format page for a more technical overview.
- For the box type description in the ErgoScript language specification.
- Visit ErgoAddress.scala, ErgoBoxCandidate, and ErgoBox.
- For an in-depth explanation on Ergo box modeling, see this page.