[toc]
本文档是BCOS区块链开源平台的一部分。 BCOS区块链开源平台由深圳前海微众银行股份有限公司、上海万向区块链股份公司、矩阵元技术(深圳)有限公司共同发起。 本文档面向读者是了解区块链基本概念的区块链技术开发人员、测试人员、产品经理、区块链爱好者、金融行业从业者等等。
为了让大家更好的了解BCOS区块链开源平台的使用方法。本文档按照Step By Step的步骤详细介绍了BCOS区块链的构建、安装、启动,智能合约部署、调用等初阶用法,还包括多节点组网、系统合约等高阶内容的介绍。
本文档不介绍BCOS区块链设计理念及思路,详情请参看白皮书。
本章主要介绍运行BCOS区块链执行程序所需要的软硬件环境、以及从源码编译的环境准备和编译步骤。
配置 | 最低配置 | 推荐配置 |
---|---|---|
CPU | 1.5GHz | 2.4GHz |
内存 | 512MB | 2GB |
核心 | 1核 | 2核 |
带宽 | 512Kb | 1Mb |
操作系统 | Ubuntu(16.04 64位)/CentOS (7.2 64位) |
以下代码及操作命令以在Centos7.2操作系统上为示例。
① 安装nodejs(安装后版本nodejs版本大于6)、babel-node环境
sudo yum install -y nodejs
sudo npm install -g cnpm --registry=https://registry.npm.taobao.org
sudo cnpm install -g babel-cli babel-preset-es2017
echo '{ "presets": ["es2017"] }' > ~/.babelrc
② 安装智能合约solidity编译器 方式一:直接下载solc二进制执行程序
wget https://github.com/ethereum/solidity/releases/download/v0.4.13/solc-static-linux
sudo cp solc-static-linux /usr/bin/solc
sudo chmod +x /usr/bin/solc
方式二: 从 https://github.com/ethereum/solidity/releases 上获取安装包自行安装
③ 安装控制台
sudo yum install -y git
sudo cnpm install -g ethereum-console
git clone https://github.com/bcosorg/bcos.git
目录 | 说明 |
---|---|
eth | 主入口目录,其中main.cpp包含main函数入口 |
libdevcore | 基础通用组件实现目录,如工具类函数、基础数据类型结构定义、IO操作函数、读写锁、内存DB、TrieDB、SHA3实现、RLP编解码实现、Worker模型等等 |
libethcore | 区块链核心数据结构目录。如ABI、秘钥管理、区块头、预编译、交易结构等等 |
libethereum | 区块链主框架逻辑目录。如交易池、系统合约、节点管理、块链、块、链参数等等 |
libevm | 虚拟机主目录。如解释器、JIT等等 |
libevmcore | OPCODE指令集定义、定价 |
libp2p | 区块链P2P网络主目录。如握手、网络包编解码、会话管理等等 |
libpbftseal | PBFT共识插件实现目录 |
libraftseal | RAFT共识插件实现目录 |
libweb3jsonrpc | web3 RPC实现目录 |
systemproxyv2 | 系统合约实现目录 |
tool | 工具脚本目录 |
① 检查cmake 版本(cmake3 --version 必须>3.4.3) 如果版本不满足要求,需要升级。 方式一:从源升级
sudo yum -y install cmake3
方式二:到官网https://cmake.org/download/ 下载最新版本安装。
② 安装依赖的开发库
sudo yum install -y openssl openssl-devel
chmod +x scripts/install_deps.sh
./scripts/install_deps.sh
mkdir -p build
cd build/
cmake3 -DEVMJIT=OFF -DTESTS=OFF -DMINIUPNPC=OFF .. #注意命令末尾的..
make -j2
编译成功,eth/bcoseth 即是区块链可执行程序。 执行安装
make install
区块链节点的启动有两个必选参数。一个是创世块文件,另一个是运行参数配置文件。
其中创世块文件包含内置管理员账号,需要启动前提前生成。 其中运行参数配置文件包含节点身份NodeId,需要启动前提前生成。
本章开始先介绍程序启动所需的创世块文件、配置文件、日志配置文件的字段含义。接着介绍NodeId的生成方法和管理员外部账号公私钥对的生成方法,及创世块文件、配置文件、日志配置文件的样例。 最后介绍启动创世节点的命令方法。
创世块文件是对区块链第一个块的描述。是唯一的,不可变更的。 它是节点启动的一个必选参数。
源码目录下有示例创世块文件genesis.json,可以根据需要进行修改,关键字段说明如下:
配置项 | 说明 |
---|---|
timestamp | 创世块时间戳(毫秒) |
god | 内置链管理员账号地址(生成方法可参看生成公私钥对) |
alloc | 内置合约数据 |
initMinerNodes | 创世块节点NodeId(生成方法可参看生成NodeId) |
在 多节点组网 章节之前,只需要变更god、initMinerNodes字段,其他保持默认即可。
配置文件是对区块链运行时参数的设置。配置值可变更,重启时生效。 它是节点启动的一个必选参数。
源码目录下有示例创世块文件config.json,可以根据需要进行修改,关键字段说明如下:
配置项 | 说明 |
---|---|
sealEngine | 共识算法(可选PBFT、RAFT、SinglePoint) |
systemproxyaddress | 系统路由合约地址(生成方法可参看部署系统合约) |
listenip | 监听IP(建议内网IP) |
rpcport | RPC监听端口)(若在同台机器上部署多个节点时,端口不能重复) |
p2pport | P2P网络监听端口(若在同台机器上部署多个节点时,端口不能重复) |
wallet | 钱包文件路径 |
keystoredir | 账号文件目录路径 |
datadir | 节点数据目录路径 |
vm | vm引擎 (默认 interpreter ) |
networkid | 网络ID |
logverbosity | 日志级别(级别越高日志越详细,>8 TRACE日志,4<=x<8 DEBU G日志,<4 INFO日志) |
coverlog | 覆盖率插件开关(ON或OFF) |
eventlog | 合约日志开关(ON或OFF) |
logconf | 日志配置文件路径(日志配置文件可参看日志配置文件说明) |
NodeextraInfo | 节点连接配置列表[{NodeId,Ip,port,nodedesc,agencyinfo,identitytype}]( 节点ID、外网IP、P2P网络端口、节点描述、节点信息、节点类型) |
dfsNode | 分布式文件服务节点ID ,与节点身份NodeID一致 (可选功能配置参数) |
dfsGroup | 分布式文件服务组ID (10 - 32个字符)(可选功能配置参数) |
dfsStorage | 指定分布式文件系统所使用文件存储目录(可选功能配置参数) |
在 多节点组网 章节之前,只需要更新rpcport、p2pport、wallet、keystoredir、datadir、NodeextraInfo字段,其他保持默认即可。
在接下来的说明中,假设节点数据目录(注意当前用户对目录需要有写入权限)路径为/mydata/nodedata-1/。
日志配置文件是对区块链运行过程日志输出的设置。配置值可变更,重启时生效。
其中log.conf的关键字段说明如下:
配置项 | 说明 |
---|---|
FORMAT | 日志格式,典型如%level |
FILENAME | 日志文件输出的文件路径典型如/mydata/nodedata-1/log/log_%datetime{%Y%M%d%H}.log |
MAX_LOG_FILE_SIZE | 最大日志文件大小 |
LOG_FLUSH_THRESHOLD | 超过多少条日志即可落盘 |
详细示例看参看创世块文件、运行参数配置文件、日志配置文件示例
节点身份NodeId是一个公钥,代表节点的唯一身份标识。
mkdir -p /mydata/nodedata-1/
mkdir -p /mydata/nodedata-1/data/
mkdir -p /mydata/nodedata-1/log/
mkdir -p /mydata/nodedata-1/keystore/
bcoseth --gennetworkrlp /mydata/nodedata-1/data/network.rlp
将在/mydata/nodedata-1/data/ 目录下生成两个文件 network.rlp 和 network.rlp.pub。 network.rlp是节点身份的私钥二进制文件。 network.rlp.pub是节点身份的NodeId文件。
读取network.rlp.pub 将其更新到创世块文件genesis.json的initMinerNodes字段及 config.json中的NodeextraInfo字段,同时更新NodeextraInfo中的Nodedesc、 Agencyinfo、Peerip、Port为对应值。(Peerip为外网IP,Port为P2P网络监听端口)
管理员公钥代表着对区块链的管理权限,生成的公钥和私钥是一一对应的,私钥代表着对公钥的所有权,私钥应妥善保管。
cd tool
cnpm install
node accountManager.js
将公钥address更新到创世块文件genesis.json的god字段。
创世块文件示例如下:
{
"nonce": "0x0",
"difficulty": "0x0",
"mixhash": "0x0",
"coinbase": "0x0",
"timestamp": "0x0",
"parentHash": "0x0",
"extraData": "0x0",
"gasLimit": "0x13880000000000",
"god":"0x4d23de3297034cdd4a58db35f659a9b61fc7577b",
"alloc": {},
"initMinerNodes":["de0fa385816b505799433e54b88788e21cb42092a6ff5bcaa2285d7ace906e5e6ce8ef2b30134ff276a5834d58721291acc5864e07e6d52469b79b28e699dfde"]
}
运行参数配置文件示例如下:
{
"sealEngine": "PBFT",
"systemproxyaddress":"0x0",
"listenip":"127.0.0.1",
"rpcport": "8545",
"p2pport": "30303",
"wallet":"/mydata/nodedata-1/keys.info",
"keystoredir":"/mydata/nodedata-1/keystore/",
"datadir":"/mydata/nodedata-1/data/",
"vm":"interpreter",
"networkid":"12345",
"logverbosity":"4",
"coverlog":"OFF",
"eventlog":"ON",
"logconf":"/mydata/nodedata-1/log.conf",
"params": {
"accountStartNonce": "0x0",
"maximumExtraDataSize": "0x0",
"tieBreakingGas": false,
"blockReward": "0x0",
"networkID" : "0x0"
},
"NodeextraInfo":[
{
"Nodeid":"de0fa385816b505799433e54b88788e21cb42092a6ff5bcaa2285d7ace906e5e6ce8ef2b30134ff276a5834d58721291acc5864e07e6d52469b79b28e699dfde",
"Nodedesc": "node1",
"Agencyinfo": "node1",
"Peerip": "127.0.0.1",
"Identitytype": 1,
"Port":30303,
"Idx":0
}
]
}
日志配置文件示例如下:
* GLOBAL:
ENABLED = true
TO_FILE = true
TO_STANDARD_OUTPUT = false
FORMAT = "%level|%datetime{%Y-%M-%d %H:%m:%s}|%msg"
FILENAME = "/mydata/nodedata-1/log/log_%datetime{%Y%M%d%H}.log"
MILLISECONDS_WIDTH = 3
PERFORMANCE_TRACKING = false
MAX_LOG_FILE_SIZE = 209715200 ## 200MB - Comment starts with two hashes (##)
LOG_FLUSH_THRESHOLD = 100 ## Flush after every 100 logs
* TRACE:
FILENAME = "/mydata/nodedata-1/log/trace_log_%datetime{%Y%M%d%H}.log"
* DEBUG:
FILENAME = "/mydata/nodedata-1/log/debug_log_%datetime{%Y%M%d%H}.log"
FORMAT = "%level|%datetime|%file|%func|%line|%msg"
* FATAL:
ENABLED = false
* ERROR:
FILENAME = "/mydata/nodedata-1/log/error_log_%datetime{%Y%M%d%H}.log"
* WARNING:
ENABLED = false
* INFO:
FILENAME = "/mydata/nodedata-1/log/info_log_%datetime{%Y%M%d%H}.log"
* VERBOSE:
ENABLED = false
命令行:区块链执行程序路径 --genesis 创世块文件 --config 配置文件
bcoseth --genesis ./genesis.json --config ./config.json &
查看日志是否正常出块
tail -f /mydata/nodedata-1/log/info* | grep Report
日志示例如下:
日志中每行blk=563 都在正常增长,即是在正常出块。
至此,一个完整的区块链节点已经跑起来了!
区块链运行日志文件都位于 日志配置文件说明 config.json所配置的log.conf 所指路径下。 各个级别日志都有各自的日志文件。如TRACE日志写到trace_开头对应的文件中。 其中TRACE日志为全量日志、INFO日志为关键信息、DEBUG为调试信息。 查看区块链主线程日志可执行:
tail -f /mydata/nodedata-1/log/trace_log* | grep "|eth"
输出示例图如下:
日志输出的”Imported and best 3721” 代表块3721已经上链。
1.参照多节点组网章节,进行多节点组网,并部署系统合约;系统合约部署成功以后将输出系统代理合约(SystemProxy)、FileInfoManager和FileServerManager三个合约地址, 示例输出如下:
2.配置config.json文件中的dfsGroup,dfsNode,dfsStorage三个参数,并更新systemproxyaddress参数为上一步得到的系统代理合约地址,具体参数定义请参看参数配置文件章节;在群组和节点的关系定义上,通常一个节点只允许加入一个群组,多个节点如果配置一样的群组ID,节点启动以后将加入到同一个群组当中,反之亦然。
3.重启群组所有节点即可用启动DFS服务。DFS服务启动后,即可以通过JAVA SDK提供的方法进行文件存取操作。
JAVA SDK提供的接口功能包括文件上传,文件删除,文件下载,查询文件服务节点,添加服务节点,删除服务节点等。所提供接口为异步回调节接口,用户需要自定义回调监听处理类。SDK的核心类为DfsEngine,位于仓库的tool/java目录,为eclipse工程,依赖于同级目录的web3j项目。
- 接口名称:init
- 接口功能说明:初始化服务
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
host | String | 主机地址 |
port | int | JSONRPC端口 |
listener | IJuListener | 监听回调接口 |
walletPasswd | String | 加密口令 |
walletFile | String | 钱包文件 |
fileContract | String | 文件合约地址 |
serverContract | String | 文件服务合约地址 |
输出参数 | 参数说明 | 参数说明 |
返回值 | int | 0 :成功 其他:失败 |
- 接口名称:addServer
- 接口功能说明:添加服务节点
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
newServer | FileServer | 分布式文件服务节点 |
输出参数 | 参数类型 | 参数说明 |
返回值 | int | 0 :成功 其他:失败 |
- 接口名称:addServerCallback
- 接口功能说明:添加文件服务节点对应回调接口(即注册监听器回调函数)
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
server | FileInfo | 文件信息 |
ret | int | 返回值 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
- 接口名称:uploadFile
- 接口功能说明:上传文件
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
fileInfo | FileInfo | 文件信息 |
file | String | 文件路径 |
输出参数 | 参数类型 | 参数说明 |
返回值 | int | 0 :成功 其他:失败 |
- 接口名称:uploadFileCallback
- 接口功能说明:上传文件对应回调接口(即注册监听器回调函数)
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
fileInfo | FileInfo | 文件信息 |
ret | int | 返回值 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
- 接口名称:downloadFile
- 接口功能说明:下载文件
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
fileServer | FileServer | 文件服务节点信息 |
fileid | String | 文件ID |
store_path | String | 文件存储完整路径 |
ret | int | 返回值 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
- 接口名称:downloadFileCallback
- 接口功能说明:下载文件对应回调接口(即注册监听器回调函数)
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
fileInfo | FileInfo | 文件信息 |
ret | int | 返回值 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
- 接口名称:deleteFile
- 接口功能说明:删除文件
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
fileServer | FileServer | 文件服务节点信息 |
fileid | String | 文件ID |
输出参数 | 参数类型 | 参数说明 |
返回值 | int | 0 :成功 其他:失败 |
- 接口名称:deleteFileCallback
- 接口功能说明:删除文件对应回调接口(即注册监听器回调函数)
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
fileInfo | FileInfo | 文件信息 |
ret | int | 返回值 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
- 接口名称:addServer
- 接口功能说明:添加文件服务器节点
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
fileServer | FileServer | 文件服务节点信息 |
输出参数 | 参数类型 | 参数说明 |
返回值 | int | 0 :成功 其他:失败 |
- 接口名称:addServerCallback
- 接口功能说明:添加文件服务器节点对应回调接口(即注册监听器回调函数)
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
server | FileInfo | 文件信息 |
ret | int | 返回值 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
- 接口名称:deleteServer
- 接口功能说明:删除文件服务器节点
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
serverid | String | 文件服务节点ID |
输出参数 | 参数类型 | 参数说明 |
返回值 | int | 0 :成功 其他:失败 |
- 接口名称:deleteServerCallback
- 接口功能说明:删除文件服务器节点对应回调接口(即注册监听器回调函数)
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
server | FileServer | 文件服务节点信息 |
ret | int | 返回值 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
- 接口名称:listServers
- 接口功能说明:获取文件服务节点列表
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
NA | NA | NA |
输出参数 | 参数类型 | 参数说明 |
返回值 | int | 0 :成功 其他:失败 |
- 接口名称:listServersCallback
- 接口功能说明:获取文件服务节点列表对应回调接口(即注册监听器回调函数)
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
fileservers | Vector | 文件服务节点信息 |
ret | int | 返回值 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
- 接口名称:listFilesByGroup
- 接口功能说明:按节点群组列举出所有文件信息
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
group | String | 服务节点群ID |
输出参数 | 参数类型 | 参数说明 |
返回值 | int | 0 :成功 其他:失败 |
- 接口名称:listServersByGroupCallback
- 接口功能说明:按节点群组列举出所有文件信息对应回调接口(即注册监听器回调函数)
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
fileservers | Vector | 文件信息列表 |
ret | int | 返回值 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
- 接口名称:errorCallback
- 接口功能说明:按节点群组列举出所有文件信息
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
code | int | 错误码 |
error | String | 错误信息 |
输出参数 | 参数类型 | 参数说明 |
NA | NA | NA |
下面是一个完整展示如何使用分布式文件存储和访问功能的实例。示例代码可以参看源码工程,源代码具体位置为com.sample包的HelloDfs类。
1.定义回调监听类
public class HelloListener implements IDfsListener{
//回调接口实现
...
...
}
2.初始化SDK
String walletPassword = "1111";//钱包口令
String keyPath = "E:\\keys\\2429feaf-0e46-ddd5-5b72-0594e0a4ab00.json";//钱包文件
String fileContract = "0x9e86c1b4c4d82607298faac27da7d78364434c58";//文件信息合约地址
String fileServerContract = "0x0d76426479e438fe0d261dbb165cd3adcc4a1dd7";//文件服务合约地址
Strign host = "10.10.8.232";//服务节点主机
int port = 8545;//JSONRPC端口
init(host, port, TestListener, walletPassword, keyPath, fileContract, fileServerContract);//初始化
3.添加文件服务节点
FileServer fileServer = new FileServer();
fileServer.setGroup("group1");
fileServer.setId("0c1585a170e75c14564427f2faa8d74850c65765a10ce9aa4fcc55c7cdd60ab7768dd7fa066145d0ebada2214705fca7f464186e61ea163a18e6ebb9c99c7627");
fileServer.setHost("10.10.8.232");
fileServer.setPort(8545);
fileServer.setInfo("the master node");
fileServer.setOrganization("weiwan");
fileServer.setEnable(1);
Calendar calendar = Calendar.getInstance();
fileServer.setUpdateTime((int)calendar.getTime().getTime()/1000);
addServer(fileServer);//添加文件服务节点,等待回调add_server_back成功
4.上传文件
FileInfo fileInfo = new FileInfo();
fileInfo.setOwner("weiwan");
fileInfo.setPriviliges("rwx");
String file = "E:"+ File.separatorChar + "test.txt";
uploadFile(fileInfo, file);//上传文件,等待回调upload_file_back
//...回调成功
//回调返回文件ID,可以使用文件ID下载和操作文件
//另外在配置文件目录,可以查看文件
对本版本所提供的加法同态运算功能,提供如下使用说明: 1.Java的API实现的同态加密算法,可以完成对需要运算的数据完成加解密操作,相关的代码工程路径为:{git_root}\tool\java\Paillier;
2.Solidity合约语言提供一个Library,实现对两个加密后数据实现加法同态运算,相关的合约路径为:{git_root}\systemcontractv2\LibPaillier.sol;
3.提供C语言同态加法算法实现,最终开放接口为智能合约同态加法运算API,相关代码路径为:{git_root}\libpaillier;
4.扩展VM中的sha3指令用以支持合约与C代码底层能力的桥接和适配,相关代码路径为:{git_root}\libevm.
- 接口名称:generateKeyPair
- 接口功能说明:生成同态加密的密钥对
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
输出参数 | 参数类型 | 参数说明 |
返回值 | KeyPair | 生成的密钥对 (其他 :成功 null:失败) |
- 接口名称:encryption
- 接口功能说明:对数据进行同态加密
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
m | BigInteger | 待加密的操作数 |
publickey | PublicKey | 加密公钥,可以使用同态密钥管理对象获取 |
输出参数 | 参数类型 | 参数说明 |
返回值 | String | 加密后的输出 (其他 :成功 null:失败) |
- 接口名称:decryption
- 接口功能说明:对加密数据进行解密还原操作数
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
输出参数 | 参数类型 | 参数说明 |
返回值 |
- 接口名称:encryption
- 接口功能说明:对数据进行同态加密
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
ciphertext | String | 加密的密文数据 |
privateKey | PrivateKey | 加密公钥对应的私钥,可以使用同态密钥管理对象获取 |
输出参数 | 参数类型 | 参数说明 |
返回值 | BigInteger | 加密后的操作数 (其他 :成功 null:失败) |
- 接口名称:ciphertextAdd
- 接口功能说明:加法同态实现
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
Ciphertext1 | String | 同态加密后的操作数1 |
Ciphertext2 | String | 同态加密后的操作数2 |
输出参数 | 参数类型 | 参数说明 |
返回值 | String | 加法同态后的结果数 (其他 :成功 null:失败) |
// generate the key pair for encrypt and decrypt
KeyPair keypair = PaillierKeyPair.generateKeyPair();
RSAPublicKey pubKey = (RSAPublicKey)keypair.getPublic();
RSAPrivateKey priKey = (RSAPrivateKey)keypair.getPrivate();
// encrypt the first number with public key
BigInteger i1 = BigInteger.valueOf(1000000);
String c1 = PaillierCipher.encryption(i1, pubKey);
// encrypt the second number with same public key
BigInteger i2 = BigInteger.valueOf(2012012012);
String c2 = PaillierCipher.encryption(i2, pubKey);
// paillier add with numbers
String c3 = PaillierCipher.ciphertextAdd(c1,c2);
// decrypt the result
BigInteger o3 = PaillierCipher.decryption(c3, priKey);
- 接口名称:pai_add
- 接口功能说明:加法同态的合约实现
- 参数说明
输入参数 | 参数类型 | 参数说明 |
---|---|---|
D1 | String | 加密后的第一个加法操作数 |
D2 | String | 加密后的第二个加法操作数 |
输出参数 | 参数类型 | 参数说明 |
返回值 | String | 同态加法的结果其他 :成功 空串:失败 |
注:该合约实现复用了sha3的机制,采用特定的前缀进行扩展算法实现
import "LibPaillier.sol";
contract Test {
using LibPaillier for *;
string balance;
function addBalance(string n) public returns (int) {
string memory result = LibPaillier.pai_add(balance, n);
if (bytes(result).length == 0) {
return 1;
}
balance = result;
return 0;
}
}
本章以一个HelloWorld.sol智能合约为例介绍部署合约的方法。 该合约中有一个name成员变量。同时有更新接口set和读取接口get,合约源码如下:
contract HelloWorld{
string name;
function HelloWorld(){
name="Hi,Welcome!";
}
function get()constant returns(string){
return name;
}
function set(string n){
name=n;
}
}
工具目录下已有部署脚本。更新目录下config.js中的Ip(内网监听IP)和端口(RPC监听端口),及privKey(注意没有0x前缀)和account(注意有0x前缀) (生成方法参看生成公私钥对)后直接使用即可。
cd tool
cnpm install
vim config.js
babel-node deploy.js HelloWorld
输出示例如下:
输出即是HelloWorld.sol智能合约地址。
本章以第四章中的HelloWorld.sol智能合约为例介绍调用合约的方法。 调用更新接口set和读取接口get。
cd tool
babel-node demoHelloWorld.js
输出示例如下:
输出即是调用合约set接口后的结果。 以上仅为示例,可以新建智能合约文件或查看、修改HelloWorld.sol,及对应的调用脚本 以符合需要。 智能合约Solidity语言教程请参考http://solidity.readthedocs.io/en/latest/
控制台是通过IPC方式连接区块链节点进程的一种方式。 控制台可以查看区块信息、查看交易信息、查看节点连接信息。 打开控制台命令行:ethconsole geth.ipc文件路径
ethconsole /mydata/nodedata-1/geth.ipc
命令行 :web3.eth.getBlock(块号,console.log) 如输出显示块号1的块信息
web3.eth.getBlock(1,console.log)
命令行 :web3.eth.getTransaction(交易哈希,console.log)
如输入
web3.eth.getTransaction('0x32e7970afe197053b6b18771dea01e392da9cf9173b0a9a22ce3778de0a109d3',console.log)
示例输出如下(字段含义请参看交易结构):
命令行 :web3.eth.getTransactionReceipt(交易哈希,console.log)
如输入
web3.eth.getTransactionReceipt('0x32e7970afe197053b6b18771dea01e392da9cf9173b0a9a22ce3778de0a109d3',console.log)console.log)
命令行 :web3.eth.getCode(合约地址,console.log)
如输入
web3.eth.getCode('0x932169080dd008768f4bf1fbae7ca706d85525b9',console.log)
示例输出如下(输出为合约二进制编码,非空即是表示合约存在):
命令行 :web3.admin.getPeers(console.log)
如输入
web3.admin.getPeers(console.log)
本章详细介绍在一个创始节点已正常运行的前提下,如何一步步操作,加入新的区块链节 点, 组成区块链网络的操作流程。
系统合约是 BCOS 区块链的重要设计思路之一,也是控制网络节点加入和退出的重要方式,
因此[部署系统合约](#7.1 部署系统合约)是多节点组网的前提条件。并且仅需执行一次。
新节点加入网络的过程主要有三个步骤[新建非创世节点](#7.2 新建非创世节点)、[非创世节点加入网络](#7.3 非创世节点加入网络)、[非创世节点启动](#7.4 非创世节点启动)。
执行以下命令:
cd systemcontractv2
cnpm install
vim config.js #更新内网监听Ip和RPC监听端口,及privKey和account(可复用2.5.生成管理员公私钥对 中的或重新生成)
babel-node deploy.js
示例输出如下:
1.从上面输出中获得系统代理合约地址,更新到创世节点运行参数配置文件config.json
中的systemproxyaddress
字段。然后重启创世节点区块链进程。
2.编辑系统合约目录下的node1.json
。将其中的字段内容更新为创世节点的config.json
中的NodeextraInfo
部分自身的节点信息。(id=NodeId、ip=Peerip、port=Port、desc=Nodedesc、category=Identitytype、CAhash留空字符串即可、agencyinfo=Agencyinfo、idx=Idx注意字段值必须完全一样!)
示例如下:
3.添加创世节点入网
babel-node tool.js NodeAction registerNode node1.json
输出示例如下:
“发送交易成功”即表示交易请求已发出。
4.查看创世节点是否已在节点列表中
babel-node tool.js NodeAction all
输出示例如下:
输出中有NodeIdsLength = 1
即是代表节点列表中有一个节点了。
1.新建节点目录,下文设定新节点目录为/mydata/nodedata-2/
2.参看[生成节点身份NodeId](#2.4 生成节点身份NodeId) ,并将新的network.rlp network.rlp.pub
文件输出到 /mydata/nodedata-2/
3.拷贝创世块文件genesis.json
和创世节点的配置文件 config.json
及日志配置文件 log.conf
到新节点目录/mydata/nodedata-2/
4.更新/mydata/nodedata-2/
的config.json
文件中的rpcport、p2pport、wallet、keystoredir、datadir
字段(注意:若多个节点同在一台服务器,需要配置rpcport、 p2pport均不互相冲突)。
5.更新/mydata/nodedata-2/
的log.conf中的日志路径。
6.追加新节点信息到 /mydata/nodedata-2/
的config.json
文件中的 NodeextraInfo
字段。
示例如下:
"NodeextraInfo":[
{ "Nodeid":"de0fa385816b505799433e54b88788e21cb42092a6ff5bcaa2285d7ace906e5e6ce8ef2b30134ff276a5834d58721291acc5864e07e6d52469b79b28e699dfde",
"Nodedesc": "node1",
"Agencyinfo": "node1",
"Peerip": "119.29.57.154",
"Identitytype": 1,
"Port":30303,
"Idx":0
},
{ "Nodeid":"2a0cb7425bd63835d346ae20ec6107d28f64009a9dcca7d485713f1dfe7c4edf6e79b7e08a70cb8220beb133327361313e6bc793433311ba997a81e14800a85f",
"Nodedesc": "node2",
"Agencyinfo": "node2",
"Peerip": "xxxx",
"Identitytype": 1,
"Port":30304,
"Idx":1
}
]
其中字段说明如下:
字段 | 说明 |
---|---|
Nodeid | 节点ID |
Nodedesc | 节点描述 |
Agencyinfo | 节点信息 |
Peerip | P2P网络监听端口(建议外网IP) |
Identitytype | 节点类型 |
Port | P2P网络端口 |
执行以下命令:
cd systemcontractv2/
vim node2.json
1.编辑系统合约目录下的节点信息文件node2.json
。将其中的字段内容更新为/mydata/nodedata-2/
的config.json
中的NodeextraInfo
部分的node2
的节点信息。(注意字段值必须完全一样!)
2.添加节点入网
babel-node tool.js NodeAction registerNode node2.json
输出示例如下:
3.查看是否已经入网
babel-node tool.js NodeAction all
输出示例如下:
输出中有 NodeIdsLength = 2
即是代表节点列表中已有个节点了。
执行以下命令启动区块链节点进程:
bcoseth --genesis /mydata/nodedata-2/genesis.json --config /mydata/nodedata-2/config.json
查看块高变化及连接节点信息:
babel-node monitor.js
输出示例如下:
输出中“已连接节点数:1”代表已连接上的对端节点数。
输出中“当前块高11690”代表当前块高,块高不断增长说明在正常运行。
至此,两个节点的区块链网络已组成功!
若需要继续添加新节点入网,重复本章的[新建非创世节点](#7.2 新建非创世节点)、[非创世节点加入网络](#7.3 非创世节点加入网络)、[非创世节点启动](#7.4 非创世节点启动) 即可。
命令行:babel-node tool.js NodeAction cancelNode
节点信息json文件
最后一个参数“节点信息json文件” 即是[非创世节点加入网络](#7.3 非创世节点加入网络) 中节点加入网络时对应的节点信息文件。
执行删除命令后,可以通过执行以下命令来查看当前节点列表:
babel-node tool.js NodeAction all
机构身份认证功能,为机构备案公钥证书到区块链,作为准入机制,使得区块链上节点能 够与现实身份对应,节点接入联盟链时需验证该节点身份,节点身份验证通过才能接入联 盟链,节点行为可追溯。
生成私钥 private.key 和公钥 public.key
openssl genrsa -out private.key 1024
openssl rsa -in private.key -pubout -out public.key
1.假设本地有 public key 和 private key,然后放到如下位置目录:
/mydata/nodedata/CA/
public.key的内容如下(内容已省略):
-----BEGIN PUBLIC KEY-----
***
***
-----END PUBLIC KEY-----
private.key的内容如下(内容已省略)
-----BEGIN RSA PRIVATE KEY-----
***
***
-----END RSA PRIVATE KEY-----
2.把公钥public key写入合约
babel-node tool.js CAAction update ca.json
ca.json结构:
{
"hash":"xxx",
"pubkey":"xxxx",
"orgname":"BCOS银行",
"notbefore":20170223,
"notafter":20180223,
"status":1,
"whitelist":"192.168.1.1;192.168.1.2;192.168.1.3",
"blacklist":"192.168.1.11;192.168.1.12;192.168.1.13"
}
其中字段说明如下:
字段 | 说明 |
---|---|
hash | 对证书的sha256sum后的hash,这里的证书是指能导出public.key的原有证书 |
pubkey | public.key的整个文本信息,注意对换行符的替换 |
orgname | 机构名称 |
notbefore | 证书生效时间 |
notafter | 证书过期时间 |
status | 证书状态 0:不可用 1:可用 |
whitelist | ip白名单,只允许哪些ip可以连接当前节点,默认为空字符串,允许所有ip |
blacklist | ip黑名单,不允许哪些ip连接当前节点,默认为空字符串,代表没有禁止ip |
开关打开后,会对当前所有节点进行CA验证,如果节点在目录 /mydata/nodedata/CA/
没有相关的证书,那么会被对方节点拒绝。
开启开关前,先确保当前所有节点的证书已经上链。
开启全局CAVerify开关
babel-node tool.js ConfigAction set CAVerify true
查看开关是否生效
babel-node tool.js ConfigAction get CAVerify
若出现以下信息,则代表成功:
开启开关并且通过CA模块验证后,通过以下命令找出相关记录
grep "verify ok" /mydata/nodedata-1/log/*
如果证书过期或者被注销,可以通过以下命令来剔除用该证书的机构所有连接节点
babel-node tool.js CAAction updateStatus ca.json
其中,ca.json的 status 要设置为0。检查日志操作是否生效
grep "blockNumber is 0 or status is false" /mydata/nodedata-1/log/*
1.妥善保管 private.key,切勿泄露,同时应把证书,public.key 和 private.key 备份到安全位置
2.开启全局 CA 开关 CAVerify 开关前,先确保当前所有连接节点已有相应的证书在指定目录,同时注意文件的名字 public.key,private.key。
3.一旦把 CAVerify 开关开启后,不建议再把 CAVerify 关闭。
系统合约是BCOS区块链的内置智能合约。 主要分为以下几种:系统代理合约、节点管理合约、机构证书合约、权限管理合约、全网配置合约。
系统合约一经部署,全网生效后,一般不轻易变更。 若需重新部署变更升级,需全网所有节点都认可且重新更新运行参数配置文件的systemproxyaddress字段后重启。 系统合约原则上只允许管理员账号调用。
以下依次介绍各个系统合约的源码路径、已实现接口说明、调用例子、工具使用方法。
系统代理合约是系统合约的统一入口。 它提供了路由名称到合约地址的映射关系。
源码路径:systemcontractv2/SystemProxy.sol
接口名 | 输入 | 输出 | 备注 |
---|---|---|---|
获取路由信息 getRoute | 路由名称 | 路由地址、缓存标志位、生效块号 | 无 |
注册路由信息setRoute | 路由名称、路由地址、缓存标志位 | 无 | 若该路由名称已存在,则覆盖 |
web3调用示例如下(可参看systemcontractv2/deploy.js):
console.log("注册NodeAction.....");
func = "setRoute(string,address,bool)";
params = ["NodeAction", NodeAction.address, false];
receipt = await web3sync.sendRawTransaction(config.account, config.privKey, SystemProxy.address, func, params);
查看所有系统合约信息:
babel-node tool.js SystemProxy
示例输出如下:
输出中即是当前系统路由表的所有路由信息。
节点管理合约主要功能是维护网络中节点列表。 网络中节点加入或退出都需要与节点管理合约进行交互。
源码路径:systemcontractv2/NodeAction.sol
接口名 | 输入 | 输出 | 备注 |
---|---|---|---|
节点入网 registerNode | 节点ID、IP、端口、节点类型、节点描述、节点CA哈希、节点agency、节点序号 | 布尔结果 | 若该节点ID已存在,则忽略 |
节点出网 cancelNode | 节点ID | 布尔结果 | 若该路由名称不存在,则忽略 |
web3调用示例如下(可参看systemcontractv2/tool.js):
var instance=getAction("NodeAction");
var func = "registerNode(string,string,uint256,uint8,string,string,string,uint256)";
var params = [node.id,node.ip,node.port,node.category,node.desc,node.CAhash,node.agencyinfo,node.idx];
var receipt = web3sync.sendRawTransaction(config.account, config.privKey, instance.address, func, params);
请参看 添加非创世节点入网、节点出网
机构证书合约主要功能是维护机构证书信息。
源码路径:systemcontractv2/CAAction.sol
接口名 | 输入 | 输出 | 备注 |
---|---|---|---|
更新证书信息 update | 证书哈希、公钥、组织名称、证书有效开始时间、证书失效时间、证书状态、白名单列表、黑名单列表 | 布尔结果 | 若该证书信息不存在,则新建 |
更新证书状态 updateStatus | 证书哈希、证书状态 | 布尔结果 | 若该路由名称不存在,则忽略 |
查询证书信息 get | 证书哈希 | 证书哈希、公钥、组织名称、证书有效开始时间、证书失效时间、证书状态、块号 | 无 |
查询证书黑白名单列表 getIp | 证书哈希 | 白名单列表、黑名单列表 | 无 |
web3调用示例如下(可参看systemcontractv2/tool.js):
var instance=getAction("CAAction");
var func = "update(string,string,string,uint256,uint256,uint8,string,string)";
var params =
[ca.hash,ca.pubkey,ca.orgname,ca.notbefore,ca.notafter,ca.status,ca.whitelist,ca.blacklist];
var receipt =
web3sync.sendRawTransaction(config.account, config.privKey, instance.address, func, params);
查看证书列表
babel-node tool.js CAAction all
更新证书信息
babel-node tool.js CAAction update
更新证书状态
babel-node tool.js CAAction updateStatus
权限管理合约是对区块链权限模型的实现。 一个外部账户只属于一个角色,一个角色拥有一个权限项列表。 一个权限项由合约地址加上合约接口来唯一标识。
源码路径:systemcontractv2/AuthorityFilter.sol 交易权限Filter systemcontractv2/Group.sol 角色
合约 | 接口名 | 输入 | 输出 | 备注 |
---|---|---|---|---|
角色 | 设置用户权限组 权限项 setPermission | 合约地址、合约接口、权限标记 | 无 | 无 |
获取权限标记 getPermission | 合约地址、合约接口 | 权限标记 | 无 | |
交易权限Filter | 设置用户所属角色 setUserGroup | 用户外部账户、用户所属角色合约 | 无 | 无 |
交易权限检查 process | 用户外部账户、交易发起账户、合约地址、合约接口、交易输入数据 | 无 |
web3调用示例如下(可参看systemcontractv2/deploy.js):
func = "setUserGroup(address,address)";
params = [config.account, Group.address];
receipt = await web3sync.sendRawTransaction(config.account, config.privKey, AuthorityFilter.address, func, params);
console.log("授予"+config.account+"角色"+Group.address);
检查用户外部账户权限
babel-node tool.js AuthorityFilter 用户外部账户、合约地址、合约接口
继承TransactionFilterBase实现新的交易Filter合约。并通过addFilter接口将新Filter注册入TransactionFilterChain即可。
全网配置合约维护了区块链中部分全网运行配置信息。 目标是为了通过交易的全网共识来达成全网配置的一致更新。
源码路径:systemcontractv2/ConfigAction.sol
配置项 | 说明 | 默认值 | 推荐值 |
---|---|---|---|
maxBlockHeadGas | 块最大GAS (16进制) | 200000000 | 20000000000 |
intervalBlockTime | 块间隔(ms) (16进制) | 1000 | 1000 |
maxBlockTranscations | 块最大交易数(16进制) | 1000 | 1000 |
maxNonceCheckBlock | 交易nonce检查最大块范围(16进制) | 1000 | 1000 |
maxBlockLimit | blockLimit超过当前块号的偏移最大值(16进制) | 1000 | 1000 |
maxTranscationGas | 交易的最大gas(16进制) | 20000000 | 20000000 |
CAVerify | CA验证开关 | FALSE | FALSE |
接口名 | 输入 | 输出 | 备注 |
---|---|---|---|
设置配置项 set | 配置项、配置值 | 无 | 若配置表中已存在,则覆盖 |
查询配置值 get | 配置项 | 配置值、块号 | 无 |
web3调用示例如下(可参看systemcontractv2/tool.js):
var func = "set(string,string)";
var params = [key,value];
var receipt = web3sync.sendRawTransaction(config.account, config.privKey, instance.address, func, params);
console.log("配置项:"+key+","+value);
查询配置项
babel-node tool.js ConfigAction get配置项
设置配置项
babel-node tool.js ConfigAction set配置项 配置值
区块链进程支持将区块、状态数据存储到数据库,在config.json中增加如下配置:
"dbconf": {
"stateDbConf": {
"dbInfo": "x.x.x.x:x@db",
"dbName": "db",
"tableName": "t_state",
"userName": "****",
"pwd": "******",
"cacheSize": 104857600,
"engineType": 1 //1-mysql 2-oracle
},
"blockDbConf": {
"dbInfo": "x.x.x.x:x@db",
"dbName": "db",
"tableName": "t_block",
"userName": "****",
"pwd": "******",
"cacheSize": 104857600,
"engineType": 1 //1-mysql 2-oracle
},
"extrasDbConf": {
"dbInfo": "x.x.x.x:x@db",
"dbName": "db",
"tableName": "tb_extras",
"userName": "*****",
"pwd": "******",
"cacheSize": 104857600,
"engineType": 1 //1-mysql 2-oracle
}
}
配置中,一共指定三个表,分别是状态存储、区块存储和额外存储;
重新编译区块链进程,cmake时增加-DETH_ODBC选项,即可开启数据库存储。
本章介绍两个可选工具的使用场景与使用方法
创世块工具主要是为了将当前区块链中现有的所有合约数据作为快照导出。
一旦新链以此快照作为创世块文件启动,新链就可以快速拥有了当前区块链的所有合约数据。
命令行:
区块链执行程序路径 --genesis 创世块文件 --config 配置文件 --export-genesis 导出新创世块文件路径
示例如下:
bcoseth --genesis ./genesis.json --config ./config.json
--export-genesis ./genesis.file
执行输出的genesis.file即是新创世块文件。
为了方便快速的查看当前节点的网络连接及块高情况。可使用本工具。
cd tool
babel-node monitor.js
示例输出如下:
输出中“已连接节点数”代表当前节点已连接上的区块链节点数。
输出中“当前块高”代表当前节点的区块链高度。如果在不断增长,代表区块链在正常运行。
欢迎任何人对本文档指出不足、提出优化建议。
欢迎任何人参与BCOS区块链开源平台的使用、优化、改进。
欢迎任何人反馈BCOS区块链开源平台的任何问题。
若有问题反馈请尽可能包含以下信息:
1.平台源码版本(如有) 2.所在的操作系统或平台 3.问题重现的方法或步骤 4.问题期望的表现 5.源码文件及行数(如有)
随时联系我们:[email protected]
关键字段 | 说明 |
---|---|
hash | 块哈希 |
difficulty | 块难度(默认1) |
parentHash | 父块哈希 |
timestamp | 块时间戳 |
gasLimit | 块GAS最大限制 |
gasused | 块已使用GAS |
number | 块号 |
sha3uncles | 叔伯块哈希 |
stateroot | 世界状态树根 |
transcationroot | 交易树根 |
receiptsroot | 交易收据树根 |
genidx | 记账节点编号 |
nodelist | 记账节点公钥列表 |
关键字段 | 说明 |
---|---|
sender | 交易发送者外部账号 |
gas | 交易GAS上限 |
receiveaddress | 合约地址 |
data | 交易数据 |
sign | 交易签名 |
randomid | 交易随机数 |
blocklimit | 交易最大块号限制 |
关键字段 | 说明 |
---|---|
blockNumber | 交易所在块号 |
contractAddress | 合约地址 |
cumulativeGasUsed | 交易预估消耗GAS |
gasUsed | 交易实际消耗GAS |
logs | EventLog列表 |
transactionHash | 交易哈希 |
transactionIndex | 交易序号 |
关键字段 | 说明 |
---|---|
id | 节点身份NodeId |
name | 节点软件版本信息 |
network | 节点网络IP信息 |