This is a short guide showing the essential components of Ethereum and its Smart Contracts, with some sample code.
To make things more comprehensive, it is broken down into 3 blocks:
- Geth client
- Contracts
- UI
geth
is the the command line interface for running a full ethereum node implemented in Go.
You can find a general reference for Geth here.
Download and install the geth client.
To initialize a custom node you will need a genesis.json
file, which you can find here.
And then run geth --datadir=./datadir init genesis.json
A folder called datadir
will be generated, which will be used as kind of a DB for the blockchain.
In order to make any interactions, you will need some accounts. To create one, run:
geth --datadir=./datadir account new
The account will be saved in ./datadir/keystore
.
The contents of this folder are totally confidential and should not be shared.
Note that accounts are created offline. This address remains unknown to the network until it is part of a transaction.
geth --datadir=./datadir account list
geth --datadir=./datadir console
Account:
eth.accounts
eth.getBalance('accAddress')
personal.newAccount('pwdForAccount')
personal.unlockAccount('account', 'pwd')
personal.unlockAccount('account', 'pwd', 60*60*24)
(unlock for 24 hours)
Transactions (unlock account first):
eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[1], value: web3.toWei(1, 'ether')})
(send 1 ether from account 0 to account 1)eth.getTransaction('transactionHash')
(get transaction details)debug.traceTransaction('transactionHash')
(for debugging a transaction)- Deploy contract:
eth.sendTransaction(
{
from: eth.accounts[0],
data: "0x" + contractCode, // contractCode = binary code
gas: 1000000
},
function(err, tx) {
console.log(err, tx) // tx = transaction
}
)
// the output contract=xxx is the address of the contract
// SAVE it for any further interactions with the contract
// if eth.getCode(contractAddress) !== '0x', then it has already been mined
Mining & General:
miner.start(numberOfThreads)
/miner.stop()
eth.blockNumber
eth.getBlock('blockHash')
(get info about specific block)web3.fromWei(amountOfWei, 'targetUnit')
(converts wei to ether)web3.toWei(amountOfUnit, 'initialUnit')
(e.g. (1, 'ether'))eth.getCode(contractAddress)
(get contract)loadScript('./path-to-script')
Contract Methods:
- For getters:
myContract.myMethod(...params)
- For setters:
myContract.myMethod(...params, {from: 'address'})
If we want to enable access to the node via RPC from e.g. our browser using Web3, then run:
geth --datadir=./datadir --nodiscover --rpc --rpcapi "db,personal,eth,net,web3,debug" --rpccorsdomain="*" --rpcaddr="localhost" --rpcport 8545 console
UI: You will set the HttpProvider on the web3 instance to use the URL specified above.
geth --datadir=./datadir --nodiscover --rpc --rpcapi "db,personal,eth,net,web3,debug" --rpccorsdomain="*" --rpcaddr="localhost" --rpcport 8545 --ws --wsapi "db,personal,eth,net,web3,debug" --wsorigins="*" --wsaddr="localhost" --wsport 8546 console
Smart contracts run on the EVM (Ethereum Virtual Machine).
EVM is an assembly-like programming environment.
We write contracts in the Solidity language and those will be compiled down to binary code, which will be deployed to the network.
Every single node on the network will run this code in order to verify its correctness.
Further, contracts will only run in response to a transaction. So they are reactive.
To run our contract(s) on the network has a cost: gas.
The EVM runs byte-code operations, called opcodes
. Each type of opcode has a different price.
The cost of the opcodes is always fixed. The total gas equals the total cost of opcodes.
The gas is then paid with ether. The price of gas is dynamically decided by the miners.
Solc and Remix provide tools to estimate gas.
Gas prices can be found here.
The main compiler for Solidity is called solc
(written in C++).
There is a JavaScript version called solcjs
(npm i -g solc
to get it).
Once you have written a contract, to generate the binary you will run:
solcjs --bin contract.sol
... and to generate both the binary code and the ABI (the contract's interface), you will run:
solcjs --bin --abi contract.sol
Nothe that a contract's code is immutable. Once it is instantiated, it cannot be changed.
- After compaling, copy the
contract.bin
code - Open the geth console and save the code above into a variable (e.g. contractCode)
- Unlock the account which will perform the deployment transaction
- And send the transaction:
eth.sendTransaction(
{
from: eth.accounts[0],
data: "0x" + counterCode,
gas: 1000000
},
function(err, tx) {
console.log(err, tx)
}
)
- Save the contract address that comes from the output (as contract=xxx) e.g. "0xF9E3793376090f6dFA1C4b3c30fe7c572E216967"
- Make sure the transaction gets mined into a block, check with
eth.getCode(contractAddress)
- The we will create a JavaScript Proxy with the ABI that describes the contract's interface
- Copy the contract.abi and parse it to JSON ->
var abi = JSON.parse(abiCode)
- Create a class for the contract ->
var Contract = eth.contract(abi)
- Create an instance ->
var contract = Contract.at(contractAddress)
- With the instance created, the methods of the contract can be accessed now
e.g. counter.sol contract: contract.get()
will return 1
While getters can be accessed locally, setters cannot: e.g. contract.increment()
will throw an error
To access to setters we have to send a transaction on that method of the contract: e.g. contract.increment.sendTransaction({from: eth.accounts[0]})
Resuming, the complete lifecycle of a contract would be:
- Contract is written in Solidity.
- It gets compiled to bytecode with solcjs.
- A transaction is submitted to create an instance of the contract (class) on the network.
There is a framework called Truffle which simplifies this process pretty much.
Todo: create a version of the sample contract using Truffle.
To access an Ethereum network and its contracts from a user interface (from browser), we will need web3.
Web3 helps to establish the connection to an Ethereum node, which in turn has access to the EVM.
So basically, we create the connection with only these piece of code:
const Web3 = require('web3');
const web3 = new Web3();
web3.setProvider(
new web3.providers.HttpProvider('http://localhost:8545')
)
Mastering Bitcoin 2nd Edition - Programming the Open Blockchain - link
White Paper (with some background about Bitcoin) - link
Good overview and starting point - link
Tutorials - link
Testing client - link
Have a look - link
Lis of DApps - link