以太坊的环境容易部署,执行一些命令就OK了。
那就开始搞吧。。。

以太坊环境部署

在安装以太坊之前要先安装下go,go的安装类似jdk,下载tar包,解压然后配置下环境变量。

安装以太坊:

1
2
3
4
5
6
7
8
9
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo add-apt-repository -y ppa:ethereum/ethereum-dev
sudo add-apt-repository ppa:ethereum/ethereum-qt
sudo apt-get update
# 安装以太坊
sudo apt-get install ethereum
# 安装solc编译器
sudo apt-get install cpp-ethereum # 并没有solc命令
sudo apt-get install solc # 安装solc,进行本地编译合约

安装结束之后的版本是Geth/v1.8.13-stable-225171a4/linux-amd64/go1.10

认识以太坊

完成以上操作之后,就可以操作以太坊了,可以进行挖矿了。这里先来熟悉下以太坊的客户端geth。

geth的全称是go-ethereum,是一个以太坊客户端,用go语言编写。

进入geth客户端有两种比较方式,一种是以开发方式登录,另一种是以私链方式登录。其中以开发方式登录相对比较简单,我们先来简单的。

输入命令geth --dev --dev.period 1 console 2>> geth-log(此命令,默认就会挖矿,执行miner.stop()停止)进入客户端。

执行上述命令会在当前目录生成一个geth-log的文件,可在其中查看运行情况。

挖矿

我们接触到以太坊或者比特币的第一想法就是,自己在测试环境挖个矿,感受下,对这些虚拟的东西来个直观的认识。

在挖矿之前我们先熟悉几个常用的命令,感受下geth。

1
2
3
4
5
6
7
8
9
eth # 全局环境变量
eth.accounts # 查看系统已有的用户
personal.newAccount('bigdatadecode') # 新增用户,bigdatadecode为密码
personal.newAccount('bigdatadecode.top') # 可以多建几个,观察下效果
eth.accounts # 建完之后,再查看系统已有的用户
# 对用户赋值,方便使用
user1 = eth.accounts[0]
user2 = eth.accounts[1]
eth.getBalance(user1) # 账户余额

发现这些账户的余额是0,那么重点就来了,开始挖矿了,

1
2
3
4
5
6
7
8
9
10
11
12
13
miner.start() # 开始挖矿
miner.stop() # 停止挖矿
eth.getBalcance(user1) # 挖矿一段时间,观察下账户余额
eth.sendTransaction({from:user1,to:user2,value:8}) # 转账
eth.getBalance(user2) # 此时为0,还没有被确认, 需重新开启挖矿,然后再查看余额,此时为8
web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
personal.unlockAccount(user3, 'bigdatadecode.top') # 解锁
eth.blockNumber # 查看区块高度
eth.getBlock(8) # 得到区块8的信息

eth.coinbase # 查看coinbase
miner.setEtherbase(eth.coinbase) # 设置miner账号
eth.blockNumber # 查看区块高度

Note: 如果你进入geth的命令是geth --dev console 2>> geth-log,当执行miner.start()时,会返回null,
原因在于geth版本更新之后,–dev模式下新增了一个参数项,加上--dev.period 1

返回null,解决方案原文

HelloWorld

上一节操作了挖矿转账等流程,这节整个智能合约的HelloWorld。直接上合约代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
contract Mortal {
/* Define variable owner of the type address */
address owner;

/* This function is executed at initialization and sets the owner of the contract */
function Mortal() { owner = msg.sender; }

/* Function to recover the funds on the contract */
function kill() { if (msg.sender == owner) selfdestruct(owner); }
}

contract Greeter is Mortal {
/* Define variable greeting of the type string */
string greeting;

/* This runs when the contract is executed */
function Greeter(string _greeting) public {
greeting = _greeting;
}

/* Main function */
function greet() constant returns (string) {
return greeting;
}
}

合约greeter是一个简单的智能合约,你可以使用这个合约来和其他人交流,它的回复会同你的输入完全一样,当输入为“Hello World!”的时候,合约也会回复“Hello World!”。

将上述代码写入greeter.sol中。

编译智能合约

编译智能合约可以使用Browser-Solidity在线编译,也可以使用solc命令本地编译,此处使用solc命令本地编译。
1、生成bytecode
执行solc --bin greeter.sol生成code,如下:

1
2
3
4
5
6
7
======= greeter.sol:Greeter =======
Binary:
608060405234801561001057600080fd5b5060405161039b38038061039b83398101806040528101908080518201929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060019080519060200190610089929190610090565b5050610135565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100d157805160ff19168380011785556100ff565b828001600101855582156100ff579182015b828111156100fe5782518255916020019190600101906100e3565b5b50905061010c9190610110565b5090565b61013291905b8082111561012e576000816000905550600101610116565b5090565b90565b610257806101446000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514610051578063cfae321714610068575b600080fd5b34801561005d57600080fd5b506100666100f8565b005b34801561007457600080fd5b5061007d610189565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100bd5780820151818401526020810190506100a2565b50505050905090810190601f1680156100ea5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610187576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b565b606060018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102215780601f106101f657610100808354040283529160200191610221565b820191906000526020600020905b81548152906001019060200180831161020457829003601f168201915b50505050509050905600a165627a7a723058203f4430a961037d5e7c4870ac4cc8f97d329171e862ae297fd0046255bec602490029

======= greeter.sol:Mortal =======
Binary:
608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610114806100606000396000f300608060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b5146044575b600080fd5b348015604f57600080fd5b5060566058565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141560e6576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b5600a165627a7a723058206554007d7824c95b6473134490ff9f84381627c8c29d43da39ce468e740abeda0029

2、生成ABI
执行solc --abi greeter.sol生成ABI,如下:

1
2
3
4
5
6
7
======= greeter.sol:Greeter =======
Contract JSON ABI
[{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"greet","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_greeting","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]

======= greeter.sol:Mortal =======
Contract JSON ABI
[{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]

ABI(Application Binary Interface)其实就是一个有序的用户手册,描述了所有方法的名字和如何调用它们

设置希望返回的字符串

进入geth命令行,执行var _greeting = "Hello World!"

部署合约

1、用ABI来创建一个javascript环境中的合约对象

1
var greeterContract = web3.eth.contract([{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"greet","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_greeting","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]);

2、通过合约对象来部署合约

1
2
3
4
5
6
7
8
9
10
11
12
var greeter = greeterContract.new(
_greeting,
{
from: web3.eth.accounts[0],
data: '0x608060405234801561001057600080fd5b5060405161039b38038061039b83398101806040528101908080518201929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060019080519060200190610089929190610090565b5050610135565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100d157805160ff19168380011785556100ff565b828001600101855582156100ff579182015b828111156100fe5782518255916020019190600101906100e3565b5b50905061010c9190610110565b5090565b61013291905b8082111561012e576000816000905550600101610116565b5090565b90565b610257806101446000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514610051578063cfae321714610068575b600080fd5b34801561005d57600080fd5b506100666100f8565b005b34801561007457600080fd5b5061007d610189565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100bd5780820151818401526020810190506100a2565b50505050905090810190601f1680156100ea5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610187576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b565b606060018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102215780601f106101f657610100808354040283529160200191610221565b820191906000526020600020905b81548152906001019060200180831161020457829003601f168201915b50505050509050905600a165627a7a723058203f4430a961037d5e7c4870ac4cc8f97d329171e862ae297fd0046255bec602490029',
gas: '4700000'
}, function (e, contract){
console.log(e, contract);
if (typeof contract.address !== 'undefined') {
console.log('Contract mined! address: ' + contract.address + ' transactionHash: ' + contract.transactionHash);
}
})

挖矿

1、执行miner.start(1)开启挖矿
2、有块产生之后,执行miner.stop()停止挖矿

运行合约

执行命令greeter.greet();,正常命令行上会出现如下返回结果:Hello World!

OK,我们的第一个智能合约程序 “Hello World!” 已经完成了,但是目前它只有一个节点!

部署在其它节点

为了使得其他人可以运行你的智能合约,你需要两个信息:

  1. 智能合约地址Address
  2. 智能合约ABI

ABI在上文中已得到,智能合约的地址可以执行greeter.address得到。

然后你可以实例化一个JavaScript对象,该对象可以用来在任意联网机器上调用该合约,此处ABI和Address是上述代码返回值。
var greeter = eth.contract(ABI).at(Address);

自毁程序

一个交易需要被发送到网络需要支付费用,自毁程序是对网络的补充,花费的费用远小于一次常用交易。
你可以通过以下代码来检验是否成功,如果自毁程序运行成功以下代码会返回0:
greeter.kill.sendTransaction({from:eth.accounts[0]})

我执行完上述命令返回的貌似是一个地址,如下:

1
2
> greeter.kill.sendTransaction({from:eth.accounts[0]})
"0x117d2066fae468a16077286573b0e3470b20e9ac5bb87291f7733dd453027441"

此时再次执行greeter.greet();依然能返回Hello World!,我再次开启挖矿,一段时间后停止挖矿,再执行greeter.greet();,报错

1
2
3
4
5
6
7
8
9
10
11
> greeter.greet()
Error: new BigNumber() not a base 16 number:
at L (bignumber.js:3:2876)
at bignumber.js:3:8435
at a (bignumber.js:3:389)
at web3.js:1110:23
at web3.js:1634:20
at web3.js:826:16
at map (<native code>)
at web3.js:825:12
at web3.js:4080:18