通过本文所述方法和项目中的脚本,我们可以快速的搭建好自己的 CITA
私链进行开发测试。
为了简化 CITA
的多机部署,帮助用户快速搭建 CITA
运行环境,我们推荐使用 docker
部署 CITA
。
安装docker
安装 docker
及 docker-compose
sudo apt-get install docker docker-compose docker.io
国内访问 hub.docker.com
可采用镜像加速:
cat > daemon.json << EOF { "registry-mirror": [ "https://registry.docker-cn.com" ] } EOF sudo mv daemon.json /etc/docker
获取CITA镜像
获取 CITA
镜像有两种方式:
hub.docker.com
拉取docker pull cryptape/play
CITA
镜像具体方式有两种,分别是二进制发布件构建和从源码编译生成发布件。
wget https://github.com/cryptape/cita/releases/download/v0.10/cita.tar.bz2 tar xf cita-v0.1.0.tar.bz2 cd cita scripts/build_image_from_binary.sh
完成后可以通过 docker images
找到 cryptape/play
的 docker
镜像。
git clone http://github.com/cryptape/cita cd cita scripts/build_image_from_source.sh
使用 docker-compose 部署 CITA
mkdir cita cd cita wget https://raw.githubusercontent.com/cryptape/cita/develop/scripts/docker-compose.yaml
sudo docker-compose run admin
sudo docker-compose up node0 node1 node2 node3
# stop single node docker-compose stop node0 # start single node docker-compose start node0 # stop all nodes docker-compose down
CITA 完全兼容以太坊的智能合约,solidity
是智能合约最为推荐的语言,因此我们也采用 solidity
语言来编写和测试智能合约。
编译 solidity 文件,返回文件字节码
要想编译 solidity
文件,你需要先安装编译器, solidity
智能合约可以通过多种方式进行编译
solidity
实时编译器来编译。 访问地址solc
编译器编译本文采用第二种方式,solc
编译器是一个来自 C++
客户端实现的组件,安装方法请参考 这里 。
安装完成后,在 Terminal
中执行 solc --version
,如果返回值为:
solc, the solidity compiler commandline interface Version: 0.4.18+commit.9cf6e910.Linux.g++
表示安装成功,接下来就可以使用 solc
命令编译 solidity
文件了。
CITA
工程中包含了智能合约示例 solidity
文件,存放目录地址为 (DIR)/cita/cita/scripts/contracts/tests
,其中 $(DIR)
代表工程的目录地址,进入该目录,就可以看到 test_example.sol
文件。
test_example.sol
文件是一个很简单的合约文件,只提供了简单的 get
和 set
方法,我们可以先调用 set
方法存储一个任意数值,然后再调用 get
方法验证存储是否生效,以此来检验合约部署和运行是否正常。
在 Terminal
执行:
solc test_example.sol --bin
如果文件没有错误,返回结果中将会包括 test_example.sol
的字节码,这个数值就是 CITA
链上该智能合约的唯一标示值。
部署合约,发送者需要构建合约权限(参看下面附录代码)
得到 solidity
文件字节码后,就可以将其部署到 CITA
链上了,部署的方法已经用 python
脚本封装,只需要传入私钥和字节码即可。
目前支持的 python
版本是2.7,python
脚本存放的位置为 (DIR)/cita/cita/scripts/contracts/txtool/txtool
,其中 $(DIR)
代表工程的目录地址,使用前你还需要提前安装好 python
脚本的依赖,具体安装方法可以参考 (DIR)/cita/cita/scripts/contracts/txtool
目录下的 README.md
文件。
在 Terminal
执行以下命令:
python make_tx.py --privkey "352416e1c910e413768c51390dfd791b414212b7b4fe6b1a18f58007fa894214" --code "606060405234156100105760006000fd5b610015565b60e0806100236000396000f30060606040526000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604b5780636d4ce63c14606c576045565b60006000fd5b341560565760006000fd5b606a60048080359060200190919050506093565b005b341560775760006000fd5b607d60a3565b6040518082815260200191505060405180910390f35b8060006000508190909055505b50565b6000600060005054905060b1565b905600a165627a7a72305820942223976c6dd48a3aa1d4749f45ad270915cfacd9c0bf3583c018d4c86f9da20029"
参数解释: code
为第一步中获得的字节码, privkey
可随意获取
通过 python 脚本发送交易命令
在 Terminal
中执行: python send_tx.py
结果如下:
{ "jsonrpc":"2.0", "id":1, "result": { "hash":"0xa02fa9a94de11d288449ccbe8c5de5916116433b167eaec37455e402e1ab53d3", "status":"Ok" } }
status
为 OK
,表示合约已经发送到 CITA
链上。
获得来自 CITA 区块链网络的回执
在 Terminal
中执行:python get_receipt.py
结果如下:
{ "contractAddress": "0x73552bc4e960a1d53013b40074569ea05b950b4d", // 合约地址 "cumulativeGasUsed": "0xafc8", "logs": [], "blockHash": "0x14a311d9f026ab592e6d156f2ac6244b153816eeec18717802ee9e675f0bfbbd", "transactionHash": "0x61854d356645ab5aacd24616e59d76ac639c5a5c2ec79292f8e8fb409b42177b", "root": null, "errorMessage": null, "blockNumber": "0x6", // 区块高度 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0", "gasUsed": "0xafc8" }
这里需要重点关注 contractAddress
和 blockNumber
,下文调用合约方法会用到。
获得合约文件方法的 hash 值
合约的调用是通过发送交易命令完成,调用具体的方法则是通过方法 hash
值完成
在 Terminal
中执行: solc test_example.sol --hash
结果如下:
======= example.sol:SimpleStorage ======= Function signatures: 6d4ce63c: get() // get方法hash值 60fe47b1: set(uint256) // set方法hash值
这里的 get
和 set
方法 hash
值是 CITA
链上的唯一标示值,下文调用合约方法会用到。
调用合约文件中的 set 方法
假定我们调用 set
方法,参数为1,也就是说将数值1存储到区块链内存中
在 Terminal
中执行:
python make_tx.py --privkey "352416e1c910e413768c51390dfd791b414212b7b4fe6b1a18f58007fa894214" --to "73552bc4e960a1d53013b40074569ea05b950b4d" --code "60fe47b10000000000000000000000000000000000000000000000000000000000000001"
privkey
是你的私钥, to
参数是合约的目标地址,code
参数是 set
方法和参数 hash
值的拼接,set
方法的 hash
值为60fe47b1,将参数1转换为uint256,转换成16进制就是64位。
通过 python 脚本发送交易命令
在 Terminal
中执行: python send_tx.py
{ "jsonrpc":"2.0", "id":1, "result": { "hash":"0xf29935d0221cd8ef2cb6a265e0a963ca172aca4f6e43728d2ccae3127631d590", "status":"Ok" } }
获得来自 CITA 区块链网络的回执
在 Terminal
中执行: python get_receipt.py
结果如下:
{ "contractAddress": null, "cumulativeGasUsed": "0x4f2d", "logs": [], "blockHash": "0x2a10ae38be9e1816487dbfb34bce7f440d60035e8978146caef5d14608bb222c", "transactionHash": "0xf29935d0221cd8ef2cb6a265e0a963ca172aca4f6e43728d2ccae3127631d590", "root": null, "errorMessage": null, "blockNumber": "0x15", // 区块的高度 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "transactionIndex": "0x0", "gasUsed": "0x4f2d" }
发送 eth_call Post 请求,验证合约执行效果
调用合约中的 get
方法,验证之前 set
方法的执行效果
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call", "params":[{"to":"0x73552bc4e960a1d53013b40074569ea05b950b4d", "data":"0x6d4ce63c"}, "latest"],"id":2}' 127.0.0.1:1337
其中 to
参数为合约目标地址, data
为 get
方法的 hash
值
结果如下:
{ "jsonrpc":"2.0", "id":2, "result":"0x0000000000000000000000000000000000000000000000000000000000000001" }
如果返回值中 result
值为1,表明合约调用生效
https://github.com/cryptape/cita/blob/develop/docs/source/cita_bootstrap.rst
附录:
# 帮助使用CITA的新用户了解操作的流程
### 安装需要的依赖
```
$ sudo add-apt-repository ppa:ethereum/ethereum
$ sudo add-apt-repository ppa:ethereum/ethereum-dev
$ sudo apt-get update
$ sudo apt-get install solc
```
```
$ pip install -r requirements.txt
$ bash requirements_sudo.sh
```
### 检查CITA是否正常启动
```
$ python check.py
```
### net_peerCount
```
$ python peer_count.py
```
### cita_blockNumber
```
$ python block_number.py
```
### 生成账户信息(账户信息保存在output/accounts目录)
使用secp256k1签名算法和sha3 hash
```
$ python generate_account.py
```
使用ed25519签名算法和blake2b hash
```
$ python generate_account.py --newcrypto
```
### 编译合约
```
传入文件的绝对路径
$ python compile.py -f /home/jerry/rustproj/cita/admintool/txtool/txtool/tests/test.sol
或者传入源码
$ python compile.py -s "pragma solidity ^0.4.0;
contract SimpleStorage {
uint storedData;
event Init(address, uint);
event Set(address, uint);
function SimpleStorage() {
storedData = 100;
Init(msg.sender, 100);
}
event Stored(uint);
function set(uint x) {
Stored(x);
storedData = x;
Set(msg.sender, x);
}
function get() constant returns (uint) {
return storedData;
}
}"
合约编译的结果保存在output/compiled目录
```
获取编译合约的函数地址
```
$ python compile.py -p "get()"
0x6d4ce63c
```
### 构造交易
使用secp256k1签名算法和sha3 hash
```
$ python make_tx.py
$ python make_tx.py --code `contract bytecode` --privkey `privatekey` --to `transaction to`
```
使用ed25519签名算法和blake2b hash
```
$ python make_tx.py --newcrypto
$ python make_tx.py --code `contract bytecode` --privkey `privatekey` --to `transaction to` --newcrypto
```
### 发送交易
交易相关的信息保存在output/transaction目录
```
$ python send_tx.py
$ python send_tx.py `deploycode`
$ python send_tx.py --codes `deploycode1` `deploycode2` `deploycode3` ...
```
### 获取交易
交易的hash使用output/transaction/hash文件中的值
```
$ python get_tx.py
$python get_tx.py --tx `transaction_hash`
```
### cita_getBlockByHash
```
$ python block_by_hash.py hash --detail
$ python block_by_hash.py hash --no-detail
```
### cita_getBlockByNumber
```
$ python block_by_number.py number --detail
$ python block_by_number.py number --no-detail
```
### 获取receipt
```
$ python get_receipt.py
$ python get_receipt.py --tx `transaction_hash`
```
### eth_getTransactionCount
```
$ python tx_count.py `block_number` -a `address`
```
### eth_getCode
```
$ python get_code.py `address` `number`
```
### 获取Logs
```
$ python get_logs.py
```
### 调用合约
```
$ python call.py `to` `data`
$ python call.py `to` `data` `block_number` --sender `option sender`
to --- contract address
data --- contract method, params encoded data.
data构造参考contract ABI
```
在编译过程中最好安装好一些python的库,以下可以直接搬过去:
sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler
sudo apt-get install --no-install-recommends libboost-all-dev
sudo apt-get install python-numpy python-scipy python-matplotlib python-sklearn python-skimage python-h5py python-protobuf python-leveldb python-networkx python-nose python-pandas python-gflags Cython ipython
sudo apt-get install protobuf-c-compiler protobuf-compiler
sudo apt-get install libatlas-base-dev1
sudo apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev
sudo pip install ecdsa pysodium
sudo pip install 'jsonrpcclient[requests]'
关于安装libsodium,从 https://download.libsodium.org/libsodium/releases/libsodium-1.0.12.tar.gz 下载安装包解压编译
参看:https://download.libsodium.org/doc/installation/
./configure
make
make check
make install
ln -s /usr/local/lib/libsodium.so.18 /usr/lib/libsodium.so.18
如果在安装过程中出现以下错误
error in ethereum setup command: 'tests_require' must be a string or list of strings containing valid project/version requirement specifiers; Unordered types are not allowed
----------------------------------------
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-6yN82G/ethereum/
证明setuptools版本太高,降版本到3.7即可,
pip install setuptools==37