Grid

The Grid function is the core operation in the entire Loom system. The primary function of the Grid is to regulate usage of various limited resources. One of those limited resources is the disk space used by the Grid itself! Consequently you must pay one usage token to buy a grid location. If you sell a grid location back to the system, you receive a refund of one usage token.

The Grid administrator possesses the issuing location for usage tokens, and can thus regulate the supply of those tokens based on supply and demand for Grid resources.

Grid Terminology

An id is a 128-bit number expressed as a hexadecimal string, All hexadecimal strings must use lower-case letters 'a'-'f', not the upper-case letters 'A'-'F'. Example:

3a4511c895fc71fdfea08f3f3f8c7a97

A hash is a 256-bit number expressed as a hexadecimal string. Example:

6486b8158425d380642a444f5b2047fd97e452f7c92eaa8d8a7d2c53516d4a69

A quantity is a signed integer value with 128 bits of precision, expressed in decimal notation. The largest positive value is:

170141183460469231731687303715884105727

The smallest negative value is:

-170141183460469231731687303715884105728

A type is an id which represents a distinct "asset type." These asset types may be created at will for various purposes. There is one special-purpose asset type which represents usage tokens, the zero type:

00000000000000000000000000000000

A location is an id which represents a distinct "place" within a given asset type, where units of that asset type may be stored.

You may think of the grid as a whole as a giant 2-dimensional array. The rows and columns of this array are numbered from 0 to 2^128-1. Inside each cell of this array is a signed 128-bit integer quantity (a 2's-complement number).

The Grid

Row/Col 0 1 ... 2^128-1
0
1
...
2^128-1

Within each row (asset type) there is always exactly one location with a negative value. Initially there is a -1 at location 0 of every row. The negative location within a row is known as the issuer location for that row. The issuer location is the only place from which new units of the asset type can be created. Within every other location in a row, the value is either 0 or positive.

The grid operations maintain conservation of value. The sum of the values within each row is always precisely -1.

To "create" a new asset type, you simply choose a row at random and move the issuer location from its original place at location 0 to some other random location you choose. Now you control that asset type entirely, since you are the only entity which knows the issuer location for that type. You can issue units at will (at most 2^128-1 of them) and move them anywhere you like.

The grid therefore acts somewhat like a giant spreadsheet, albeit with some very restricted arithmetic properties. The grid is nothing more than a very solid and well-defined counting mechanism.

The beauty of the grid concept is that it allows us to build a web site starting from nothing but an empty grid, and then construct all sorts of content management applications from there, where the usage of limited resources such as disk space is strictly regulated and throttled by the numbers in the grid. For example, if we decided to provide a feature to upload pictures for safekeeping, the web site could charge a certain number of usage tokens per kilobyte of data uploaded.

If you don't do things this way, with some form of economic regulation, then a web site can become a giant "tragedy of the commons" with no sensible limits on usage. The traditional way most sites deal with this is to create a revenue model based on advertising. Perhaps the Loom method is a refreshing way for users to avoid all the ads, and providers to have a new revenue model.

Example API Call

Here is a url which executes a "Move" operation, moving 42500 units of type 0f8fccf7c65e42d422c37ea222e700d5 from the origin location c80481226973dfec6dc06c8dfe8a5b1c to the destination location 29013fc66a653f6765151dd352675d0f.

https://fexl.com/loom?function=grid&action=move
	&type=0f8fccf7c65e42d422c37ea222e700d5
	&qty=42500
	&orig=c80481226973dfec6dc06c8dfe8a5b1c
	&dest=29013fc66a653f6765151dd352675d0f

(The url is broken up across lines for clarity. In practice you would keep the entire url on a single line.)

When the API receives this GET operation from the internet, it translates the information into an internal key-value structure for easy access. It then executes the operation, which has the effect of filling out additional keys and values in the key-value structure. Then it sends the results back to the caller as a plain-text document, with the resulting key-value structure expressed in our simple standard "KV" format.

For example, after the url above is translated and executed, the API will send the result back to the caller like this:

Content-Type: text/plain

(
:function
=grid
:action
=move
:type
=0f8fccf7c65e42d422c37ea222e700d5
:qty
=42500
:orig
=c80481226973dfec6dc06c8dfe8a5b1c
:dest
=29013fc66a653f6765151dd352675d0f
:status
=success
:value_orig
=0
:value_dest
=42500
)

Grid Operations

Here we describe the API (application programming interface) for the Grid. The operations are Buy, Sell, Issuer, Touch, Look, and Move.

Buy

Buy a location in the grid. This costs one usage token. The input is:

Key Value Description
function grid
action buy Name of operation
type id Asset type
loc id Location to buy
usage id Location of usage tokens (where 1 is charged)

If the Buy operation succeeds, you will see the following keys in the result:

Key Value Description
status success Everything went well.
value qty The value at the new location. This will typically be 0, unless you are buying the location 0 for a brand new type, in which case it will be -1.
usage_balance qty New usage balance

If the operation fails, the status will be fail, and the reason for the failure will be indicated with any keys below which apply:

Key Value Description
status fail Something went wrong.
error_type not_valid_id type is not a valid id
error_loc not_valid_id loc is not a valid id
error_usage not_valid_id usage is not a valid id
error_loc occupied loc is already occupied (bought)
error_usage insufficent usage location did not have at least one usage token

Sell

Sell a location in the grid. This refunds one usage token. The input is:

Key Value Description
function grid
action sell Name of operation
type id Asset type
loc id Location to sell
usage id Location of usage tokens (where 1 is refunded)

If the Sell operation succeeds, you will see the following keys in the result:

Key Value Description
status success Everything went well.
value qty The value at the location. You can only sell a location that is empty: either a 0 value in a non-zero location, or a -1 value in a zero location. These are the values which can be safely deleted from the database without losing any information.
usage_balance qty New usage balance

If the operation fails, the status will be fail, and the reason for the failure will be indicated with any keys below which apply:

Key Value Description
status fail Something went wrong.
error_type not_valid_id type is not a valid id
error_loc not_valid_id loc is not a valid id
error_usage not_valid_id usage is not a valid id
error_loc vacant loc is already vacant (sold)
error_loc non_empty loc is not empty
error_loc cannot_refund Cannot sell a usage token location and receive the refund in same place.

Issuer

Change the issuer location for an asset type. The input is:

Key Value Description
function grid
action issuer Name of operation
type id Asset type
orig id Current issuer location
dest id New issuer location

If the Issuer operation succeeds, you will see the following keys in the result:

Key Value Description
status success Everything went well.
value_orig qty Value of original location (after the change)
value_dest qty Value of destination location

If the operation fails, the status will be fail, and the reason for the failure will be indicated with any keys below which apply:

Key Value Description
status fail Something went wrong.
error_type not_valid_id type is not a valid id
error_orig not_valid_id orig is not a valid id
error_dest not_valid_id dest is not a valid id
error_qty insufficient insufficient value at orig/dest (or other error listed below)

The operation must obey the following rules (otherwise you'll see error_qty = insufficient):

Touch

Examine a location directly, seeing the value stored there.

(Note that there is another operation called "Look" which examines a location indirectly using a hash, e.g. for audit purposes. See below.)

The input for the Touch operation is:

Key Value Description
function grid
action touch Name of operation
type id Asset type
loc id Location

If the Touch operation succeeds, you will see the following keys in the result:

Key Value Description
status success Everything went well.
value qty Value at location

If the operation fails, the status will be fail, and the reason for the failure will be indicated with any keys below which apply:

Key Value Description
status fail Something went wrong.
error_type not_valid_id type is not a valid id
error_loc not_valid_id loc is not a valid id
error_loc vacant loc is vacant (not yet bought)

Look

Examine a location indirectly, seeing the value stored there.

The Look operation examines a location indirectly using a hash. Using the hash, one may view the contents of a location without the ability to change them.

For example, you could safely divulge the hash of a location to another party for audit purposes. This would give the auditor the ability to monitor the location, but not to change it in any way. If all you have is the hash of a location, then you can Look but you can't Touch.

The input for the Look operation is:

Key Value Description
function grid
action look Name of operation
type id Asset type
hash hash Hash of location to examine

If the Look operation succeeds, you will see the following keys in the result:

Key Value Description
status success Everything went well.
value qty Value at location

If the operation fails, the status will be fail, and the reason for the failure will be indicated with any keys below which apply:

Key Value Description
status fail Something went wrong.
error_type not_valid_id type is not a valid id
error_hash not_valid_hash hash is not a valid hash
error_loc vacant location is vacant (not yet bought)

Move

Move units of a given type from one location to another.

The input for the Move operation is:

Key Value Description
function grid
action move Name of operation
type id Asset type
qty qty Number of units to move
orig id Origin location (subtract qty from here)
dest id Destination location (add qty to here)

The quantity is normally positive, but a negative or zero value is also allowed.

The Loom system first tries subtracting the qty from the origin and adding it to the destination. If the sign (+/-) of both the origin and destination remain unchanged, then the operation succeeds and the database is updated. Otherwise, if either sign changes, the operation fails and the database is unaffected.

In short, if both locations were positive or zero before the move, then they must remain so after the move.

Now consider the case where one of the locations is negative. That location is the privileged issuer location for the asset type, and in this case the move operation is either creating or destroying units of the asset type.

If the issuer location becomes more negative, units are being created at the other location. If the issuer location becomes less negative, units are being destroyed at the other location. The same rule applies here as well: if a location is negative before the move, it must remain negative after the move as well.

This simple rule, called sign preservation, enforces the principle of conservation of value within the Loom grid. Note also that this rule ensures that there can be only one issuer location (negative value) for a given type. This rule also prevents the negative value from moving elsewhere during a move. If you wish to move the issuer location, you must use the Issuer operation (see above).

If the Move operation succeeds, you will see the following keys in the result:

Key Value Description
status success Everything went well.
value_orig qty New value at origin
value_dest qty New value at destination

If the operation fails, the status will be fail, and the reason for the failure will be indicated with any keys below which apply:

Key Value Description
status fail Something went wrong.
error_type not_valid_id type is not a valid id
error_orig not_valid_id orig is not a valid id
error_dest not_valid_id dest is not a valid id
error_qty not_valid_int qty is not a valid integer value
error_qty insufficient insufficient value at orig/dest (or other error listed below)

Note that if the orig or destination is vacant (not bought), then the corresponding value_orig or value_dest will have a null value in the result. (Because null values are not actually stored, the value will simply be missing.)

The operation must obey the following rules (otherwise you'll see error_qty = insufficient):

Scan

Scan an entire set of locations and types in one operation.

The input for the Scan operation is:

Key Value Description
function grid
action scan Name of operation
locs list of id or hash Space-separated list of locations and/or hashes
types list of id Space-separated list of types
zeroes flag Option to force the scan to return 0-values

The Scan operation combines all the specified locs and types together, forming all possible pairs, and returns the value associated with each pair. It uses Touch for locations and Look for hashes.

Normally Scan does not return any 0 values it finds, but you can force it to do so by setting the "zeroes" flag to "1". Otherwise you can simply omit that flag altogether.

For each location L in the locs list, the output will contain this entry:

Key Value Description
loc/L list of qty:id Space-separated list of value:type pairs

Note that if a location L is completely empty for all specified types, the "loc/L" entry will also be empty, i.e. the null string. Because the output does not list entries which have null values, you will not see an entry at all for any completely empty location.

Example (specified in "KV" key-value format):

(
:function
=grid
:action
=scan
:locs
=cf432b0acbaa7065a852cdda9e68f4c2 7ec5db6c103d6c0ebf2110abbd01e9ab 06d384fafd07b729f2990ffdb2786e68
:types
=e420516d14dd97358c44a2be37e6a403 8610c5a529e57981f189189cd9e3158d
)

When you submit that request to the API, it will come back to you looking something like this:

(
:function
=grid
:action
=scan
:locs
=cf432b0acbaa7065a852cdda9e68f4c2 7ec5db6c103d6c0ebf2110abbd01e9ab 06d384fafd07b729f2990ffdb2786e68
:types
=e420516d14dd97358c44a2be37e6a403 8610c5a529e57981f189189cd9e3158d
:loc/cf432b0acbaa7065a852cdda9e68f4c2
=99804428:8610c5a529e57981f189189cd9e3158d
:loc/06d384fafd07b729f2990ffdb2786e68
=14556348000:e420516d14dd97358c44a2be37e6a403 39450540000:8610c5a529e57981f189189cd9e3158d
)

From this result we can determine that:

NOTE:

The Scan operation will scan at most 2048 pairs. This is a hard limit which cannot be circumvented. If you specify a list of locations and types which combine to form more than 2048 pairs, Scan will return the results only for the first 2048 pairs, and set error flags in the output as follows:

Key Value Description
status fail Something went wrong.
error excessive tried to scan too many pairs
error_max 2048 maximum allowed scan size