Fisco开发第一个区块链应用
一、部署区块链
1. 环境准备
第一步:安装JDK 1.8版本。
第二步:下载fisco压缩包。
链接:https://pan.baidu.com/s/1_ivw1FeKVhbVZIAbzvdSQg
提取码:e14j
下载完成后解压缩到/root
目录下。
2. 启动节点
1)启动区块链节点:
cd /root/fisco/nodes/127.0.0.1/
sh start_all.sh
确认节点启动正常:
tail -f /root/fisco/nodes/127.0.0.1/node0/log/log* | grep +++
正常情况会不停输出++++Generating seal,表示共识正常。
2)启动节点控制台服务:
cd /root/fisco/WeBASE-Front/dist
sh start.sh
通过浏览器远程访问如下链接,如果可以访问,则说明已经正常运行了。
http://ip:5002/WeBASE-Front/
界面如下所示:
3. 编译合约
1)准备合约
pragma solidity ^0.4.21;
contract Asset {
address public issuer;
mapping (address => uint) public balances;
event Sent(address from, address to, uint amount);
constructor() {
issuer = msg.sender;
}
function issue(address receiver, uint amount) public {
if (msg.sender != issuer) return;
balances[receiver] += amount;
}
function send(address receiver, uint amount) public {
if (balances[msg.sender] < amount) return;
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
}
2)部署合约
选择合约IDE,点右上角“部署”按钮。部署成功后,会生成合约地址(如下图所示)。
3)下载SDK证书
点击右上角的“SDK证书下载”按钮,将下载的证书压缩包文件保存起来,后面需要导入到项目中。
4. 创建测试用户
点击左边“测试用户”菜单,在主界面上点击“新增用户”,然后输入用户名。
点击新建用户右边的导出按钮,选择.pem,导出用户证书。
二、创建应用
1. 新建项目
本示例所使用开发工具为Idea。首先新建一个Maven项目。然后按照下面目录结构在src/main/java
和src/main/resources
中创建相应的包和文件夹。
将上面准备好的用户证书和sdk证书分别复制到对应文件夹中(如下图所示)。
2. 引入依赖
pom文件如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fisco.bcos</groupId>
<artifactId>asset-app</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.6.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.fisco-bcos.java-sdk</groupId>
<artifactId>fisco-bcos-java-sdk</artifactId>
<version>2.9.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. 启动类
在org.fisco.bcos.asset
包下创建启动类。
@SpringBootApplication
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
System.out.println("项目启动成功");
}
}
4. 导出Java文件
点击节点控制台上的合约IDE,然后选中Asset.sol
合约后,点击上方的导出Java文件。
然后将导出的Java文件拷贝到项目的org.fisco.bcos.asset.contract
包下。
5. 定义区块链配置信息
在src/main/resources
目录下,新建application.yaml
文件。
fisco:
nodeList: 192.168.88.15:20201
groupId: 1
certPath: E:workspaceasset-appsrcmainresourcessdk
contractAddress:
# Asset合约地址(一定要加引号 不然注解@Value会把按照16进制数字进行转换赋值)
asset: "0xe755337500bb6ffad292a2499bc12e30d5dc744f"
# 账户地址
account:
# 账户秘钥地址
accountAddress: E:workspaceasset-appsrcmainresourcesaccount
# 账户文件地址
accountFilePath: E:workspaceasset-appsrcmainresourcesaccountzhongliwen_key_0x6e26d380588049b43efca3881a2b2c419ae1a118.pem
fisco.nodeList:区块链节点的ip和端口;
fisco.groupId:组ID;
fisco.certPath:证书保存目录;
fisco.contractAddress.asset:合约地址;
fisco.contractAddress.account.accountAddress:测试用户地址;
fisco.contractAddress.account.accountFilePath:用户密码文件地址;
6. 编写sdk访问合约方法
在org.fisco.bcos.asset.client
包下新建一个类,该类用于配置相关Bean。
package org.fisco.bcos.asset.client;
import org.fisco.bcos.sdk.BcosSDK;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.config.ConfigOption;
import org.fisco.bcos.sdk.config.exceptions.ConfigException;
import org.fisco.bcos.sdk.config.model.ConfigProperty;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.security.KeyPair;
import java.util.*;
/**
* @Description: 配置类
* @Date: 2022/9/30
* @Author: zhongliwen
* @Version: 1.0
*/
@Configuration
public class ApplicationContext {
@Value("${fisco.nodeList}")
private String nodeLists;
@Value("${fisco.groupId}")
private Integer groupId;
@Value("${fisco.certPath}")
private String certPath;
@Value("${fisco.account.accountFilePath}")
private String accountFilePath;
@Bean(name = "configProperty")
public ConfigProperty defaultConfigProperty() {
ConfigProperty property = new ConfigProperty();
// 配置cryptoMaterial
Map<String, Object> cryptoMaterialMap = new HashMap<>();
cryptoMaterialMap.put("certPath", certPath);
property.setCryptoMaterial(cryptoMaterialMap);
// 配置network
Map<String, Object> networkMap = new HashMap<>();
String[] split = nodeLists.split(",");
List<String> nodeList = Arrays.asList(split);
networkMap.put("peers", nodeList);
property.setNetwork(networkMap);
// 配置account
Map<String, Object> accountMap = new HashMap<>();
accountMap.put("keyStoreDir", "account");
accountMap.put("accountAddress", "");
accountMap.put("accountFileFormat", "pem");
accountMap.put("password", "");
accountMap.put("accountFilePath", accountFilePath);
property.setAccount(accountMap);
//配置 threadPool
Map<String, Object> threadPoolMap = new HashMap<>();
threadPoolMap.put("channelProcessorThreadSize", "16");
threadPoolMap.put("receiptProcessorThreadSize", "16");
threadPoolMap.put("maxBlockingQueueSize", "102400");
property.setThreadPool(threadPoolMap);
return property;
}
@Bean(name = "configOption")
public ConfigOption defaultConfigOption(ConfigProperty configProperty) throws ConfigException {
return new ConfigOption(configProperty);
}
@Bean(name = "bcosSDK")
public BcosSDK bcosSDK(ConfigOption configOption) {
return new BcosSDK(configOption);
}
@Bean(name = "client")
public Client getClient(BcosSDK bcosSDK) {
// 为群组初始化client
Client client = bcosSDK.getClient(groupId);
return client;
}
@Bean
public CryptoKeyPair getCryptoKeyPair(Client client) {
// 如果有密钥文件 那么每次读取的就不再是随机的
CryptoSuite cryptoSuite = client.getCryptoSuite();
CryptoKeyPair cryptoKeyPair = cryptoSuite.getCryptoKeyPair();
return cryptoKeyPair;
}
}
然后再同样的包下创建另外一个类,该类定义了访问Asset
合约的方法。
package org.fisco.bcos.asset.client;
import org.fisco.bcos.asset.contract.Asset;
import org.fisco.bcos.sdk.BcosSDK;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.model.callback.TransactionCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.math.BigInteger;
@Component
public class AssetClient {
@Autowired
private BcosSDK bcosSDK;
@Autowired
private Client client;
@Autowired
private CryptoKeyPair cryptoKeyPair;
@Value("${fisco.contractAddress.asset}")
private String contractAddress;
/**
* 发布资产(条件:当前用户是Asset合约发布者)
* @param receiver 接收者地址
* @param amount 资产数量
*/
public void issueAsset(String receiver, BigInteger amount) {
Asset asset = Asset.load(contractAddress, client, cryptoKeyPair);
asset.issue(receiver, amount, new CallbackResponse());
}
/**
* 发送资产(条件:发送者的账号Balance必须大于等于amount)
* @param receiver 接收者地址
* @param amount 资产数量
*/
public void sendAsset(String receiver, BigInteger amount) {
Asset asset = Asset.load(contractAddress, client, cryptoKeyPair);
asset.send(receiver, amount, new CallbackResponse());
}
private class CallbackResponse extends TransactionCallback {
@Override
public void onResponse(TransactionReceipt transactionReceipt) {
System.out.println("回调结果:");
System.out.println(transactionReceipt.getContractAddress());
System.out.println(transactionReceipt.getFrom());
System.out.println(transactionReceipt.getGasUsed());
System.out.println(transactionReceipt.getRemainGas());
System.out.println(transactionReceipt.getStatus());
System.out.println(transactionReceipt.getMessage());
System.out.println(transactionReceipt.getStatusMsg());
}
}
}
关于Java SDK的使用手册,可以参考官方提供的文档。
https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/sdk/java_sdk/index.html
7. 测试
编写一个单元测试类,分别对AssetClient
类中的两个方法进行单元测试。
package org.fisco.bcos.asset.client;
import org.fisco.bcos.Application;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.math.BigInteger;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class AssetClientTest {
@Autowired
private AssetClient assetClient;
@Test
public void testIssueAsset() throws InterruptedException {
String receiver = "0x6e26d380588049b43efca3881a2b2c419ae1a118";
BigInteger amount = new BigInteger("10000");
assetClient.issueAsset(receiver, amount);
Thread.sleep(5000);
System.out.println("发布成功!");
}
@Test
public void testSendAsset() throws InterruptedException {
String receiver = "0x0f16fe999788f945adcad08e5b8c4fb1fcfca55d";
BigInteger amount = new BigInteger("50000");
assetClient.sendAsset(receiver, amount);
Thread.sleep(5000);
System.out.println("发送成功!");
}
}
测试步骤:
- 先后执行
testIssueAsset
和testSendAsset
测试方法; - 执行成功后,在节点控制台的合约列表中找到对应的合约;
3. 点击右方的合约调用,然后方法选择balances
,参数输入测试方法中receiver地址;
点击确定后,可以看到相关的交易回执。
到目前为止,已经完成了在Fisco区块链上部署智能合约,并通过Java SDK调用智能合约函数的示例。