Typing and Your Contracts Storage

Typing in solidity

Solidity includes 7 basic types, listed below:

hash: 256-bit, 32-byte data chunk, indexable into bytes and operable with bitwise operations.
uint: 256-bit unsigned integer, operable with bitwise and unsigned arithmetic operations.
int: 256-bit signed integer, operable with bitwise and signed arithmetic operations.
string32: zero-terminated ASCII string of maximum length 32-bytes (256-bit).
address: account identifier, similar to a 160-bit hash type.
bool: two-state value.

Solidity is a statically typed language – this means that a variables type must be known at compile time, thus it differs from javascript whose loose typing allows more flexibility in the typing of variables. Explicit type conversion is typically only allowed when converting between signed and unsigned integers, or when converting an address or an integer to a hash.

It is also possible to specify the size of uint, int and hash by suffixing the required bit width in steps of 8 bits (hash160, int8, uint32 etc..).

In addition to these types it is possible to define structs and mappings as datatypes (which I will show below). Every type is based around Ethereum’s 32byte word limit.

Your contracts storage

Every contract on the blockchain has it’s own storage which only it can write to. This is known as the contracts state and it is a flexible database which allows you almost unlimited storage space – if you are willing to pay for it!

A contract’s storage is at its most basic a key-value store with 2^256 possible keys and 2^256 values. This makes for sufficient possible storage to create database structures of any type imaginable.

Solidity has several tools for you to use to structure the storage of a contract as a relational database model. In the previous contract you used a mapping to store value associated with an address but this only one of many options.

In this tutorial we will cover the basic use of structs, state variables and mappings that abstract the creation of complex rules for storing information.

Structs

Structs may be familiar to anyone who has used C type language before – essentially they are physical grouping of variables, stored under one reference:

struct coinWallet {
	uint redCoin;
	uint greenCoin;
}

This code defines a ‘type’ of struct but does not initialise an instance of it – this means that defining the struct doesn’t write anything to the contracts storage, in order to do this we have to declare an instance of the struct and then assign a value to at least on of its parameters:

coinWallet myWallet;
myWallet.redCoin = 500
myWallet.greenCoin = 250

This would write to storage addresses 0 and 1 respectively – try deploying this contract in Alethzero:

contract Test{
	struct coinWallet {
	uint redCoin;
	uint greenCoin;
	}
	coinWallet myWallet;
	function Test(){
		myWallet.redCoin = 500;
		myWallet.greenCoin = 250;
	}
}

Note in the above how a dot operator on the myWallet instance of the coinWallet struct accesses the underlying parameters of the myWallet variable.

When used as a variable of finite size (i.e. not inside a mapping) structs place things continuously in storage starting at key value ‘0x0’. If you Deployed the above in Alethzero be sure to look inside the contract pane to see the storage addresses the above writes to.

Mappings

Structs become far more interesting when used as data types for values inside of mappings.

Here is our very first metaCoin contract amended so that each user has two balances:

contract metaCoin {
	struct coinWallet {
	uint redCoin;
	uint greenCoin;
	}
	mapping (address => coinWallet) balances;
	function metaCoin() {
		balances[msg.sender].redCoin = 10000;
		balances[msg.sender].greenCoin = 5000;
	}
	function sendRed(address receiver, uint amount) returns(bool successful) {
		if (balances[msg.sender].redCoin < amount) return false;
		balances[msg.sender].redCoin -= amount;
		balances[receiver].redCoin += amount;
		return true;
	}
	function sendGreen(address receiver, uint amount) returns(bool successful) {
		if (balances[msg.sender].greenCoin < amount) return false;
		balances[msg.sender].greenCoin -= amount;
		balances[receiver].greenCoin += amount;
		return true;
	}
}

Mappings calculate references for data storage by hashing the keys passed to the mapping. More details on how this works can be found here.

We can also include mappings as data types within another mapping:

contract rainbowCoin {
	mapping (address => mapping (uint => uint)) balances;
	function rainbowCoin() {
		balances[msg.sender][0] = 10000; ///red coin
		balances[msg.sender][1] = 10000; ///orange coin
		balances[msg.sender][2] = 10000; ///yellow coin
		balances[msg.sender][3] = 10000; ///green coin
		balances[msg.sender][4] = 10000; ///blue coin
		balances[msg.sender][5] = 10000; ///indigo coin
		balances[msg.sender][6] = 10000; ///violet coin
	}
	function sendCoin(address receiver, uint amount, uint coin) returns(bool successful) {
		if (balances[msg.sender][coin] < amount) return false;
		balances[msg.sender][coin] -= amount;
		balances[receiver][coin] += amount;
		return true;
	}
}

Note how this allows us to access elements in the sub mapping inside balances using square brackets [][].

It is also possible to place mappings inside of structs, and place structs inside mappings – in fact the only data type that you cannot place inside a struct or a mapping is itself.

Try deploying the rainbowCoin contract above by pasting it into the Alethzero transact window. You will find that it behaves just like our coin contract from the first tutorial, the only difference is when sending a transaction you must include a third argument ‘coin’ which should be an integer between 0 and 6.

A typical data array for a transaction calling our sendCoin function should look like this:
$0x90b98a11
0x5487699870...
500
4

Check the contract pane to view the changes to the contracts storage this transaction causes.

Accessor Functions

So far you have viewed the contents of any contract you have added to the network using Alethzero’s GUI, however we have not defined any way to ‘get’ the value associated with a key directly. This is necessary requirement for many contracts because although we as external actors can easily view the whole of the contracts storage – other contracts are not able to look inside another contracts storage without executing a message call to a function specifically defined to return the relevant information.

Fortunately for us, Solidity will automatically create an accessor function to any of the state variables we choose to make public using the public keyword. By amending our Rainbow coin contract we can have solidity create an accessor function automatically:

contract rainbowCoin {
	mapping (address => mapping (uint => uint)) public balances;
	function rainbowCoin() {
		balances[msg.sender][0] = 10000; ///red coin
		balances[msg.sender][1] = 10000; ///orange coin
		balances[msg.sender][2] = 10000; ///green coin
		balances[msg.sender][0] = 10000; ///red coin
		balances[msg.sender][1] = 10000; ///orange coin
		balances[msg.sender][2] = 10000; ///green coin
	}
	function sendCoin(address receiver, uint amount, uint coin) {
		if (balances[msg.sender][coin] < amount) return;
		balances[msg.sender][coin] -= amount;
		balances[receiver][coin] += amount;
	}
}

If you copy the above into Alethzero’s new transaction window you will see an additional 4 byte ABI code has been generated by the compiler called ‘balances’. This function could be executed by a transaction, but in reality it never would be. Instead accessor functions are accessed via message calls from other contracts and calls made from our web front-end. Both of these will be demonstrated in a later tutorial.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s