Introduction to Ethereum - Part 2


Bhaskar S 12/22/2017


Overview

In the previous article Part 1 of this series, we introduced some basic concepts in and got our hands dirty with Ethereum by setting up a private network with 4 accounts and sending a transaction between accounts.

In this article, we will explore how to build, deploy, and trigger Smart Contracts in Ethereum using Solidity, a high-level, contract-oriented, statically typed, compiled to bytecode, programming language.

So, what are Smart Contracts really ??? Lets us refer back to our first article, Introduction to Blockchain, where we indicated a Smart Contract is a digital legal contract that consists of some state (data representing the conditions of the contract), along with some code (logic that implements the contract process), and resides in the Blockchain.

When some event (another transaction) satisfying the terms and conditions of the contract occurs, the code associated with the contract self-executes, legalizing and enforcing the terms of the contract, and potentially updating the state (recording the conditions of the contract) in the Blockchain, as well as possibly generating additional transaction(s), without the involvement of any third party agents (notaries, lawyers, etc).

So, whats the big deal ??? Efficiency, Immutability, and Transparency. Imagine a complex multi-step contract process involving multiple third party agents. Using Blockchain and Smart Contracts, the entire contract process can be automated and simplified, thereby making the whole process efficient, in addition to increasing transparency of the transactions, and establishing trust/credibility amongst the involved parties.

Installation

The installation will be on a Ubuntu 16.04 LTS (and above) based Linux desktop.

We will assume a hypothetical user called polarsparc with the home directory located at /home/polarsparc.

Assuming that we are logged in as polarsparc and the current working directory is the home directory /home/polarsparc, we will create two additional sub-directories by executing the following commands:

$ mkdir -p Ethereum/src

$ mkdir -p Ethereum/bin

Now, change the current working directory to the directory /home/polarsparc/Ethereum.

To install the Solidity compiler, execute the following commands:

$ sudo apt-get update

$ sudo apt-get install solc

Once the installation complete, execute the following command to check everything was ok:

$ solc --version

The following would be the typical output:

Output.1

solc, the solidity compiler commandline interface
Version: 0.4.19+commit.c4cbbb05.Linux.g++

NOTE: The Solidity compiler is being continuously improved and enhanced, so the version is likely to change.

Hands-on with Smart Contracts using Solidity

We will assume that we have started the single Ethereum node in our private network, and have the geth Javascript shell prompt ready.

In order to get started with Smart Contracts in Ethereum, we need to write the contract logic using Solidity.

Referring to our first article, Introduction to Blockchain, we will implement the simple usecase of the transfer of a vehicle from the dealer to the buyer. We will start simple and evolve as we go along.

The following is the Solidity source code named Vehicle.sol located in the directory /home/polarsparc/Ethereum/src:

Vehicle.sol
pragma solidity ^0.4.15;

/*
 * A Vehicle instance is first created in the Ethereum blockchain by the dealer.
 * Once the payment is received, the dealer transfers ownership to the buyer.
 */

contract Vehicle {
    uint vin_no;
    address owner;
    
    function getVinNo() public view returns (uint) {
        return vin_no;
    }
    
    function getOwner() public view returns (address) {
        return owner;
    }
    
    function soldTo(address buyer) public {
        // Only the current owner can transfer ownership
        if (msg.sender == owner) {
            owner = buyer;
        }
    }
    
    function Vehicle(uint vin, address dealer) public {
        vin_no = vin;
        owner = dealer;
    }
}

Let us explain some of the important keywords used in the Vehicle.sol file shown above.

A Solidity source file must always begin with a version pragma. In our case it is the first line pragma solidity ^0.4.15. This indicates that the source code will not compile with a Solidity compiler with version earlier than 0.4.15 or starting from 0.5.0.

The keyword contract is similar to the keyword class in many popular object-oriented programming languages like C++, Java, etc. It encapsulates state variables, functions, etc

The keyword uint is a built-in data-type and indicates an unsigned integer that is 256 bits long.

The keyword address is a built-in data-type and indicates the 20 byte hexadecimal account address.

The variables vin_no and owner represent the contract's state information and will be permanently stored in a block in Ethereum (often referred to as the contract storage).

The keyword public in the function definition indicates that the function can either be called internally or via messages.

The keyword view in the function definition indicates that the function will not modify any state variables.

The global variable msg.sender captures the account address of the caller or sender of the transaction message.

To compile Vehicle.sol using the Solidity compiler, execute the following command:

$ solc -o ./bin --abi --bin --gas ./src/Vehicle.sol

The following would be the typical output:

Output.2

======= ./src/Vehicle.sol:Vehicle =======
Gas estimation:
construction:
   40527 + 105000 = 145527
external:
   getOwner():  486
   getVinNo():  416
   soldTo(address): 20710

From the Output.2 above, one can infer the amount of gas that will be needed to deploy (construction) and/or invoke the different contract functions (once deployed)

There will be two generated files, namely, Vehicle.abi and Vehicle.bin located in the directory /home/polarsparc/Ethereum/bin.

The option --gas passed to the Solidity compiler enables one to get an estimate of the gas required to create/deploy a contract and to interact with its functions.

The option --abi passed to the Solidity compiler enables the creation of the Vehicle.abi file. ABI stands for Application Binary Interface and is a language neutral contract specification, which details all of the publicly accessible contract methods and their associated parameters. For a contract function written in Solidity to call another contract function written in another language, say, Serpent, they both need to implement the same approach to serialize and deserialize data - hence the need for a common ABI specification. In other words, ABI is intended to serve as the standard for encoding and decoding of data in to and out of transactions.

The following is a pretty version of the contents of the file Vehicle.abi located in the directory /home/polarsparc/Ethereum/bin:

Vehicle.abi
[
    {
        "constant": false,
        "inputs": [
            {
                "name": "buyer",
                "type": "address"
            }
        ],
        "name": "soldTo",
        "outputs": [],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "getVinNo",
        "outputs": [
            {
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "getOwner",
        "outputs": [
            {
                "name": "",
                "type": "address"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "inputs": [
            {
                "name": "vin",
                "type": "uint256"
            },
            {
                "name": "dealer",
                "type": "address"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "constructor"
    }
]

The option --bin passed to the Solidity compiler enables the creation of the Vehicle.bin binary file containing the hex-encoded binary. This file contains the bytecode for the specified contract source file Vehicle.sol. This bytecode will be executed by the Ethereum Virtual Machine (EVM), which serves as a runtime environment for smart contracts.

The following is a pretty version of the contents of the file Vehicle.bin located in the directory /home/polarsparc/Ethereum/bin:

Vehicle.bin
6060604052341561000f57600080fd5b60405160408061029a833981016040528080519060200190919080519060200190919050508160008190
555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffff
ffffff160217905550505061020d8061008d6000396000f300606060405260043610610057576000357c01000000000000000000000000000000
00000000000000000000000000900463ffffffff168063683c80741461005c5780636c41597a14610095578063893d20e8146100be575b600080
fd5b341561006757600080fd5b610093600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610113565b00
5b34156100a057600080fd5b6100a86101ae565b6040518082815260200191505060405180910390f35b34156100c957600080fd5b6100d16101
b7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191
505060405180910390f35b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffff
ffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614156101ab5780600160006101000a81548173ffffffffffff
ffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505b50565b6000805490509056
5b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050905600a165627a7a72305820bceb3476d0c8
33c549d1f9f84d71bcfd86b3e23e2ec8c4641a2f71225675fe7f0029

Unfortunately, there is no easy way to load these two files Vehicle.abi and Vehicle.bin via the geth Javascript shell. Found an excellent article written by Gustavo (Gus) Guimaraes (link included in the References) addressing this issue.

To compile Vehicle.sol using the Solidity compiler to generate a Javascript file (with .js file extension) that will contain both the ABI as well as the bytecode, execute the following command:

$ echo "var vehicle=`solc --optimize --combined-json abi,bin,interface src/Vehicle.sol`" > bin/Vehicle.js

The above command will generate a Javascript file called Vehicle.js located in directory /home/polarsparc/Ethereum/bin with both the ABI and bytecode for the specified contract Vehicle.sol encoded as JSON.

To load the above generated Javascript file Vehicle.js, execute the following command in the geth Javascript shell prompt:

> loadScript("./bin/Vehicle.js")

The following would be the typical output:

Output.3

true

To check the value stored in the variable vehicle, execute the following command in the Javascript shell prompt:

> vehicle

The following would be the typical output:

Output.4

{
  contracts: {
    src/Vehicle.sol:Vehicle: {
      abi: "[{\"constant\":false,\"inputs\":[{\"name\":\"buyer\",\"type\":\"address\"}],\"name\":\"soldTo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getVinNo\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"vin\",\"type\":\"uint256\"},{\"name\":\"dealer\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]",
      bin: "6060604052341561000f57600080fd5b6040516040806101f48339810160405280805191906020018051600093845560018054600160a060020a031916600160a060020a03909216919091179055506101959182915061005f90396000f3006060604052600436106100565763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663683c8074811461005b5780636c41597a14610089578063893d20e8146100ae575b600080fd5b341561006657600080fd5b61008773ffffffffffffffffffffffffffffffffffffffff600435166100ea565b005b341561009457600080fd5b61009c610147565b60405190815260200160405180910390f35b34156100b957600080fd5b6100c161014d565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6001543373ffffffffffffffffffffffffffffffffffffffff90811691161415610144576001805473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b60005490565b60015473ffffffffffffffffffffffffffffffffffffffff16905600a165627a7a72305820ead3ff4e0d30a244745dab2015896c6d3ddcbd2ba949323e6386ca18620d7a960029"
    }
  },
  version: "0.4.19+commit.c4cbbb05.Linux.g++"
}

To retrieve the abi value from the variable vehicle, execute the following command in the Javascript shell prompt:

> vehicle.contracts['src/Vehicle.sol:Vehicle'].abi

The following would be the typical output:

Output.5

"[{\"constant\":false,\"inputs\":[{\"name\":\"buyer\",\"type\":\"address\"}],\"name\":\"soldTo\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getVinNo\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"vin\",\"type\":\"uint256\"},{\"name\":\"dealer\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]"

Similarly, to retrieve the bin value from the variable vehicle, execute the following command in the Javascript shell prompt:

> vehicle.contracts['src/Vehicle.sol:Vehicle'].bin

The following would be the typical output:

Output.6

"6060604052341561000f57600080fd5b6040516040806101f48339810160405280805191906020018051600093845560018054600160a060020a031916600160a060020a03909216919091179055506101959182915061005f90396000f3006060604052600436106100565763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663683c8074811461005b5780636c41597a14610089578063893d20e8146100ae575b600080fd5b341561006657600080fd5b61008773ffffffffffffffffffffffffffffffffffffffff600435166100ea565b005b341561009457600080fd5b61009c610147565b60405190815260200160405180910390f35b34156100b957600080fd5b6100c161014d565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6001543373ffffffffffffffffffffffffffffffffffffffff90811691161415610144576001805473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b60005490565b60015473ffffffffffffffffffffffffffffffffffffffff16905600a165627a7a72305820ead3ff4e0d30a244745dab2015896c6d3ddcbd2ba949323e6386ca18620d7a960029"

For convenience and ease of use, let us assign the addresses of the 2nd and 3rd accounts to variables named buyer and dealer using the Javascript shell as shown below:

> buyer = "0x35ddac855e0029676f489dafca9ab405a348317c"

> dealer = "0x46bf8994c8702919434271d89bcad8abec915612"

Now we are at a point ready to deploy our first Smart Contract called Vehicle into our private Ethereum network.

The first step is to create a contract object. To create a contract object called vehicle_contract, execute the following command in the Javascript shell prompt:

> var vehicle_contract = eth.contract(JSON.parse(vehicle.contracts['src/Vehicle.sol:Vehicle'].abi))

The following would be the typical output:

Output.7

undefined

To check the value of the contract object variable vehicle_contract, execute the following command in the Javascript shell prompt:

> vehicle_contract

The following would be the typical output:

Output.8

{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "soldTo",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getVinNo",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getOwner",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}, {...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "constructor"
  }],
  eth: {
    accounts: ["0xef17ec5df3116dea3b7abaf1ff3045639453cc76", "0x35ddac855e0029676f489dafca9ab405a348317c", "0x46bf8994c8702919434271d89bcad8abec915612", "0x518a6377a3863201aef3310da41f3448d959a310"],
    blockNumber: 83,
    coinbase: "0xef17ec5df3116dea3b7abaf1ff3045639453cc76",
    compile: {
      lll: function(),
      serpent: function(),
      solidity: function()
    },
    defaultAccount: undefined,
    defaultBlock: "latest",
    gasPrice: 18000000000,
    hashrate: 0,
    mining: false,
    pendingTransactions: [],
    protocolVersion: "0x3f",
    syncing: false,
    call: function(),
    contract: function(abi),
    estimateGas: function(),
    filter: function(options, callback, filterCreationErrorCallback),
    getAccounts: function(callback),
    getBalance: function(),
    getBlock: function(),
    getBlockNumber: function(callback),
    getBlockTransactionCount: function(),
    getBlockUncleCount: function(),
    getCode: function(),
    getCoinbase: function(callback),
    getCompilers: function(),
    getGasPrice: function(callback),
    getHashrate: function(callback),
    getMining: function(callback),
    getPendingTransactions: function(callback),
    getProtocolVersion: function(callback),
    getRawTransaction: function(),
    getRawTransactionFromBlock: function(),
    getStorageAt: function(),
    getSyncing: function(callback),
    getTransaction: function(),
    getTransactionCount: function(),
    getTransactionFromBlock: function(),
    getTransactionReceipt: function(),
    getUncle: function(),
    getWork: function(),
    iban: function(iban),
    icapNamereg: function(),
    isSyncing: function(callback),
    namereg: function(),
    resend: function(),
    sendIBANTransaction: function(),
    sendRawTransaction: function(),
    sendTransaction: function(),
    sign: function(),
    signTransaction: function(),
    submitTransaction: function(),
    submitWork: function()
  },
  at: function(address, callback),
  getData: function(),
  new: function()
}

Next, we will define 3 variables, namely, vin, gas_price, and contract_transaction with values representing the Vehicle Identification Number (VIN), the gas price paid for the contract creation, and the contract transaction object that encapsulates the address of the account creating the contract, the bytecode of the contract, and the gas price. Execute the following statements in the Javascript shell as shown below:

> var vin = 1234567890

> var gas_price = 1000000

> var contract_transaction = { from: dealer, data: '0x'+vehicle.contracts['src/Vehicle.sol:Vehicle'].bin, gas: gas_price }

To check the value of the contract transaction object variable contract_transaction, execute the following command in the Javascript shell prompt:

> contract_transaction

The following would be the typical output:

Output.9

{
  data: "0x6060604052341561000f57600080fd5b6040516040806101f48339810160405280805191906020018051600093845560018054600160a060020a031916600160a060020a03909216919091179055506101959182915061005f90396000f3006060604052600436106100565763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663683c8074811461005b5780636c41597a14610089578063893d20e8146100ae575b600080fd5b341561006657600080fd5b61008773ffffffffffffffffffffffffffffffffffffffff600435166100ea565b005b341561009457600080fd5b61009c610147565b60405190815260200160405180910390f35b34156100b957600080fd5b6100c161014d565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6001543373ffffffffffffffffffffffffffffffffffffffff90811691161415610144576001805473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b60005490565b60015473ffffffffffffffffffffffffffffffffffffffff16905600a165627a7a72305820ead3ff4e0d30a244745dab2015896c6d3ddcbd2ba949323e6386ca18620d7a96002900000000000000000000000000000000000000000000000000000000499602d200000000000000000000000046bf8994c8702919434271d89bcad8abec915612",
  from: "0x46bf8994c8702919434271d89bcad8abec915612",
  gas: "0xf4240"
}

Since the contract is deployed by the dealer, we need to unlock the dealer account before proceeding further.

To unlock the dealer account, execute the following command in the Javascript shell prompt:

> personal.unlockAccount(dealer)

This will prompt us for the password for the dealer account. The following would be the typical output:

Output.10

Unlock account 0x46bf8994c8702919434271d89bcad8abec915612
Passphrase: dealer
true

The second step is to create an instance of the contract object by calling the new method on the contract object vehicle_contract, passing in the required arguments. Execute the following command in the Javascript shell prompt:

> var vehicle_contract_inst = vehicle_contract.new(vin, dealer, contract_transaction)

The following would be the typical output:

Output.11

undefined

To check the value of the contract instance variable vehicle_contract_inst, execute the following command in the Javascript shell prompt:

> vehicle_contract_inst

The following would be the typical output:

Output.12

{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "soldTo",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getVinNo",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getOwner",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}, {...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "constructor"
  }],
  address: undefined,
  transactionHash: "0x56eb85db9905d2b6f33a832f1bae745b59dabc34c54db31346cffe453dec2910"
}

The above contract instance creation command will create an Ethereum transaction that needs to be mined for the contract to be deployed on the private Blockchain network.

From the Output.12, we see the transactionHash for the contract deployment transaction.

To start the miner with one mining thread, execute the following command in the Javascript shell prompt:

> miner.start(1)

In a few seconds (about 5 to 10), the contract deployment transaction will be mined and the contract will be deployed to our private Blockchain network.

To stop the miner, execute the following command in the Javascript shell prompt:

> miner.stop()

To retrieve the transaction details of the just sent transaction 0x56eb85db9905d2b6f33a832f1bae745b59dabc34c54db31346cffe453dec2910, execute the following command in the Javascript shell prompt:

> eth.getTransactionReceipt(vehicle_contract_inst.transactionHash)

The following would be the typical output:

Output.13

{
  blockHash: "0x2a4cd01691866665382342f80d8714ffa125691c65128ef8c06e41be65468499",
  blockNumber: 84,
  contractAddress: "0xfa332003301955dd8526f0ef3aa7c670bda5f4fa",
  cumulativeGasUsed: 206925,
  from: "0x46bf8994c8702919434271d89bcad8abec915612",
  gasUsed: 206925,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0x2d7fa49d64b631e3818ecad7813305f63cc9785ce99b3afe1d0120b02a9ad664",
  to: null,
  transactionHash: "0x56eb85db9905d2b6f33a832f1bae745b59dabc34c54db31346cffe453dec2910",
  transactionIndex: 0
}

The presence of a value for the contractAddress indicates that the contract has been successfully deployed to our private Blockchain network.

To check the bytecode of the just deployed contract 0xfa332003301955dd8526f0ef3aa7c670bda5f4fa, execute the following command in the Javascript shell prompt:

> eth.getCode(eth.getTransactionReceipt(vehicle_contract_inst.transactionHash).contractAddress)

The following would be the typical output:

Output.14

"0x6060604052600436106100565763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663683c8074811461005b5780636c41597a14610089578063893d20e8146100ae575b600080fd5b341561006657600080fd5b61008773ffffffffffffffffffffffffffffffffffffffff600435166100ea565b005b341561009457600080fd5b61009c610147565b60405190815260200160405180910390f35b34156100b957600080fd5b6100c161014d565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6001543373ffffffffffffffffffffffffffffffffffffffff90811691161415610144576001805473ffffffffffffffffffffffffffffffffffffffff191673ffffffffffffffffffffffffffffffffffffffff83161790555b50565b60005490565b60015473ffffffffffffffffffffffffffffffffffffffff16905600a165627a7a72305820ead3ff4e0d30a244745dab2015896c6d3ddcbd2ba949323e6386ca18620d7a960029"

The last step is to create an instance of the Vehicle contract that was just deployed to our private Blockchain, so we can invoke the contract function(s). To create a instance of the Vehicle contract, we need to invoke the at method on the contract object vehicle_contract, passing in the value of contractAddress as the argument. Execute the following command in the Javascript shell prompt:

> var vehicle_inst = vehicle_contract.at(eth.getTransactionReceipt(vehicle_contract_inst.transactionHash).contractAddress)

The following would be the typical output:

Output.15

undefined

To check the value of the contract instance variable vehicle_inst, execute the following command in the Javascript shell prompt:

> vehicle_inst

The following would be the typical output:

Output.16

{
  abi: [{
      constant: false,
      inputs: [{...}],
      name: "soldTo",
      outputs: [],
      payable: false,
      stateMutability: "nonpayable",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getVinNo",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getOwner",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}, {...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "constructor"
  }],
  address: "0xfa332003301955dd8526f0ef3aa7c670bda5f4fa",
  transactionHash: null,
  allEvents: function(),
  getOwner: function(),
  getVinNo: function(),
  soldTo: function()
}

To invoke the getOwner method on the contract instance vehicle_inst, execute the following command in the Javascript shell prompt:

> vehicle_inst.getOwner.call()

The following would be the typical output:

Output.17

"0x46bf8994c8702919434271d89bcad8abec915612"

Similarly, to invoke the getVinNo method, execute the following command in the Javascript shell prompt:

> vehicle_inst.getVinNo.call()

The following would be the typical output:

Output.18

1234567890

By using the call() method, the contract methods are executed locally on the connected Ethereum node without costing any gas. This also means that any changes made to the contract state (such as calling the soldTo method) will not be persisted or stored in our private Blockchain.

References

Introduction to Ethereum - Part 1

Official Solidity Documentation

Deploying A Smart Contract, The Hard Way