Pages

Saturday, November 10, 2018

Building a Contract in Solidity and Uploading it to a Test Blockchain

In this lesson, we will write a contract and execute it on a test blockchain. The Ownable contract uses solidity 0.4.8, which is not the current version of solidity. For this reason we will debug the contract, replacing deprecated terms and syntax.

If you have not, you will need to download Visual Studio Code and install Juan Blanco’s Solidity compiler. You will need to download and install Node.js. This will allow you to download and install truffle with the command:

npm install truffle

You will also need to download and install Ganache, which will automatically set up the test blockchain.

To start, open PowerShell to start a new project with Truffle. Navigate to your desired directory and create a new folder with the mkdir command.  Since we will build the Ownable contract in this folder, name the folder ownable:

mkdir ownable
cd ownable

Once you have navigated to the new folder, create a new project using truffle:

truffle init

The console should return the following text:

Compile:        truffle compile
Migrate:        truffle migrate
Test contracts: truffle test

Now that you have initialized a project with truffle, it is time to create a contract. We are going to copy a contract from Chapter 7, page 148, of Blockchain: A PracticalGuide to Developing Business, Law, and Technology Solutions.

Write the following code in a Visual Studio file and save it as Ownable.sol under the contracts folder, created during the truffle initialization of the ownable folder.

pragma solidity ^0.4.8;
// module handling and transfer of contract ownership
contract Ownable {
    address public owner;
    function Ownable() {
        owner = msg.sender;
    }
    modifier onlyOwner {
        if(msg.sender != owner) revert();
        _;
    }
    function transferOwnership(address _newOwner) external onlyOwner {
        owner = _newOwner;
        TransferOwnership(msg.sender, _newOwner);
    }
    event TransferOwnership(address indexed _from, address indexed _to);
}

Now compile your code. You may use the short-cut F5 for this. Make sure that you have opened the file explorer. If not, you can use the command CTRL + SHIFT + E. Upon compiling the code, you should see a list of errors, under the PROBLEMS tab. We will solve these one at a time.




Debugging

The first error is not significant to the execution of the program. To make it disappear, we can enter a command above the first line:
//solium-disable linebreak-style
pragma solidity ^0.4.8;
// module handling and transfer of contract ownership
...

The next two errors appear on line 6:



The first error indicates we should have specified and access keyword like: public, private, internal or external. The second error notes that constructor() should be used to define a constructor for the class instead of function Ownable(). Edit the script to reflect this:
contract Ownable {
    address public owner;
    constructor() public {
        owner = msg.sender;
...

We change function Ownable() to constructor(). We also add the term public after the constructor. This allows the constructor to be called from both inside and outside of the contract.
A comprehensive list of visibility keywords for functions and state variables:
·        public - all can access the referenced object
·        external – The object cannot be accessed from outside of the contract
·        internal - only this contract and contracts deriving from it can access the object
·        private – the object can only be accessed only from this contract

After making the edits for the constructor, the errors for line 6 have disappeared.




Next is an error concerning the calling of revert().  The error suggests that a string should be passed into the revert function. We could pass one like this:

    modifier onlyOwner {
        if (msg.sender != owner) revert(“Error: non-owner access denied”);
        _;
...

The error disappears, but when we upload the contract to the blockchain, this will require more gas than if we do not pass a string to revert(). For now, we can leave this blank. The error will not affect anything.

To solve the next error, we need to call the event on line 15 using the term emit. This is required by more recent versions of solidity:

    function transferOwnership(address _newOwner) external onlyOwner {
        owner = _newOwner;
        emit TransferOwnership(msg.sender, _newOwner);
    }
...

If you have followed the instructions to this point, there should remain only the error concerning require() from line 6. The contract is ready to be executed. Before we do this, we will need to create a migration file for the Ownable contract and modify the Truffle.js file to point to a private blockchain.
Compile and Migrate
In order to upload the contract, we need to first convert the contract to a form that is readable in javascript. Then, this will be converted to byte code which is uploaded to the blockchain.
Using Visual Studio let’s create a javascript file called  2_ownable_migration.js , and save it under the ownable/migrations folder.
var Ownable  = artifacts.require('./Ownable.sol');
module.exports = function(deployer) {
    deployer.deploy(Ownable);
};

When the files are compiled using truffle, this script will be used to upload to the blockchain the json file representing the compiled contract.
Next, edit the truffle.js file, located in the ownable folder. This file identifies the network that will be used to locate the test blockchain to which we will upload the contract. Replace this code:
module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!
};

With the following:

module.exports = {
  networks: {
      development: {
          host: 'localhost',
          port: 7545,
          network_id: '*'
      }
  }
};

This points to the test blockchain on your local machine, that is created when you launch Ganache.
Now that everything is ready, make sure that you have navigated in the PowerShell to the ownable folder. Compile the contract using the commands:
truffle compile

If you were successful, you should see the following text:

Compiling .\contracts\Migrations.sol...
Compiling .\contracts\Ownable.sol...
Writing artifacts to .\build\contracts

Next, migrate the contracts to the blockchain. First, we will need to open Ganache so that there is a blockchain with which we can interact through truffle. When you launch Ganache, you will see the accounts created for the test blockchain:



Only the genesis block has been created. We will now upload the contract to the test blockchain by using the command:

truffle migrate

This will yield the following in the PowerShell

Using network 'development'.

Running migration: 1_initial_migration.js
  Deploying Migrations...
  ... 0x2bcc6f737e1244ee9be0db52bf59dd0e954b4c3c9ae2028b3f4479bd13d57cd6
  Migrations: 0xe9ab13bb64959432cf38416759cc2e4c0db7d6be
Saving successful migration to network...
  ... 0x661b37c2202a45457151ec65f23f15080f23238724c8d665db12df4bb67a6afc
Saving artifacts...
Running migration: 2_ownable_migration.js
  Deploying Ownable...
  ... 0x6603eaf64060e817a202810c5b6f717f3492a2f5d07fcef221b2af45057f5773
  Ownable: 0xcea93908c932064d61cd2dd1f72c974b190cc3ce
Saving successful migration to network...
  ... 0x6bfd670baad0f28816e6d0df7f2b9cd40e64b32fa70d2e3da73c241edcb09f47
Saving artifacts...

This reflects that blocks have been added to the genesis block. We also observe this in Ganache:



Create an Instance of the Contract
Now we can call the truffle console. Since we have already edited the truffle.js file, truffle will automatically connect to the network housing the test blockchain.

truffle console

If you have successfully connected the network provided by Ganache, you should see the following:

truffle(development)>

To create an instance of the contract, we must first create a variable using javascript commands. Enter the following lines one by one into the truffle console:

var ownable;
Ownable.deployed().then(function(instance){ownable = instance;})
ownable.transferOwnership(web3.eth.accounts[1]);

The command var ownable; creates a new object called ownable. The next line defines this object as an instance of the contract that we created.
After both commands the truffle console will return the result ‘undefined’.

If you are familiar with programming already, you will see that the contract is essentially a class. Finally we transfer ownership of the contract from the account identified by index [0] to the account identified by index[1].

The event is executed and logged, yielding the following text in the console:

{ tx: '0x20a8fd775c5c26868b18b2b61c127e6acdbc02e509fb28783aa9594b9195c9bc',
  receipt:
   { transactionHash: '0x20a8fd775c5c26868b18b2b61c127e6acdbc02e509fb28783aa9594b9195c9bc',
     transactionIndex: 0,
     blockHash: '0xa433b974f3ea4ae87aa94229263f64b2b3947056d77ca7be6212a569a5d8cf27',
     blockNumber: 5,
     gasUsed: 29986,
     cumulativeGasUsed: 29986,
     contractAddress: null,
     logs: [ [Object] ],
     status: '0x1',
     logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000400000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000800000000000004010002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000060000000000000000000000000000100000' },
  logs:
   [ { logIndex: 0,
       transactionIndex: 0,
       transactionHash: '0x20a8fd775c5c26868b18b2b61c127e6acdbc02e509fb28783aa9594b9195c9bc',
       blockHash: '0xa433b974f3ea4ae87aa94229263f64b2b3947056d77ca7be6212a569a5d8cf27',
       blockNumber: 5,
       address: '0xcea93908c932064d61cd2dd1f72c974b190cc3ce',
       type: 'mined',
       event: 'TransferOwnership',
       args: [Object] } ] }

Congratulations, you have successfully built and executed your first contract!

*Ingrid Caton shares credit for this post

No comments:

Post a Comment