In the second part of our Ethereum programming tutorial we will set up a private Ethereum development network, and implement our first smart contract.
This tutorial is based on a geth version later than 1.6, namely 1.7.2. What makes worth mentioning it is the fact that in version 1.6 the inline Solidity compiler support was removed from geth. For whatever reason. But by the time of writing these lines (end of 2017) there is no ramp-up tutorial to be found out there which reflects this fact. Even the official Ethereum "Hello world" tutorial still refers to the Solidity compiler being included with geth!
But no worry: I'll do that for you! Here comes the first rookie walkthrough for creating, compiling, deploying, and running a Solidity Ethereum contract utilizing the command line Solidity compiler!
1. Setup the private Ethereum Development Node
First create a new data directory for your private blockchain. We do this right beneath our home directory:
$ mkdir ~/privatechain
Then start a geth development network pointing to this data directory:
$ geth --rpc --rpcaddr 127.0.0.1 --rpcport 8545 --dev --datadir ~/privatechain
If everything went right the last terminal output should read something like:
IPC endpoint opened: /Users/as/privatechain/geth.ipc
HTTP endpoint opened: http://127.0.0.1:8545
But what do these options mean:
- rpc: Enable remote procedure calls via http on this geth instance, so we can connect to it from another node (i.e. terminal window)
- rpcaddr: The IP address where RPC shall be accessible. In this case it's the local host since we are on the same machine.
- rpcport: The port to access RPC. As 8545 is the standard port, we also could have left out this option.
- dev: This flag creates a development network, so we do not connect to the "real" Ethereum network where we would have to spend real Ether (meaning real money) to execute our contracts. It also conveniently preconfigures the first block (the Genesis) of our network. We will cover creating our own Genesis Block in a later tutorial.
- datadir: Guess what? It points to our private chain's data directory just created!
2. Connect a geth console to the Development Node
You will have recognized that our running geth node is quite busy with its own affairs. It's not being impressed by typing commands into its terminal window. Not even by poems! So we have to get in contact:
Open another macOS terminal window. I'd suggest using a different color for it so you never mix up the terminals later on. We will use the grass style terminal throughout this tutorial - as it comes preconfigured with macOS - to reference the remote command line interface (CLI) geth console.
So just execute this in the new console window replacing the "as" with your user name:
$ geth attach ipc://Users/as/privatechain/geth.ipc
But what about the "ipc" thing when we where talking about "rpc" earlier? Just that simple: IPC or Inter Process Communication can be used when separate processes need to interact on the same machine while RPC must be used when the processes run on different machines.
3. Create the first account
Now we have to create an external account on our Ethereum network. An account enables us to perform transactions on the network (i.e. make use of it). To do so we utilize geth's Management API:
> personal.newAccount('password')
'password' literarily is the password here. So feel free to use your own! This command will output the address of the account created. It's a good idea to write it down somewhere!
Now check the account really exists:
> personal.listAccounts
This should output an array containing the account just created. So in my case it's:
["0x839d4ed149062e6e2e7ab772167f366282c600ce"]
This first account automatically is set as the coinbase in our network. This is where all the mining rewards will got to. You can check it using the web3 API:
> eth.coinbase
This should output the same account just created.
4. Create the Contract Source Code
Now it's time to write our first Ethereum contract definition. If you are familiar with object oriented programming languages it helps to think of a contract definition as a class definition.
For better maintainability we will store the contract files in a separate directory. So just go ahead an create a folder ~/ethcontracts!
Right inside this folder create a new text file named MyFirstContract.sol. This is your first Solidity source code file! Feeling great?
Now paste this code into the file and save:
Now paste this code into the file and save:
pragma solidity ^0.4.8;
contract MyFirstContract {
function reflect(string yourself) public returns(string){
return yourself;
}
}
contract MyFirstContract {
function reflect(string yourself) public returns(string){
return yourself;
}
}
I think there isn't a detailed walkthrough required. You will have noticed that in the first line we define the smallest Solidity version supported by this contract. Then we create a contract named MyFirstContract which has one method that simply reflects its input.
But now comes the challenging part:
5. Compile the Contract
As told earlier in this tutoriel, calling the Solidity compiler right from the geth console has been removed from geth 1.6. So we have to compile our source file outside the running Ethereum network, and import it into it. In order to do so we need to have the Solidity compiler installed as explained in the first part of this tutorial.As we have two instances of macOS terminal already running, we will need a third one. Believe it or not! So please open another terminal instance. We will use the ocean theme to identify it in this tutorial.
First we'll do a test run to check if the Solidity compiler is working as expected. So please issue:
$ solc --optimize --combined-json abi,bin,interface ~/ethcontracts/MyFirstContract.sol
We should get something like this:
{"contracts":{"/Users/as/ethcontracts/MyFirstContract.sol:MyFirstContract":{"abi":"[{\"constant\":false,\"inputs\":[{\"name\":\"yourself\",\"type\":\"string\"}],\"name\":\"reflect\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]","bin":"6060604052341561000f57600080fd5b6101578061001e6000396000f3006060604052600436106100405763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663c1ce53fc8114610045575b600080fd5b341561005057600080fd5b61009660046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061010d95505050505050565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100d25780820151838201526020016100ba565b50505050905090810190601f1680156100ff5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610115610119565b5090565b602060405190810160405260008152905600a165627a7a723058207e8ac985f99f507869c23d1d1457c38e5aace7b1eafa9f31eff3e02d9aecfd450029"}},"version":"0.4.18+commit.9cf6e910.Darwin.appleclang"}
If there are some warnings ahead of this output we just can ignore them! The important thing to notice is that we have our contract source code compiled into an abi and a bin section.
Now let's use this for real!
In order to be able to deploy the compiled contract into our Ethereum dev network, we have to create a compiled file from the source code. We do it using good old terminal commands:
echo "var MyFirstContractCompiled=`solc --optimize --combined-json abi,bin,interface ~/ethcontracts/MyFirstContract.sol`" > ~/ethcontracts/MyFirstContract.js
What happens here is that we create an actual JavaScript file MyFirstContract.js where we assign the output JSON object of the Solidity compiler to a variable called MyFirstContractCompiled.
Now we're ready for the next step:
6. Import the contract
We want to get the precompiled contract from the compiled JavaScript file into our Ethereum node and prepare it for deployment to our development network.
So we return to our geth console and load the JavaScript file just compiled (Note: We assume that the geth console was started from your user's home directory. If not, you have to specify the absolute path to the MyFirstContract.js file):
> loadScript("./ethcontracts/MyFirstContract.js")
The resulting output should be:
true
So let's check if everything went right by outputting the value of the MyFirstContractCompiled variable:
> MyFirstContractCompiled
Should give you an output like this:
{
contracts: {
/Users/as/ethcontracts/MyFirstContract.sol:MyFirstContract: {
abi: "[{\"constant\":false,\"inputs\":[{\"name\":\"yourself\",\"type\":\"string\"}],\"name\":\"reflect\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
bin: "6060604052341561000f57600080fd5b6101578061001e6000396000f3006060604052600436106100405763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663c1ce53fc8114610045575b600080fd5b341561005057600080fd5b61009660046024813581810190830135806020601f8201819004810201604051908101604052818152929190602084018383808284375094965061010d95505050505050565b60405160208082528190810183818151815260200191508051906020019080838360005b838110156100d25780820151838201526020016100ba565b50505050905090810190601f1680156100ff5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b610115610119565b5090565b602060405190810160405260008152905600a165627a7a723058207e8ac985f99f507869c23d1d1457c38e5aace7b1eafa9f31eff3e02d9aecfd450029"
}
},
version: "0.4.18+commit.9cf6e910.Darwin.appleclang"
}
Now we have to create an actual contract object from the compiled contract definition, which we can instantiate on our Ethereum network later. To achieve this, we have to select the abi part of our MyFirstContract stored in the MyFirstContractCompiled variable and pass it to the web3.eth.contract function:
> MyContract = web3.eth.contract(JSON.parse(MyFirstContractCompiled.contracts["/Users/as/ethcontracts/MyFirstContract.sol:MyFirstContract"].abi))
Make sure to replace the "as" with your actual user name!
It is important to not forget the JSON.parse part! This will parse the string representation of our abi into an actual JavaScript object.
You should get an output like this:
{
abi: [{
constant: false,
inputs: [{...}],
name: "reflect",
outputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "function"
}],
eth: {
accounts: ["0x839d4ed149062e6e2e7ab772167f366282c600ce"],
blockNumber: 0,
coinbase: "0x839d4ed149062e6e2e7ab772167f366282c600ce",
compile: {
lll: function(),
serpent: function(),
solidity: function()
},
defaultAccount: undefined,
defaultBlock: "latest",
gasPrice: 0,
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()
}
As you know: There's no free lunch! Especially not on the Ethereum network. Every transaction has its cost. And contract deployment is a transaction! So we have to check first if we have enough Ether to actually do the deployment.
For convenience we define a neat variable pointing to our coinbase account (where all the mined ether goes to)..
..and check the funds:
If this returns 0, we have to mine some Ether:
This will start the mining process on our initial geth development node. Just check your first terminal window (the one that is black in this tutorial, but is likely to be white on your Mac).
Meanwhile, we want to know the expenses of deploying our contract. The deployment itself is a Ethereum transaction with the compiled binary contract data as payload. We can use the web3.eth.estimateGas function to simulate this transaction and estimate the gas required to execute it.
First we create a hex string from the bin section of MyFirstContractCompiled and store it in a variable for later use. This is done by suffixing the bin string with "0x":
Then we can estimate the costs of contract deployment:
This will output a number to which we will refer a little later when actually deploying the contract.
For now it's time to stop mining:
Prior to be able to deploy the contract we have to authorize (or unlock) our account with our password, so nobody else than you can spend your ether for this deployment:
And now we create the contract:
Supply at least as much gas as we estimated a few steps earlier!
You should get an output like this:
{
abi: [{
constant: false,
inputs: [{...}],
name: "reflect",
outputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "function"
}],
address: undefined,
transactionHash: "0x42878f04878dd33dbb6969d72ff48385ed2c050e867def4b2b1c3536d8ec9f85"
}
Now our contract is deployed to the Ethereum development network. But it's not alive yet: Its address is still undefined!
After a few seconds check the contract instance again:
It should have an address set now! So our contract is alive and we can test it.
But first let's stop mining:
Then we call the reflect method of our contract:
And voilĂ : Your contract tells you that it is alive!
If you wonder why we had to add call to the actual method name, you will find the answer here.
Congratulations! You just implemented your first Ethereum contract!
It is important to not forget the JSON.parse part! This will parse the string representation of our abi into an actual JavaScript object.
You should get an output like this:
{
abi: [{
constant: false,
inputs: [{...}],
name: "reflect",
outputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "function"
}],
eth: {
accounts: ["0x839d4ed149062e6e2e7ab772167f366282c600ce"],
blockNumber: 0,
coinbase: "0x839d4ed149062e6e2e7ab772167f366282c600ce",
compile: {
lll: function(),
serpent: function(),
solidity: function()
},
defaultAccount: undefined,
defaultBlock: "latest",
gasPrice: 0,
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()
}
7. Deploy the contract
Now that we have our MyContract object, we want to deploy it to our Ethereum development network.As you know: There's no free lunch! Especially not on the Ethereum network. Every transaction has its cost. And contract deployment is a transaction! So we have to check first if we have enough Ether to actually do the deployment.
For convenience we define a neat variable pointing to our coinbase account (where all the mined ether goes to)..
> MyAccount = eth.coinbase
..and check the funds:
> eth.getBalance(MyAccount)
If this returns 0, we have to mine some Ether:
> miner.start()
This will start the mining process on our initial geth development node. Just check your first terminal window (the one that is black in this tutorial, but is likely to be white on your Mac).
Meanwhile, we want to know the expenses of deploying our contract. The deployment itself is a Ethereum transaction with the compiled binary contract data as payload. We can use the web3.eth.estimateGas function to simulate this transaction and estimate the gas required to execute it.
First we create a hex string from the bin section of MyFirstContractCompiled and store it in a variable for later use. This is done by suffixing the bin string with "0x":
> MyContractBin = "0x" + MyFirstContractCompiled.contracts["/Users/as/ethcontracts/MyFirstContract.sol:MyFirstContract"].bin
Then we can estimate the costs of contract deployment:
> eth.estimateGas({data: MyContractBin })
This will output a number to which we will refer a little later when actually deploying the contract.
For now it's time to stop mining:
> miner.stop()
Prior to be able to deploy the contract we have to authorize (or unlock) our account with our password, so nobody else than you can spend your ether for this deployment:
> personal.unlockAccount(MyAccount, "password")
And now we create the contract:
> MyContractInstance = MyContract.new({data: MyContractBin gas: 143940, from: MyAccount})
Supply at least as much gas as we estimated a few steps earlier!
You should get an output like this:
{
abi: [{
constant: false,
inputs: [{...}],
name: "reflect",
outputs: [{...}],
payable: false,
stateMutability: "nonpayable",
type: "function"
}],
address: undefined,
transactionHash: "0x42878f04878dd33dbb6969d72ff48385ed2c050e867def4b2b1c3536d8ec9f85"
}
8. Activate and test the Contract
What we've done in the step before is telling the Ethereum network that we want to execute a transaction which creates our contract as an executable unit of code in the network. Now it's up to the miners to decide when and where this transaction will be executed. In real life they would take this decision based on the amount of gas we provided. But since we are in the test net, and we currently have only one miner, our transaction will be executed anyway! So let's start mining again:
> miner.start()
After a few seconds check the contract instance again:
> MyContractInstance
It should have an address set now! So our contract is alive and we can test it.
But first let's stop mining:
> miner.stop()
Then we call the reflect method of our contract:
> MyContractInstance.reflect.call("I'm alive!")
And voilĂ : Your contract tells you that it is alive!
If you wonder why we had to add call to the actual method name, you will find the answer here.
Congratulations! You just implemented your first Ethereum contract!
i and my folllowing your blogs regularly,thanks for such a nice blog Blockchain Online Training Bangalore
ReplyDeleteVery useful info. Hope to see more posts soon!. creating smart contract
ReplyDeleteThe specialists are endeavoring to utilize it for more than one goals and these days, the most noticeable and conspicuous utilization of the Blockchain innovation is Bitcoin.Lucrotrade
ReplyDeleteI thought protecting the website from the hackers is a hectic task. This post makes it easy for the developers and business people to protect the website. Keep sharing posts like this…
ReplyDeleteHire Wordpress Developer
Hire Opencart Developer
Hire Php Programmer
Hire Web Developer
Hire wordpress developer India
Thank you for sharing your info. tutuapp
ReplyDeleteit was a wonderful chance to visit this kind of site and I am happy to know. thank you so much for giving us a chance to have this opportunity.. estilo de vida
ReplyDeleteEverything shared here is amazing and i would like to share this article with public. I will recommend your article. I am glad to tell everyone that we can now Hire Laravel Developer for betterment and growth of our business. I'll visit here again for more updates. Thank You!
ReplyDeleteThanks for sharing https://cutt.ly/grOAGH1
ReplyDeleteI think this is an informative post and it is very useful and knowledgeable. therefore, I would like to thank you for the efforts you have made in writing this article.
ReplyDeleteDigital Marketing Training in Chennai
Digital Marketing Course in Chennai
Great blog and an interesting post which you have shared here. I was looking for this type of interesting post. I totally agreed with this post, and I also tell my friends about this post. Thanks for this post. innosilicon a11
ReplyDeleteHigh profitability Antminer Z15 crypto Miner machine.
ReplyDeleteProfitable miner Antminer L7 you dont want to miss out caus crypto is the future
ReplyDeleteAs we have two instances of macOS terminal already running, we will need a third one. Believe it or not! So please open another terminal instance. We will use the ocean theme to identify it in this tutorial.
ReplyDeleteOpen another macOS terminal window. I'd suggest using a different color for it so you never mix up the terminals later on. We will use the grass style terminal throughout this tutorial - as it comes preconfigured with macOS - to reference the remote command line interface (CLI) geth console.
ReplyDeleteI think this is an informative post and it is very useful and knowledgeable. krnl.fun
ReplyDeletehdstreamz apk