基于https://fisco-bcos-documentation.readthedocs.io文档开发
起因:需要将文件的sha256Hex哈希值存于搭建的FISCO BCOS 区块链中并验证文件的hash是否改变达到知晓文件是否改动的效果,并能查询出区块链的相关信息比如区块链的总高度,当前高度,区块链的hash值,名称,时间。
说明:我是一个java程序员只是负责读文档完成怎么实现调用区块链,关于这个区块链怎么搭建我没有做过多的了解,下面分享我通过智能合约调用区块链的过程
什么是FISCO BCOS 区块链
FISCO BCOS是由国内企业主导研发、对外开源、安全可控的企业级金融联盟链底层平台,由金链盟开源工作组协作打造,并于2017年正式对外开源。
FISCO BCOS 是一个稳定、高效、安全的区块链底层平台,经过多家机构、多个应用,长时间在生产环境运行的实际检验。
社区以开源链接多方,截止2020年5月,汇聚了超1000家企业及机构、逾万名社区成员参与共建共治,发展成为最大最活跃的国产开源联盟链生态圈。底层平台可用性经广泛应用实践检验,数百个应用项目基于FISCO BCOS底层平台研发,超80个已在生产环境中稳定运行,覆盖文化版权、司法服务、政务服务、物联网、金融、智慧社区等领域。
注解FISCO BCOS以联盟链的实际需求为出发点,兼顾性能、安全、可运维性、易用性、可扩展性,支持多种SDK,并提供了可视化的中间件工具,大幅缩短建链、开发、部署应用的时间。此外,FISCO BCOS通过信通院可信区块链评测功能、性能两项评测,单链TPS可达两万。
调用过程
- 引入调用区块链的相关jar
<dependency> <groupId>org.fisco-bcos.java-sdk</groupId> <artifactId>fisco-bcos-java-sdk</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.60</version> </dependency> <dependency> <groupId>org.fisco-bcos</groupId> <artifactId>netty-sm-ssl-context</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>org.fisco-bcos</groupId> <artifactId>tcnative</artifactId> <version>2.0.34.0</version> </dependency>
- 引入相关配置文件比如证书,智能合约
环境准备好后,话不多说直接上代码
第一个接口,去往区块链里存值并拿到区块链返回的区块hash值
说明:此方法传进去的两个参数一个是当前创建时间另一个是文件的hash值去存储,包涵了初始化sdk,初始化对象部署,同步方式部署合约异步方式部署,同步发送交易,异步发生区块交易,已经一些区块链的接口方法的调用,具体说明在远程调用接口 — FISCO BCOS v2.7.2 文档借口文档
private String transactionHash;//区块链返回的hash
public String testClient(String createTime,String FileMd5) throws Exception {
String path = this.getClass().getResource("/").getPath()
.replaceFirst("/","");
//String path = classpath.replaceAll("WEB-INF/classes/", "conf");
//path = path.replaceAll("\\\\", "/");
//初始化BcosSDK对象
BcosSDK sdk = BcosSDK.build("/"+path+"conf/config-example.toml");
// 获取Client对象,此处传入的群组ID为1
final Client client = sdk.getClient(1);
// 获得区块数量
//BlockNumber blockNumber = client.getBlockNumber();
//*******************************TEST***********************************************************
//初始化配置对象--------------------部署、交易和查询/仅交易和查询
//构造AssembleTransactionProcessor对象,需要传入client对象,CryptoKeyPair对象和
//abi、binary文件存放的路径。
CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair();
AssembleTransactionProcessor transactionProcessor =
TransactionProcessorFactory.createAssembleTransactionProcessor
(client, cryptoKeyPair, "/"+path+"abi/", "/"+path+"bin/");
// 同步方式部署合约-----------------也可以异步部署
// 部署HelloWorld合约。第一个参数为合约名称,第二个参数为合约构造函数的列表,是
//List<Object>类型。
TransactionResponse response = transactionProcessor.deployByContractLoader("StoreData", new ArrayList<Object>());
String con = response.getContractAddress();//获取部署或调用的合约地址。
System.out.println("the contract hash is :"+con);
//获取合约的abi文件里的参数
final String api = transactionProcessor.getContractLoader().getABIByContractName("StoreData");
//获取交易总数
String txNumber = client.getTotalTransactionCount().getTotalTransactionCount().getTxSum();
int startTxNumber = Integer.parseInt(txNumber.replace("0x",""), 16);
System.out.println("the startTxNumber:TxNumber is :"+startTxNumber);
final int SEND_TX_NUMBER = 1;
//发送交易
for (int i = 0; i < SEND_TX_NUMBER; i++) {
// 创建调用交易函数的参数,此处为传入一个参数
List<Object> listAgv = new ArrayList<Object>();
listAgv.add(createTime);
listAgv.add(FileMd5);
//同步发送交易 调用合约交易
// 调用StoreData合约,合约地址为con, 调用函数名为『set』,函数参数类型为listAgv 并接收TransactionResponse结果。
// TransactionResponse transactionResponse = transactionProcessor.sendTransactionAndGetResponseByContractLoader("StoreData", con, "set", listAgv);
// System.out.println(transactionResponse);
//异步发送交易
transactionProcessor.sendTransactionAndGetReceiptByContractLoaderAsync("StoreData", con,
"set", listAgv,new TransactionCallback() {
@SneakyThrows
@Override
public void onResponse(TransactionReceipt receipt) {
transactionHash = receipt.getTransactionHash();
System.out.println("start parse the receipt");
System.out.printf("the block getBlockNumber is %d \n",Integer.parseInt(receipt.getBlockNumber().replace("0x",""), 16));
System.out.printf("the block hash is %s\n",receipt.getBlockHash());
if(true)
return;
CryptoSuite cryptoSuite = client.getCryptoSuite();
TransactionDecoderInterface decoder = new TransactionDecoderService(cryptoSuite);
List<TransactionReceipt.Logs> logs = receipt.getLogs();
Map<String, List<List<Object>>> events = new HashMap<String, List<List<Object>>>();
try {
events = decoder.decodeEvents(api, receipt.getLogs());
} catch (ABICodecException e) {
e.printStackTrace();
}
// Map<String, List<List<Object>>>> events = decoder.decodeEvents(abi, receipt.getLogs());
for (List<List<Object>> lists :events.values()){
for(List<Object> list : lists){
System.out.println(list);
}
}
}
});
}
txNumber = client.getTotalTransactionCount().getTotalTransactionCount().getTxSum();
int endTxNumber = Integer.parseInt(txNumber.replace("0x",""), 16);
while (endTxNumber - startTxNumber < SEND_TX_NUMBER) {
txNumber = client.getTotalTransactionCount().getTotalTransactionCount().getTxSum();
endTxNumber = Integer.parseInt(txNumber.replace("0x",""), 16);
//System.out.println(endTxNumber);
}
System.out.println("the endTxNumber:TxNumber is :"+endTxNumber);
//当前区块链的高度
System.out.printf("client.getBlockNumber() is %d",client.getBlockNumber().getBlockNumber());
return transactionHash;
}
第二个接口,根据区块链返回的hash值去查询我存进去的文件hash以及传入时间
说明:参数hash是存值是区块链返回的hash值
public void todiscase(String hash){
String path = request.getSession().getServletContext().getRealPath("/");
//初始化BcosSDK对象
BcosSDK sdk = BcosSDK.build(path+"WEB-INF/classes/conf/config-example.toml");
// 获取Client对象,此处传入的群组ID为1
Client client = sdk.getClient(1);
//初始化配置对象--------------------部署、交易和查询/仅交易和查询
//构造AssembleTransactionProcessor对象,需要传入client对象,CryptoKeyPair对象和
//abi、binary文件存放的路径。
CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().createKeyPair();
AssembleTransactionProcessor transactionProcessor =
TransactionProcessorFactory.createAssembleTransactionProcessor(client,
cryptoKeyPair, path+"WEB-INF/classes/abi/", path+"WEB-INF/classes/bin/");
//获取合约的abi文件里的参数
String api =
transactionProcessor.getContractLoader().getABIByContractName("StoreData");
//根据交易哈希获取交易回执
BcosTransactionReceipt cosTransactionReceipt =
client.getTransactionReceipt(hash);
TransactionReceipt transactionReceipt = cosTransactionReceipt.getResult();
//查询传入的参数
CryptoSuite cryptoSuite = client.getCryptoSuite();
TransactionDecoderInterface decoder = new TransactionDecoderService(cryptoSuite);
Map<String, List<List<Object>>> events =
decoder.decodeEvents(api, transactionReceipt.getLogs());
/*for (List<List<Object>> lists :events.values()){
for(List<Object> list : lists){
System.out.println(list);
}
}*/
events.get("onset").get(0).get(0);//存入时间
events.get("onset").get(0).get(1);//存入的文件hash
}
第三个接口,查询区块链的信息
说明:参数hash是存值是区块链返回的hash值
public void selectBlock(String hash) {
String path = request.getSession().getServletContext().getRealPath("/");
//初始化BcosSDK对象
BcosSDK sdk = BcosSDK.build(path+"WEB-INF/classes/conf/config-example.toml");
// 获取Client对象,此处传入的群组ID为1
Client client = sdk.getClient(1);
BcosTransaction bcosTransaction = client.getTransactionByHash(hash);
JsonTransactionResponse jsonTransactionResponse = bcosTransaction.getResult();
BlockNumber blockNumber = client.getBlockNumber();
BigInteger blockNumbersum = blockNumber.getBlockNumber();//区块链的总高度
jsonTransactionResponse.getBlockNumber();//当前区块链的高度
jsonTransactionResponse.getBlockHash();//blockHash
jsonTransactionResponse.getFrom();//from
jsonTransactionResponse.getHash();;//hash
}
我当时需求涉及的接口就这三个,更多接口的调用依需求而定