Function Visibility and Global Variables

Function visibility

Contracts are made up of state variables and functions, but so far you have only executed functions using message calls from outside the contract. We can, however have our contracts call their own functions directly and this can use this to significantly simplify our code.

Lets quickly return to our crowdfund contract:

contract CrowdFunding {
    // data structure to hold information about campaign contributors
    struct Funder {
        address addr;
        uint amount;
    }
    // Campaign data structure
    struct Campaign {
        address beneficiary;
        uint fundingGoal;
        uint numFunders;
        uint amount;
        uint deadline;
        mapping (uint => Funder) funders;
    }
    //Declares a state variable 'numCampaigns'
    uint numCampaigns;
    //Creates a mapping of Campaign datatypes
    mapping (uint => Campaign) campaigns;
    //first function sets up a new campaign
    function newCampaign(address beneficiary, uint goal, uint deadline) returns (uint campaignID) {
        campaignID = numCampaigns++; // campaignID is return variable
        Campaign c = campaigns[campaignID]; // assigns reference
        c.beneficiary = beneficiary;
        c.fundingGoal = goal;
        c.deadline = block.number + deadline;
    }
    //function to contributes to the campaign
    function contribute(uint campaignID) {
        Campaign c = campaigns[campaignID];
        Funder f = c.funders[c.numFunders++];
        f.addr = msg.sender;
        f.amount = msg.value;
        c.amount += f.amount;
    }
    // checks if the goal or time limit has been reached and ends the campaign
    function checkGoalReached(uint campaignID) returns (bool reached) {
        Campaign c = campaigns[campaignID];
        if (c.amount >= c.fundingGoal){
            uint i = 0;
            uint f = c.numFunders;
            c.beneficiary.send(c.amount);
            c.amount = 0;
            c.beneficiary = 0;
            c.fundingGoal = 0;
            c.deadline = 0;
            c.numFunders = 0;
            while (i <= f){
                c.funders[i].addr = 0;
                c.funders[i].amount = 0;
                i++;
            }
        return true;
        }
        if (c.deadline <= block.number){
            uint j = 0;
            uint n = c.numFunders;
            c.beneficiary = 0;
            c.fundingGoal = 0;
            c.numFunders = 0;
            c.deadline = 0;
            c.amount = 0;
            while (j <= n){
                c.funders[j].addr.send(c.funders[j].amount);
                c.funders[j].addr = 0;
                c.funders[j].amount = 0;
                j++;
            }
            return true;
        }
        return false;
    }
}

Note how at the end of every event we always zero out the entries for our campaign, we should simplify our code by creating a function to perform this for us.

contract CrowdFunding {
    // data structure to hold information about campaign contributors
    struct Funder {
        address addr;
        uint amount;
    }
    // Campaign data structure
    struct Campaign {
        address beneficiary;
        uint fundingGoal;
        uint numFunders;
        uint amount;
        uint deadline;
        mapping (uint => Funder) funders;
    }
    //Declares a state variable 'numCampaigns'
    uint numCampaigns;
    //Creates a mapping of Campaign datatypes
    mapping (uint => Campaign) campaigns;
    //first function sets up a new campaign
    function newCampaign(address beneficiary, uint goal, uint deadline) returns (uint campaignID) {
        campaignID = numCampaigns++; // campaignID is return variable
        Campaign c = campaigns[campaignID]; // assigns reference
        c.beneficiary = beneficiary;
        c.fundingGoal = goal;
        c.deadline = block.number + deadline;
    }
    //function to contributes to the campaign
    function contribute(uint campaignID) {
        Campaign c = campaigns[campaignID];
        Funder f = c.funders[c.numFunders++];
        f.addr = msg.sender;
        f.amount = msg.value;
        c.amount += f.amount;
    }
    // checks if the goal or time limit has been reached and ends the campaign
    function checkGoalReached(uint campaignID) returns (bool reached) {
        Campaign c = campaigns[campaignID];
        if (c.amount >= c.fundingGoal){
            c.beneficiary.send(c.amount);
            clean(campaignID);
        	return true;
        }
        if (c.deadline <= block.number){
            uint j = 0;
            uint n = c.numFunders;
            while (j <= n){
                c.funders[j].addr.send(c.funders[j].amount);
                j++;
            }
            clean(campaignID)
            return true;
        }
        return false;
    }
    function clean(uint id) {
    	Campaign c = campaigns[id];
    	uint i = 0;
    	uint n = c.numfunders;
    	c.amount = 0;
        c.beneficiary = 0;
        c.fundingGoal = 0;
        c.deadline = 0;
        c.numFunders = 0;
        while (i <= n){
            c.funders[i].addr = 0;
            c.funders[i].amount = 0;
            i++;
        }
    }
}

While this contract works it now has a problem – when compiling contracts solidity assumes that you want all functions to be accessible from the outside via the ABI – but obviously we don’t want outside actors to be able to ‘clean’ our campaigns storage at will so we must mark it as being a function for internal use only:

function clean(uint id) private {
    	Campaign c = campaigns[id];
    	uint i = 0;
    	uint n = c.numfunders;
    	c.amount = 0;
        c.beneficiary = 0;
        c.fundingGoal = 0;
        c.deadline = 0;
        c.numFunders = 0;
        while (i <= n){
            c.funders[i].addr = 0;
            c.funders[i].amount = 0;
            i++;
        }

The function clean() is now a private function – this means that it can only be accessed by the contract itself – it cannot be called externally and if you put this contract into alethzero you would see no ABI function ID created.

The four options for specifying the visibility of functions are: external, public, inherited, and private. Public is the default and does not need to be specified – it allows access to the function either internally or via the ABI. Private, as mentioned, makes the function accessible only by the contract itself. inherited functions can be accessed by the contract and derivatives of the contract (we will cover contract inheritance in a later tutorial). External makes a function only accessible through message calls.

Failing to correctly specify the visibility of your function could lead to your contract not operating as specified it is especially important to consider when your functions amend a contracts state.

Previously, we have shown how how we can create accessor functions to our state variables by specifying it as public There are three possible visibility status’ for storage: inherited, private and public. The default is inherited and allows access to storage only to the contract and the contracts derivatives.

Global variables

Contracts live on the block chain – it is their home. You can send them information from the outside world via transactions and they will interact with it as their specification demands but this information is only as trustworthy as the source that provided it. This can lead to a situation where your contracts usefulness is limited by there being very little trusted information for it to run it’s logic on.

This matter’s little when your contract is a simple metacoin – the only information the contracts logic needs to assess is held in the coin balances in the storage – if you have enough coins, you can transfer some. Unfortunately this is not true of many dapps…

…Fortunately the consensus mechanism provided by the ethereum blockchain provides contracts with some information regarding the state of the blockchain that they can trust – these ‘global variables’ are listed below:

block.coinbase (address): current block miner’s address
block.difficulty (uint): current block difficulty
block.gaslimit (uint): current block gaslimit
block.number (uint): current block number
block.blockhash (function(uint) returns (hash)): hash of the given block
block.timestamp (uint): current block timestamp
msg.data (bytes): complete calldata
msg.gas (uint): remaining gas
msg.sender (address): sender of the message (current call)
msg.value (uint): number of wei sent with the message
tx.gasprice (uint): gas price of the transaction
tx.origin (address): sender of the transaction (full call chain)
this.balance (uint): current contract balance
addr.balance (uint): where addr is an address of an account in the ethereum network

All these variables return information to the contract regarding the “current” state of the blockchain – and (with the exception of timestamp) can be considered “truth” by contracts executing them. What use these variables are to the contract depends on the way they are used in the contracts design.

All commands prefixed with a block pass information about the current block, with the exception of block.blockhash which will return the hash of any block not older than 256 blocks.
block.number is very useful if we wish to build contracts that want to limit certain code execution to certain periods of time.
block.timestamp returns the unix time stamped by the miner of the block as an integer. This value should not be considered ‘accurate’ as a block will still be considered valid by the network even if the timestamp is not completely correct.
block.coinbase gives the contract the address of the miner currently processing the block and executing the code.

addr.balance lets you examine the balance of any ethereum address including contract addresses. Prefix ‘this’ to query the contracts own balance.

The commands prefixed with msg give you information on the latest msg call, the command prefixed with tx give you information on the original transaction that triggered the msg.call. This means that if your contract is executing code after being called by an account holder msg.sender & tx.origin will be the same, and if your contract is executing code after being called by another contract then msg.sender will be the calling contracts address and tx.origin will be the address of the original transaction caller.

The most useful of these variable is likely msg.sender as it is the public key of the sender of the message call. There are others in this list that give you a hint of what is going on in the network – block.difficulty provides you with information on the current cost to mine a block – block.coinbase gives you a winning miner. block.blockhash can be used as a source of entropy (though using this comes with some risk).

So far you have seen only a few of these in action but as we see more complex contracts being built we will find many of these very useful.

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