Solidity tutorial 4 "Cryptographic Functions ~ Structs"

Cryptographic Functions

  • sha3(...) returns (bytes32)
    compute the SHA3 hash of the (tightly packed) arguments
  • sha256(...) returns (bytes32)
    compute the SHA256 hash of the (tightly packed) arguments
  • ripemd160(...) returns (bytes20)
    compute RIPEMD of 256 the (tightly packed) arguments
  • ecrecover(bytes32, byte, bytes32, bytes32) returns (address)
    recover public key from elliptic curve signature

In the above, "tightly packed" means that the arguments are concatenated without padding, i.e.

sha3("ab", "c") == sha3("abc") == sha3(0x616263) == sha3(6382179) = sha3(97, 98, 99)

If padding is needed, explicit type conversions can be used.

Contract Related

  • This (current contract's type)
    the current contract, explicitly convertible to address
  • suicide(address))` suicide the current contract, sending its funds to the given address

Furthermore, all functions of the current contract are callable directly including the current function.

Functions on addresses

It is possible to query the balance of an address using the property balance and to send Ether (in units of wei) to an address using the send function:

address x = 0x123;
if (x.balance < 10 && address(this).balance >= 10) x.send(10)

Also, to interface with contracts that do not adhere to the ABI (like the classic NameReg contract), the function call is provided which takes an arbitrary number of arguments of any type.

These arguments are ABI-serialized (i.e. also padded to 32 bytes).
One exception is the case where the first argument is encoded to exactly four bytes.
In this case, it is not padded to allow the use of function signatures here.

address nameReg =0x72ba7d8e73fe8eb666ea66babc8116a41bfb10e2;
nameReg.call("register", "MyName");
nameReg.call(bytes4(sha3("fun(uint256)")), a);

Note that contracts inherit all members of address, so it is possible to query the balance of the current contract using this.balance.

Order of Evaluation of Expressions

The evaluation order of expressions is not specified (more formally, the order in which the children of one node in the expression tree are evaluated is not specified, but they are of course evaluated before the node itself).
It is only guaranteed that statements are executed in order and short-circuiting for boolean expressions is done.

Arrays

Both variably and fixed size arrays are supported in storage and as parameters of external functions:

contract ArrayContract { 
    uint[2**20] m_aLotOfIntegers;
     bool[2][] m_pairsOfFlags;
    
     function setAllFlagPairs(bool[2][] newPairs) {
    // assignment to array replaces the complete array 
    m_pairsOfFlags = newPairs;
     }

      function setFlagPair(uint index, bool flagA, bool flagB) {
         // access to a non-existing index will stop execution
         m_pairsOfFlags[index][0] = flagA;
          m_pairsOfFlags[index][1] = flagB; 
          }

          function changeFlagArraySize(uint newSize) {
             // if the new size is smaller, removed array elements will be cleared
                m_pairsOfFlags.length = newSize;  
                }

          function clear() {
              // these clear the arrays completely delete m_pairsOfFlags;
               delete m_aLotOfIntegers; 
               // identical effect here 
               m_pairsOfFlags.length = 0;  
              }
            bytes m_byteData;

            function byteArrays(bytes data) external {
                     // byte arrays ("bytes") are different as they are stored without padding,
                      // but can be treated identical to "uint8"
                     m_byteData = data;
                     m_byteData.length += 7;
                    m_byteData[3] = 8;
                    delete m_byteData[2];  
                    }

Structs

Solidity provides a way to define new types in the form of structs, which is shown in the following example:

contract CrowdFunding {
  struct Funder { address addr;  uint amount;}
  struct Campaign {address beneficiary;
    uint fundingGoal;
    uint numFunders;
    uint amount;
    mapping (uint => Funder) funders;  
    }

  uint numCampaigns;
  mapping (
      uint => Campaign) campaigns;
    function newCampaign(address beneficiary, uint goal) returns (uint campaignID) {
        campaignID = numCampaigns++; // campaignID is return variable
        Campaign c = campaigns[campaignID];  // assigns reference
        c.beneficiary = beneficiary;
        c.fundingGoal = goal; 
        }

  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; 
    }

  function checkGoalReached(uint campaignID) returns (bool reached) {
    Campaign c = campaigns[campaignID];
    if (c.amount < c.fundingGoal)
      return false;
    c.beneficiary.send(c.amount);
    c.amount = 0;
    return true;  
    }

The contract does not provide the full functionality of a crowdfunding contract, but it contains the basic concepts necessary to understand structs.

Struct types can be used as value types for mappings and they can itself contain mappings.
Even the struct itself can be the value type of the mapping, although it is not possible to include a struct as is inside of itself.

Note how in all the functions, a struct type is assigned to a local variable.
This does not copy the struct but only store a reference so that assignments to members of the local variable actually write to the state.

Next Lesson

Summary of Lessons

AUTHOR

READ NEXT

Boostlog is an online community for developers
who want to share ideas and grow each other.

Delete an article

Deleted articles are gone forever. Are you sure?