Introduction to Ethereum - Part 3


Bhaskar S 12/27/2017


Overview

In the previous article Part 2 of this series, we introduced basic concepts in and got our hands dirty with Solidity, the high-level Smart Contract programming language used by Ethereum.

In this article, we will build upon the concepts, from where we left off, by enhancing the Smart Contract used in the transfer of a vehicle from the dealer to the buyer.

Hands-on with Smart Contracts using Solidity

The following is the enhanced Solidity contract code named Vehicle2.sol located in the directory /home/polarsparc/Ethereum/src:

Vehicle2.sol
pragma solidity ^0.4.15;

/*
 * This AmountOwed contract implements a common function modifier to check the value of tranfer
 * satisfies the amount owed to dealer
 */

contract AmountOwed {
    // Modifiers can be used to change the behaviour of any function in a contract, such as checking
    // a condition prior to executing the function. Modifiers are inheritable properties of contracts
    // and may be overridden by derived contracts
    modifier validate(uint amt) {
        require(msg.value >= amt);
        _; // Function body
    }
}

/*
 * 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 Vehicle2 is AmountOwed {
    enum Deal { Open, Closed }
    
    uint _flag;
    uint _vin;
    uint _cost;
    address _owner;
    Deal _status;
    
    event Bought(uint vin, uint cost);
    
    function getFlag() public view returns (uint) {
        return _flag;
    }
    
    function getVin() public view returns (uint) {
        return _vin;
    }
    
    function getCost() public view returns (uint) {
        return _cost;
    }
    
    function getOwner() public view returns (address) {
        return _owner;
    }
    
    // The keyword 'payable' is important for accepting ethers from the buyer
    function buyVehicle() public payable validate(_cost) {
        _flag = 1;
        // Only the assigned owner can close the deal
        if (msg.sender == _owner) {
            _flag = 2;
            _status = Deal.Closed;
            Bought(_vin, _cost);
        }
    }
    
    function Vehicle2(uint vin, uint cost, address buyer) public {
        _flag = 0;
        _vin = vin;
        _cost = cost;
        _owner = buyer;
        _status = Deal.Open;
    }
}

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

A single contract file (with .sol extension) can have multiple contract definitions (AmountOwed and Vehicle2) as shown above.

In addition, one contract definition can inherit from another contract definition. The contract Vehicle2 inherits from AmountOwed in our example above.

The keyword modifier is used to alter the behavior of other functions using it. Think of the modifier as a decorator. It is often used for checking some condition(s) before executing a function. In our use-case, we are checking if the value transferred through a sendTransaction message has the desired amount.

The global built-in variable msg.value represents the value sent through the sendTransaction message.

The method require(expr) is a built-in function that checks for the specified condition expr to be true. If the specified expr evaluates to false, then an exception is thrown and undoes any state changes.

The expression _ (underscore) represents the body of the decorated function.

The keyword enum defines an enum just like in any other high-level programming language with 2 values Open and Closed. When the contract is created by the dealer, it is in the Open state. Once the buyer makes the specified payment, the contract status changes to Closed.

The keyword event defines a signal with some desired arguments, that can be emitted from a function and is stored in Ethereum transaction logs (a special structure in the Blockchain). Events are typically used for notifying applications on conditions. One can also use an event for debugging purposes.

The keyword payable indicates that the function it is defined on can receive ethers while being invoked. Without this keyword, sending some cryptocurrency during a function invocation will throw an exception.

An instance of the contract Vehicle2 will be deployed by the dealer such that the buyer can transfer ethers to fulfill the cost of the vehicle while invoking the method buyVehicle(), thus closing the deal.

For convenience, we have created a custom Javascript utility script with some helper variables and a function to extract and display information on account balances. The following is the custom Javascript script called UtilScripts.js located in the directory /home/polarsparc/Ethereum/bin:

UtilScripts.js
var bank = "0xef17ec5df3116dea3b7abaf1ff3045639453cc76";
var buyer = "0x35ddac855e0029676f489dafca9ab405a348317c";
var dealer = "0x46bf8994c8702919434271d89bcad8abec915612";
var dmv = "0x518a6377a3863201aef3310da41f3448d959a310";

var vin = 1234567890
var cost = 1000000000000000000
var gas_price = 1000000;

function showBalances() {
  var i = 0;
  eth.accounts.forEach(function(e) {
     console.log("---> eth.accounts["+i+"]: " + e + " \tbalance: " + web3.fromWei(eth.getBalance(e), "ether") + " ether");
     i++;
  })
};

To load the custom Javascript file UtilScripts.js from above, execute the following command in the geth Javascript shell prompt:

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

The following would be the typical output:

Output.1

true

To compile Vehicle2.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 vehicle2=`solc --optimize --combined-json abi,bin,interface src/Vehicle2.sol`" > bin/Vehicle2.js

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

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

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

The following would be the typical output:

Output.2

true

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

> vehicle2

The following would be the typical output:

Output.3

{
  contracts: {
    src/Vehicle2.sol:AmountOwed: {
      abi: "[]",
      bin: "60606040523415600e57600080fd5b603580601b6000396000f3006060604052600080fd00a165627a7a723058204730712ec07ff26de3760fde858ce558dc3435a508c0091cac2c22412f47661d0029"
    },
    src/Vehicle2.sol:Vehicle2: {
      abi: "[{\"constant\":true,\"inputs\":[],\"name\":\"getOwner\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"buyVehicle\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getCost\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getVin\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getFlag\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"vin\",\"type\":\"uint256\"},{\"name\":\"cost\",\"type\":\"uint256\"},{\"name\":\"buyer\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"vin\",\"type\":\"uint256\"},{\"indexed\":false,\"name\":\"cost\",\"type\":\"uint256\"}],\"name\":\"Bought\",\"type\":\"event\"}]",
      bin: "6060604052341561000f57600080fd5b6040516060806102958339810160405280805191906020018051919060200180516000808055600195909555600293909355505060038054600160a060020a031916600160a060020a039092169190911760a060020a60ff021916905561021990819061007c90396000f30060606040526004361061006c5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663893d20e88114610071578063a4e72902146100ad578063bd3e19d4146100b7578063bf20f940146100dc578063f9633930146100ef575b600080fd5b341561007c57600080fd5b610084610102565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100b561011e565b005b34156100c257600080fd5b6100ca6101db565b60405190815260200160405180910390f35b34156100e757600080fd5b6100ca6101e1565b34156100fa57600080fd5b6100ca6101e7565b60035473ffffffffffffffffffffffffffffffffffffffff1690565b600254348190101561012f57600080fd5b60016000556003543373ffffffffffffffffffffffffffffffffffffffff908116911614156101d8576002600055600380546001919074ff00000000000000000000000000000000000000001916740100000000000000000000000000000000000000008302179055507f3ccb2ab6980b218b1dd4974b07365cd90a191e170c611da46262fecc208bd66160015460025460405191825260208201526040908101905180910390a15b50565b60025490565b60015490565b600054905600a165627a7a723058206bddd2f4e42cc80921d64b69c8c1953bef9faef537685d6ecbf6b67746db57100029"
    }
  },
  version: "0.4.19+commit.c4cbbb05.Linux.g++"
}

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

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

> var vehicle2_contract = eth.contract(JSON.parse(vehicle2.contracts['src/Vehicle2.sol:Vehicle2'].abi))

The following would be the typical output:

Output.4

undefined

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

> vehicle2_contract

The following would be the typical output:

Output.5

{
  abi: [{
      constant: true,
      inputs: [],
      name: "getOwner",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: false,
      inputs: [],
      name: "buyVehicle",
      outputs: [],
      payable: true,
      stateMutability: "payable",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getCost",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getVin",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getFlag",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}, {...}, {...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "constructor"
  }, {
      anonymous: false,
      inputs: [{...}, {...}],
      name: "Bought",
      type: "event"
  }],
  eth: {
    accounts: ["0xef17ec5df3116dea3b7abaf1ff3045639453cc76", "0x35ddac855e0029676f489dafca9ab405a348317c", "0x46bf8994c8702919434271d89bcad8abec915612", "0x518a6377a3863201aef3310da41f3448d959a310"],
    blockNumber: 0,
    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 a variable called vehicle2_contract_txn with a value representing 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 statement in the Javascript shell as shown below:

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

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

> vehicle2_contract_txn

The following would be the typical output:

Output.6

{
  data: "0x6060604052341561000f57600080fd5b6040516060806102958339810160405280805191906020018051919060200180516000808055600195909555600293909355505060038054600160a060020a031916600160a060020a039092169190911760a060020a60ff021916905561021990819061007c90396000f30060606040526004361061006c5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663893d20e88114610071578063a4e72902146100ad578063bd3e19d4146100b7578063bf20f940146100dc578063f9633930146100ef575b600080fd5b341561007c57600080fd5b610084610102565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100b561011e565b005b34156100c257600080fd5b6100ca6101db565b60405190815260200160405180910390f35b34156100e757600080fd5b6100ca6101e1565b34156100fa57600080fd5b6100ca6101e7565b60035473ffffffffffffffffffffffffffffffffffffffff1690565b600254348190101561012f57600080fd5b60016000556003543373ffffffffffffffffffffffffffffffffffffffff908116911614156101d8576002600055600380546001919074ff00000000000000000000000000000000000000001916740100000000000000000000000000000000000000008302179055507f3ccb2ab6980b218b1dd4974b07365cd90a191e170c611da46262fecc208bd66160015460025460405191825260208201526040908101905180910390a15b50565b60025490565b60015490565b600054905600a165627a7a723058206bddd2f4e42cc80921d64b69c8c1953bef9faef537685d6ecbf6b67746db57100029",
  from: "0x46bf8994c8702919434271d89bcad8abec915612",
  gas: 1000000
}

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.7

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 vehicle2_contract, passing in the required arguments. Execute the following command in the Javascript shell prompt:

> var vehicle2_contract_inst = vehicle2_contract.new(vin, cost, buyer, vehicle2_contract_txn)

The following would be the typical output:

Output.8

undefined

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

> vehicle2_contract_inst

The following would be the typical output:

Output.9

{
  abi: [{
      constant: true,
      inputs: [],
      name: "getOwner",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: false,
      inputs: [],
      name: "buyVehicle",
      outputs: [],
      payable: true,
      stateMutability: "payable",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getCost",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getVin",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getFlag",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}, {...}, {...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "constructor"
  }, {
      anonymous: false,
      inputs: [{...}, {...}],
      name: "Bought",
      type: "event"
  }],
  address: undefined,
  transactionHash: "0x95e7e420b4a4dcd522a36379b4227a6c2b0604f97cb5b7db973c436109a2230f"
}

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.9, we see the transactionHash for the contract deployment transaction.

To check all the pending transactions, execute the following command in the Javascript shell prompt:

> eth.pendingTransactions

The following would be the typical output:

Output.10

[{
    blockHash: null,
    blockNumber: null,
    from: "0x46bf8994c8702919434271d89bcad8abec915612",
    gas: 1000000,
    gasPrice: 18000000000,
    hash: "0x95e7e420b4a4dcd522a36379b4227a6c2b0604f97cb5b7db973c436109a2230f",
    input: "0x6060604052341561000f57600080fd5b6040516060806102958339810160405280805191906020018051919060200180516000808055600195909555600293909355505060038054600160a060020a031916600160a060020a039092169190911760a060020a60ff021916905561021990819061007c90396000f30060606040526004361061006c5763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663893d20e88114610071578063a4e72902146100ad578063bd3e19d4146100b7578063bf20f940146100dc578063f9633930146100ef575b600080fd5b341561007c57600080fd5b610084610102565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b6100b561011e565b005b34156100c257600080fd5b6100ca6101db565b60405190815260200160405180910390f35b34156100e757600080fd5b6100ca6101e1565b34156100fa57600080fd5b6100ca6101e7565b60035473ffffffffffffffffffffffffffffffffffffffff1690565b600254348190101561012f57600080fd5b60016000556003543373ffffffffffffffffffffffffffffffffffffffff908116911614156101d8576002600055600380546001919074ff00000000000000000000000000000000000000001916740100000000000000000000000000000000000000008302179055507f3ccb2ab6980b218b1dd4974b07365cd90a191e170c611da46262fecc208bd66160015460025460405191825260208201526040908101905180910390a15b50565b60025490565b60015490565b600054905600a165627a7a723058206bddd2f4e42cc80921d64b69c8c1953bef9faef537685d6ecbf6b67746db5710002900000000000000000000000000000000000000000000000000000000499602d20000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000035ddac855e0029676f489dafca9ab405a348317c",
    nonce: 0,
    r: "0xd8c6112d4c2f14e68e4f19c5b8bef6e9155b1a5781d2432c6e44d1851c7ef3fc",
    s: "0x6aa590f957a4b9c2b3072ea4a68bac903c063378eacfb904418f99897e111331",
    to: null,
    transactionIndex: 0,
    v: "0x4d",
    value: 0
}]

Before we start the miner, let us check the account balances. To display account balances using the Javascript utility function showBalances, execute the following command in the Javascript shell prompt:

> showBalances()

The following would be the typical output:

Output.11

---> eth.accounts[0]: 0xef17ec5df3116dea3b7abaf1ff3045639453cc76  balance: 20 ether
---> eth.accounts[1]: 0x35ddac855e0029676f489dafca9ab405a348317c  balance: 10 ether
---> eth.accounts[2]: 0x46bf8994c8702919434271d89bcad8abec915612  balance: 5 ether
---> eth.accounts[3]: 0x518a6377a3863201aef3310da41f3448d959a310  balance: 3 ether
undefined

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.

Let us stop the miner. Execute the following command in the Javascript shell prompt:

> miner.stop()

To retrieve the transaction details for 0x95e7e420b4a4dcd522a36379b4227a6c2b0604f97cb5b7db973c436109a2230f, execute the following command in the Javascript shell prompt:

> eth.getTransactionReceipt(vehicle2_contract_inst.transactionHash)

The following would be the typical output:

Output.12

{
  blockHash: "0x71ac9ad00dda0064b70a8300ef6669502d85ae6bc32712035b78ad1fa5ded675",
  blockNumber: 1,
  contractAddress: "0xfa332003301955dd8526f0ef3aa7c670bda5f4fa",
  cumulativeGasUsed: 266798,
  from: "0x46bf8994c8702919434271d89bcad8abec915612",
  gasUsed: 266798,
  logs: [],
  logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0x5ca6bef8e4b49e1702ad084365c74aa1e36d801526b8a40873dcca03df4d8506",
  to: null,
  transactionHash: "0x95e7e420b4a4dcd522a36379b4227a6c2b0604f97cb5b7db973c436109a2230f",
  transactionIndex: 0
}

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

Next, we will define a variable called vehicle2_contract_addr with a value containing the deployed contract address. Execute the following statement in the Javascript shell as shown below:

> var vehicle2_contract_addr = eth.getTransactionReceipt(vehicle2_contract_inst.transactionHash).contractAddress

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

> vehicle2_contract_addr

The following would be the typical output:

Output.13

"0xfa332003301955dd8526f0ef3aa7c670bda5f4fa"

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

> var vehicle2_obj = vehicle2_contract.at(vehicle2_contract_addr)

The following would be the typical output:

Output.14

undefined

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

> vehicle2_obj

The following would be the typical output:

Output.15

{
  abi: [{
      constant: true,
      inputs: [],
      name: "getOwner",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: false,
      inputs: [],
      name: "buyVehicle",
      outputs: [],
      payable: true,
      stateMutability: "payable",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getCost",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getVin",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      constant: true,
      inputs: [],
      name: "getFlag",
      outputs: [{...}],
      payable: false,
      stateMutability: "view",
      type: "function"
  }, {
      inputs: [{...}, {...}, {...}],
      payable: false,
      stateMutability: "nonpayable",
      type: "constructor"
  }, {
      anonymous: false,
      inputs: [{...}, {...}],
      name: "Bought",
      type: "event"
  }],
  address: "0xfa332003301955dd8526f0ef3aa7c670bda5f4fa",
  transactionHash: null,
  Bought: function(),
  allEvents: function(),
  buyVehicle: function(),
  getCost: function(),
  getFlag: function(),
  getOwner: function(),
  getVin: function()
}

Once again, let us display account balances using the Javascript utility function showBalances. Execute the following command in the Javascript shell prompt:

> showBalances()

The following would be the typical output:

Output.16

---> eth.accounts[0]: 0xef17ec5df3116dea3b7abaf1ff3045639453cc76   balance: 40.004802364 ether
---> eth.accounts[1]: 0x35ddac855e0029676f489dafca9ab405a348317c  balance: 10 ether
---> eth.accounts[2]: 0x46bf8994c8702919434271d89bcad8abec915612  balance: 4.995197636 ether
---> eth.accounts[3]: 0x518a6377a3863201aef3310da41f3448d959a310  balance: 3 ether
undefined

Since the dealer deployed the contract Vehicle2 to our private Blockchain, as expected, the dealer account incurred a small processing fees in the form of gas.

The buyer will invoke the buyVehicle method on the object vehicle2_obj by sending a transaction message, along with the payment covering the cost of the vehicle.

We will define a variable called buyer_txn with a value representing the payment and method invocation transaction object that encapsulates the address of the buyer (from), the cost (value), and the gas price. Execute the following statement in the Javascript shell as shown below:

> var buyer_txn = { from: buyer, value: cost, gas: gas_price }

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

> buyer_txn

The following would be the typical output:

Output.17

{
  from: "0x35ddac855e0029676f489dafca9ab405a348317c",
  gas: 1000000,
  value: 1000000000000000000
}

Since the buyer is initiating the transaction, we need to unlock the buyer account before proceeding further.

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

> personal.unlockAccount(buyer)

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

Output.18

Unlock account 0x35ddac855e0029676f489dafca9ab405a348317c
Passphrase: buyer
true

The buyer will invoke the contract by calling the sendTransaction method on the object vehicle2_obj.buyVehicle. Execute the following command in the Javascript shell prompt:

> var buyer_txn_hash = vehicle2_obj.buyVehicle.sendTransaction(buyer_txn)

The following would be the typical output:

Output.19

undefined

To check the value of the transaction hash variable buyer_txn_hash, execute the following command in the Javascript shell prompt:

> buyer_txn_hash

The following would be the typical output:

Output.20

"0x2a9acb27c5406dfd3b4be6d456cedf772d0cd6656b0d05d62ce51dfeb87f3567"

The transaction created by the buyer above needs to be mined for the method invocation on the deployed contract on our private Blockchain network.

To check all the pending transactions, execute the following command in the Javascript shell prompt:

> eth.pendingTransactions

The following would be the typical output:

Output.21

[{
    blockHash: null,
    blockNumber: null,
    from: "0x35ddac855e0029676f489dafca9ab405a348317c",
    gas: 1000000,
    gasPrice: 18000000000,
    hash: "0x2a9acb27c5406dfd3b4be6d456cedf772d0cd6656b0d05d62ce51dfeb87f3567",
    input: "0xa4e72902",
    nonce: 0,
    r: "0x1871d12481d3689cc036eec06c39592eb563215a97bee537089cb5c73728ebe8",
    s: "0x4bce1bb99250da899eb1b88043990326d818439d6712a96ef7e31b20ac9ee87b",
    to: "0xfa332003301955dd8526f0ef3aa7c670bda5f4fa",
    transactionIndex: 0,
    v: "0x4d",
    value: 1000000000000000000
}]

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 invocation transaction will be mined and the contract method vehicle2_obj.buyVehicle will be invoked on deployed contract.

Let us stop the miner. Execute the following command in the Javascript shell prompt:

> miner.stop()

To retrieve the transaction details for 0x2a9acb27c5406dfd3b4be6d456cedf772d0cd6656b0d05d62ce51dfeb87f3567, execute the following command in the Javascript shell prompt:

> eth.getTransactionReceipt(buyer_txn_hash)

The following would be the typical output:

Output.22

{
  blockHash: "0xc88bc4af7fcf9ac9366866f987be3694fab14ed259f68c776830644c5d2c961b",
  blockNumber: 7,
  contractAddress: null,
  cumulativeGasUsed: 53865,
  from: "0x35ddac855e0029676f489dafca9ab405a348317c",
  gasUsed: 53865,
  logs: [{
      address: "0xfa332003301955dd8526f0ef3aa7c670bda5f4fa",
      blockHash: "0xc88bc4af7fcf9ac9366866f987be3694fab14ed259f68c776830644c5d2c961b",
      blockNumber: 7,
      data: "0x00000000000000000000000000000000000000000000000000000000499602d20000000000000000000000000000000000000000000000000de0b6b3a7640000",
      logIndex: 0,
      removed: false,
      topics: ["0x3ccb2ab6980b218b1dd4974b07365cd90a191e170c611da46262fecc208bd661"],
      transactionHash: "0x2a9acb27c5406dfd3b4be6d456cedf772d0cd6656b0d05d62ce51dfeb87f3567",
      transactionIndex: 0
  }],
  logsBloom: "0x00000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  root: "0xf007b6666df14298ecebf584fb2069dac2c1353fafe82c3c09adadbcffcc2c8b",
  to: "0xfa332003301955dd8526f0ef3aa7c670bda5f4fa",
  transactionHash: "0x2a9acb27c5406dfd3b4be6d456cedf772d0cd6656b0d05d62ce51dfeb87f3567",
  transactionIndex: 0
}

How do we know the method invocation of buyVehicle() by the buyer succeeded ???

One can use the eth.getStorageAt(contactAddress, position) command in the Javascript shell to check for the current contract state values. The contract state is persisted in the Blockchain storage, which is essentially a key-value store. For example, value for the state variable _flag is at position 0, value for the state variable _vin is at position 1, and so on.

To check the state value for _flag in the storage (which is a decimal), execute the following command in the Javascript shell prompt:

> web3.toDecimal(eth.getStorageAt(vehicle2_contract_addr, 0))

The following would be the typical output:

Output.23

2

The above value of 2 for the state variable _flag is possible only on the correct execution of the method buyVehicle.

To check the state value for _vin in the storage (which is a decimal), execute the following command in the Javascript shell prompt:

> web3.toDecimal(eth.getStorageAt(vehicle2_contract_addr, 1))

The following would be the typical output:

Output.24

1234567890

To check the state value for _cost in the storage (which is a decimal), execute the following command in the Javascript shell prompt:

> web3.toDecimal(eth.getStorageAt(vehicle2_contract_addr, 2))

The following would be the typical output:

Output.25

1000000000000000000

To check the state value for _owner in the storage (which is a hex), execute the following command in the Javascript shell prompt:

> web3.toHex(eth.getStorageAt(vehicle2_contract_addr, 3))

The following would be the typical output:

Output.26

"0x00000000000000000000000135ddac855e0029676f489dafca9ab405a348317c"

One can also look for the emitted event(s) Bought from the transaction log. To display the event details, we first need to create an events filter. Then, we invoke the watch(func) command in the Javascript shell, specifying a callback function func to display the results.

To create a filter for event Bought, execute the following command in the Javascript shell prompt:

> var vehicle2_events = vehicle2_obj.Bought({}, {fromBlock: 0, toBlock: 'latest'});

We want to scan all the transaction log(s) for all the mined blocks, and hence the fromBlock of 0 to the toBlock of latest.

To start the display of event(s) from the transaction log(s), execute the following command in the Javascript shell prompt:

> var dummy = vehicle2_events.watch(function (error, result) { console.log("=> : " + JSON.stringify(result)); });

The following would be the typical output:

Output.27

=> : {"address":"0xfa332003301955dd8526f0ef3aa7c670bda5f4fa","args":{"cost":"1000000000000000000","vin":"1234567890"},"blockHash":"0xb8e701ba79b273b1102a03fcbcdf606b517750283da37119adc0ebf00669c2de","blockNumber":5,"event":"Bought","logIndex":0,"removed":false,"transactionHash":"0x2a9acb27c5406dfd3b4be6d456cedf772d0cd6656b0d05d62ce51dfeb87f3567","transactionIndex":0}
undefined

From the above Output.27, we see the event values "args":{"cost":"1000000000000000000","vin":"1234567890"}.

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

> vehicle2_events.stopWatching()

References

Introduction to Ethereum - Part 2