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:
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:
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:
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:
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:
{ 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:
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:
{ 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:
{ 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:
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:
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:
{ 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:
[{ 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:
---> 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:
{ 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:
"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:
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:
{ 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:
---> 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:
{ 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:
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:
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:
"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:
[{ 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:
{ 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:
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:
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:
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:
"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:
=> : {"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