0%

使用Fisco平台开发Solidity智能合约

开发环境部署

环境准备

  • 安装openssl和curl

开发部署工具 build_chain.sh脚本依赖于openssl、curl,因此需要首先安装openssl和curl。对于CentOS,使用yum安装;对于MacOS,使用brew安装。

1
2
3
4
// CentOS
yum install -y openssl curl
// MacOS
brew install -y openssl curl
  • 创建目录
1
cd ~ && mkdir -p fisco && cd fisco
  • 下载build_chain.sh工具
1
curl -LO https://github.com/FISCO-BCOS/FISCO-BCOS/releases/download/v2.4.0/build_chain.sh && chmod u+x build_chain.sh

如果因网络问题长时间未下载完成,可以使用如下链接下载:

1
curl -LO https://gitee.com/FISCO-BCOS/FISCO-BCOS/raw/master/tools/build_chain.sh && chmod u+x build_chain.sh

搭建单机四节点集群

  • 生成四节点的配置

在fisco目录下执行下面的指令,生成一条单群组4节点的FISCO链。 请确保机器的30300 ~ 30303,20200 ~ 20203,8545 ~ 8548端口没有被占用

1
bash build_chain.sh -l "127.0.0.1:4" -p 30300,20200,8545

注解:
其中-p选项指定起始端口,分别是p2p_port,channel_port,jsonrpc_port

  • 启动单机四节点集群

启动所有节点

1
bash nodes/127.0.0.1/start_all.sh
  • 检查进程是否成功
1
ps -ef | grep -v grep | grep fisco-bcos

使用控制台

环境准备

  • Java环境配置

参考Java环境配置

  • 获取控制台
1
cd ~/fisco && curl -LO https://github.com/FISCO-BCOS/console/releases/download/v1.0.9/download_console.sh && bash download_console.sh

如果因网络问题长时间未下载完成,可以使用如下链接下载:

1
cd ~/fisco && curl -LO https://gitee.com/FISCO-BCOS/console/raw/master/tools/download_console.sh
  • 拷贝控制台配置文件
1
cp -n console/conf/config-example.toml console/conf/config.toml
  • 配置控制台证书
1
cp nodes/127.0.0.1/sdk/* console/conf/

启动控制台

  • 启动
1
cd ~/fisco/console && bash start.sh

使用控制台获取信息

1
2
3
4
5
6
# 获取帮助信息
[group:1]> help
# 获取客户端版本
[group:1]> getNodeVersion
# 获取节点链接信息
[group:1]> getPeers

部署及调用HelloWorld合约

  • HelloWorld合约
1
2
3
4
5
6
7
8
9
10
11
12
13
pragma solidity>=0.4.24 <0.6.11;
contract HelloWorld {
string name;
constructor() public {
name = "Hello, World!";
}
function get() public view returns (string memory) {
return name;
}
function set(string memory n) public {
name = n;
}
}
  • 部署HelloWorld合约

HelloWorld合约已经内置于控制台中,位于控制台目录下contracts/solidity/HelloWorld.sol

1
2
3
[group:1]> deploy HelloWorld
transaction hash: 0x40413207aa2ab3b4fb1b9911c0e735b8a4e1a0dd3af58202169a42a06d9a9176
contract address: 0x673c7db07e818df412f2b8fbfb2c96ccdee1cbfd
  • 调用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
26
# 查看当前块高
[group:1]> getBlockNumber
1

# 调用get接口获取name变量 此处的合约地址是deploy指令返回的地址
[group:1]> call HelloWorld 0xb3c223fc0bf6646959f254ac4e4a7e355b50a344 get
Hello, World!

# 查看当前块高,块高不变,因为get接口不更改账本状态
[group:1]> getBlockNumber
1

# 调用set设置name
[group:1]> call HelloWorld 0xb3c223fc0bf6646959f254ac4e4a7e355b50a344 set "Hello, FISCO BCOS"
0x21dca087cb3e44f44f9b882071ec6ecfcb500361cad36a52d39900ea359d0895

# 再次查看当前块高,块高增加表示已出块,账本状态已更改
[group:1]> getBlockNumber
2

# 调用get接口获取name变量,检查设置是否生效
[group:1]> call HelloWorld 0xb3c223fc0bf6646959f254ac4e4a7e355b50a344 get
Hello, FISCO BCOS

# 退出控制台
[group:1]> quit

SDK调用测试

合约编译

由于Java程序无法直接调用solidity合约,因此需要将solidity合约编译成java文件。控制台提供了sol2java.sh脚本。

1
2
3
4
# 切换到fisco/console/目录
$ cd ~/fisco/console/
# 编译合约,后面指定一个Java的包名参数,可以根据实际项目路径指定包名
$ ./sol2java.sh org.fisco.bcos.asset.contract

注解:
sol2java.sh脚本使用方法:

1
./sol2java.sh [packageName] [solidityFilePath] [javaCodeOutputDir]

其中,$[packageName]$表示生成的java文件的包名;$[solidityFilePath]$表示solidity源文件的路径,默认为$contracts/solidity$;$[javaCodeOutputDir]$表示生成的java文件的路径,默认为$contracts/sdk/java$

SDK配置

  • 下载Java样例工程项目
1
2
curl -LO https://github.com/FISCO-BCOS/LargeFiles/raw/master/tools/asset-app.tar.gz
tar -zxf asset-app.tar.gz
  • 目录结构

asset-app的目录结构如下:

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
26
27
28

|-- build.gradle // gradle配置文件
|-- gradle
| |-- wrapper
| |-- gradle-wrapper.jar // 用于下载Gradle的相关代码实现
| |-- gradle-wrapper.properties // wrapper所使用的配置信息,比如gradle的版本等信息
|-- gradlew // Linux或者Unix下用于执行wrapper命令的Shell脚本
|-- gradlew.bat // Windows下用于执行wrapper命令的批处理脚本
|-- src
| |-- main
| | |-- java
| | |-- org
| | |-- fisco
| | |-- bcos
| | |-- asset
| | |-- client // 放置客户端调用类
| | |-- AssetClient.java
| | |-- contract // 放置Java合约类
| | |-- Asset.java
| |-- test| |-- resources // 存放代码资源文件
| |-- applicationContext.xml // 项目配置文件
| |-- contract.properties // 存储部署合约地址的文件
| |-- log4j.properties // 日志配置文件
| |-- contract //存放solidity约文件
| |-- Asset.sol
| |-- Table.sol
||-- tool
|-- asset_run.sh // 项目运行脚本
  • 项目引入Web3SDK

在build.gradle文件中引入了fisco-bcos-java-sdk

1
2
3
4
dependencies {
compile ("org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:2.8.0-SNAPSHOT")
...
}
  • 证书与配置文件

将区块链节点的sdk目录下的证书和配置文件拷贝到项目

1
cp ~/fisco/nodes/127.0.0.1/sdk/* asset-app/src/test/resources/

业务应用开发

  • 初始化

初始化主要是构造bcosSDK客户端以及设置客户端证书

1
2
3
4
5
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
bcosSDK = context.getBean(BcosSDK.class);
client = bcosSDK.getClient(1);
cryptoKeyPair = client.getCryptoSuite().createKeyPair();
client.getCryptoSuite().setCryptoKeyPair(cryptoKeyPair);
  • 部署合约
1
Asset asset = Asset.deploy(client, cryptoKeyPair);
  • 存储和加载合约地址
1
2
3
4
5
6
7
// 存储合约地址
Properties prop = new Properties();
prop.setProperty("address", address);
// 获取配置文件
final Resource contractResource = new ClassPathResource("contract.properties");
FileOutputStream fileOutputStream = new FileOutputStream(contractResource.getFile());
prop.store(fileOutputStream, "contract address");
1
2
3
4
5
6
7
8
9
10
// 加载合约地址
Properties prop = new Properties();
final Resource contractResource = new ClassPathResource("contract.properties");
prop.load(contractResource.getInputStream());

String contractAddress = prop.getProperty("address");
if (contractAddress == null || contractAddress.trim().equals("")) {
throw new Exception(" load Asset contract address failed, please deploy it first. ");
}
return contractAddress;
  • 调用合约
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 加载合约地址并创建合约对象
String contractAddress = loadAssetAddr();
Asset asset = Asset.load(contractAddress, client, cryptoKeyPair);

// 处理结果
Tuple2<BigInteger, BigInteger> result = asset.select(assetAccount);
if (result.getValue1().compareTo(new BigInteger("0")) == 0) {
System.out.printf(" asset account %s, value %s \n", assetAccount, result.getValue2());
} else {
System.out.printf(" %s asset account is not exist \n", assetAccount);
}

// 处理事件
List<Asset.RegisterEventEventResponse> response = asset.getRegisterEventEvents(receipt);
if (!response.isEmpty()) {
if (response.get(0).ret.compareTo(new BigInteger("0")) == 0) {
}
}

运行和测试

  • 编译
1
2
3
4
# 切换到项目目录
$ cd ~/asset-app
# 编译项目
$ ./gradlew build

注:
如果编译过程中出现“Could not find tools.jar”错误,需要配置JAVA_HOME
如:

1
export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home
  • 部署Asset.sol合约
1
2
3
# 进入dist目录
$ cd dist
$ bash asset_run.sh deploy
  • 注册资产
1
2
3
4
$ bash asset_run.sh register Alice 100000
Register account successfully => account: Alice, value: 100000
$ bash asset_run.sh register Bob 100000
Register account successfully => account: Bob, value: 100000
  • 查询资产
1
2
3
4
$ bash asset_run.sh query Alice
account Alice, value 100000
$ bash asset_run.sh query Bob
account Bob, value 100000
  • 转移资产
1
2
3
4
5
6
$ bash asset_run.sh transfer Alice Bob  50000
Transfer successfully => from_account: Alice, to_account: Bob, amount: 50000
$ bash asset_run.sh query Alice
account Alice, value 50000
$ bash asset_run.sh query Bob
account Bob, value 150000