Get to the point with Solidity

As I explained in my previous post about coding for Ethereum, there are a lot of ways to learn Solidity. However, most of them are really humdrum if you already know how to code, almost if you know javascript. So, let’s get to the point with Solidity looking the simplest structures you need to start coding.

ethereum photo

Solidity is based on javascript, but it also owns structures from other functional languages like Haskell and from object-oriented languages like Java. To do Dapps you need more than knowing the language because you need to know about patterns, security, how to compile and publish, and what actions cost more gas than others. Also, Solidity owns more reserved words than the explained below and more complex structures like inserting assembly inline, but with a little base of javascript and reading the following script (just 242 lines) you will be ready to start the backend of your very own distributed application over the Ethereum Virtual Machine.

pragma solidity ^0.4.19; //Version of the compiler

import "./otherContractsFile.sol";

contract ContractName { //Declaration of the basic unit of code
   /***Variables and funtions***/
   bool boolVariable;
   uint unsignedIntVariable;
   int intVariable;
   int intVariableWithValue = 10;
   uint16 unsigned16BitInt;
   uint256 unsignedIntVariable2;
   ufixed unsignedFixedVariable;
   fixed128x19 fixedVariableWith128bitsAnd19DecimalPoints;
   string stringVariable = "It can store any UTF-8 encoded string";
   address addressVariable; //addresses are used to store user accounts and contracts identifiers
   var aVariable = intVariableWithValue; //aVariable is defined as an int variable
   uint constant lustrum = 5 years;

   /*State variables are permanently stored in the EVM
    *between external function calls for this contract. 
    */
   uint stateVariable;

   function doSomething(uint uintParam) {
      /*Variables declared inside functions
       *are stored in memory and they are reset 
       *between different calls to the function.
       */
      uint functionVariable;
      
      functionVariable++;
      stateVariable = stateVariable + functionVariable;
      /*functionVariable = 1
       *stateVariable = 1 the first time this function is executed,
       *2 the second time this functions is executed, 3 the third, ...
       */
   }

   /***Collections and your own types***/
   uint[2] fixedArray;
   uint[] dynamicArray;
   mapping (address => uint) mapFromAddressToUint;

   enum EnumType {
      FirstValue,
      SecondValue,
      ThirdValue
   }

   struct StructType {
      uint uintField;
      string stringField;
   }
   StructType structVariable;
   StructType structVariableWithValue = StructType(10, "something");
   StructType[] structArray;

   function manageStructArrayByValue() {
      /*This variable is asigned by value (a copy is done)*/
      StructType memory myStruct = structArray[0]; 
      myStruct.uintField = 10; //structArray[0].uintField = 0;
   }

   function manageStructArrayByReference() {
      /*This variable is asigned by reference (a pointer is created)*/
      StructType storage myStruct = structArray[0]; 
      myStruct.uintField = 10; //structArray[0].uintField = 10;
   }

   uint[] public publicArray; //A public array is read-only publicly accessible by other contracts
   mapping (uint => string) public publicMap;

   function workWithArrays() private {
      uint[] myArray;
      myArray.push(1); //myArray = [1]
      myArray.push(2); //myArray = [1,2]
      uint newLenth = myArray.push(1); //newLenth = 3, myArray = [1,2,1] 
   }

   /*Functions are public by default, so you need to set them private
    *in order to keep your contract secure. In other case, functions
    *can be called (and executed) by other contracts.
    */
   function doSomethingPrivate(uint uintParam) private {
      //some code
   }

   /*Internal functions are functions that can be called from
    *contracts that inherit from this one.
    */
   function doSomethingInternal(uint uintParam) internal {
       //some code
   }

   /*Public functions can be called from anywhere.*/
   function do(uint param) public {
      //some code
      doSomethingPrivate(param);
      doSomethingInternal(unsignedIntVariable);
      doSomethingPrivate(10); //Can't call to doSomethingExternal
   }

   /*External functions can be called from external contracts
    *but not from inside this contract.
    */
   function doSomethingExternal(uint param) external {
      //some code
   }

   function ContractName() public { //this is a constructor but be carefull using them, they are not executed in some special cases
      //do something
   }

   function return10() returns (uint) {
      return 10;
   }

   function returnMultipleValues() returns (uint value1, uint value2) {
      value1 = 10;
      value2 = 20;
   }

   function returnMultipleValues2() returns (uint, uint) {
      return(10, 20);
   }

   function useMultipleValues() {
      uint value1;
      uint value2;
      (value1, value2) = returnMultipleValues();

      uint value4;
      (,value4) = returnMultpleValues2();
   }

   /*function throwsAnError(int a) private returns (int8) {
    *   return a + 1;
    *}
    */

   function addAndConvert(int a) private returns (int8) {
      return int8(a) + 1; //uses the 8 less significant bits of a
   }

   function addAndConvertIfIsInt8(uint a) private returns (uint8) {
      require(a <= 2 ** 8); //Throws an error if false
      return uint8(a) + 1;
   }

   /***Events***/
   event sthOccurred(uint param);

   function throwEvent() private {
      sthOcurred(10);
   }

   /***Modifiers***/
   //"view" can be used to identify functions that are not changing any data
   function returnInt() public view returns (int) {
      return intVariable;
   }

   //"pure" can be used to identify functions that do not access any data in the contract
   function add(int a, int b) public pure returns (int) {
      return a + b;
   }

   //"payable" is needed in order to receive Ether with a call
   function aFunctionThatCost() public payable {
      //this contract will own the ether sended at the end of the execution
   }

   modifier myModifier() {
      //some code to be executed before the function
      _; //this is a placeholder that indicates the point where the code of the function will be executed
      //some code to be executed after the function
   }

   function functionWithModifier() public myModifier {
      //some code to be executed in the place where the placeholder is set inside modifier's code
   }

   function otherFunctionsAndValues() private {
      keccak256("qwerty"); //returns a 256-bit hexadecimal with a SHA3 hash of the param
      //"qwerty" == "QWERTY"; Solidity can't compare strings. Instead you can do
      keccak256("qwerty") != keccak256("QWERTY");

      uint currentUnixTimestamp = now;
      1 minutes == 60;
      1 hours == 3600;
      //you also have available "days", "weeks" and "years" units

      address currentBlocMiner = block.coinbase;
      uint currentBlockDifficulty = block.difficulty;
      uint currentBlockGasLimit = block.gaslimit;
      uint currentBlockNumber = block.number; 
      uint currentBlockUnixTimestamp = block.timestamp;
      bytes32 theHash = block.blockhash(block.number); //only works for 256 most recent blocks excluding current
      bytes completeCallData = msg.data;
      uint remainingGas = msg.gas;
      address callerWhoInitiatesThisExecution = msg.sender;
      bytes4 firstFourBytesOfMsgData = msg.sig;
      uint numberOfWei = msg.value;
      uint gasPriceOfTheTransaction = tx.gasprice;
      uint senderOfTheTransaction = tx.origin;

      assert(1==2); //like require but for internal errors
      revert(); //abort and revert changes
   }

}

/***Inheritance and rehusability***/
contract A {
   function aFunction {}
}

contract B is A {
   function bFunction {
      aFunction();
   }
}

/*If you want to use an external contract, you need to define an
 *interface with the definition of the methods that you want to
 *use.
 */
contract InterfaceOfExternalContract {
   function functionExternalDefinition(uint param) external return (uint);

   function functionPublicDefinition(uint param) public return (uint);
}

contract ContractWichUsesTheExternalContract {
   address externalContractAddress = 0x...;
   InterfaceOfExternalContract externalContract = InterfaceOfExternalContract(externalContractAddress);

   function aFunction() {
      uint value = externalContract.functionExternalDefinition(1);
   }
}

And now, what are you starting to code?

Como empezar a programar apps distribuidas en Solidity para Ethereum

Podría parecer que para programar Dapps, las aplicaciones que corren sobre la máquina virtual de Ethereum, es necesario ser un experto en blockchain, saber de criptografía, entender cómo se calculan los hash de los bloques, entender cómo está implementado el Proof of Work, o incluso saber cómo se mina. Sin embargo, no hace falta profundizar tanto para echar a andar una aplicación distribuida, veamos por dónde se puede empezar.

learn photo

Para desarrollar Dapps, basta con conocer cómo funciona la Ethereum Virutal Machine, conocer las arquitecturas y patrones que se emplean y manejarse con alguno de los lenguajes pensados para tal fin. El más popular es Solidity, que está basado en javascript, aunque hay otros como LLL (que está basado en Lisp) o Serpent (basado en Python).

Para aprender a programar con Solidity se puede empezar por muchos sitios. Puedes empezar a dar vueltas por el Wiki de Ethereum, o ir directamente a la documentación oficial, aunque personalmente creo que es un poco tediosa y no va demasiado al grano. Otra opción es buscar un buen tutorial en el que te enseñen paso a paso, como Cryptozombies que te enseña a hacer desde cero un juego como el popular Cryptokitties.

Para aprender el lenguaje cualquiera de esas vías es válida. Sin embargo,  por desgracia, creo que es necesario pasar por todas esas documentaciones para tener conocimiento de los patrones más habituales y estar preparado para hacer cualquier tipo de aplicación, ya que si por ejemplo te quedas en ver cómo está hecho Cryptokitties, sólo conocerás aquellos que sirven para hacer un sistema de compraventa de bienes únicos.

Es cierto que esto puede llevar mucho tiempo, y si tienes prisa por empezar a programar, puedes buscar un curso para que alguien te guíe y te dé información concisa y bien estructurada. Recientemente he empezado a colaborar con DevAcademy, una academia que ofrece cursos de alto nivel para las tecnologías más punteras (DevOps, Machine Learning, Big Data, …) y, cómo no, entre ellos tiene un curso de Solidity. Es una buena alternativa para que te lo den todo mascado, y además, le puedes pedir a tu empresa que te lo pague ya que le saldrá gratis por ser formación bonificada. Si quieres saber más sobre este u otro de sus cursos, no dudes en ponerte en contacto conmigo y que podamos ver tus necesidades o las de tu empresa.