基于FiscoBcos的web3sdk实现区块链服务

FiscoBcos-web3sdk实现

项目结构

  • contract 应用合约,sol文件

  • fiscobcos-dev   链证书、机构证书、机构私钥、账户

  • application-dev.yml
encrypt-type: # 0:普通, 1:国密

  encrypt-type: 0  #集群使用的加密类型



group-channel-connections-config:

  caCert: classpath:fiscobcos-${spring.profiles.active}/ca.crt  #链证书

  sslCert: classpath:fiscobcos-${spring.profiles.active}/sdk.crt  #机构证书

  sslKey: classpath:fiscobcos-${spring.profiles.active}/sdk.key  #机构私钥

  gmCaCert: classpath:fiscobcos-${spring.profiles.active}/gmca.crt #集群为国密版,则需要配置

  gmEnSslCert: classpath:fiscobcos-${spring.profiles.active}/gmensdk.crt

  gmEnSslKey: classpath:fiscobcos-${spring.profiles.active}/gmensdk.key

  gmSslCert: classpath:fiscobcos-${spring.profiles.active}/gmsdk.crt

  gmSslKey: classpath:fiscobcos-${spring.profiles.active}/gmsdk.key

  all-channel-connections:

    - group-id: 1 # sdk实际连接的群组

      connections-str:

        # 若节点小于v2.3.0版本,查看配置项listen_ip:channel_listen_port

        - 192.168.160.136:20200

        - 192.168.160.136:20201

        #- group-id: 2

        #connections-str:

        #- 192.168.160.130:20200

        #- 192.168.160.130:20201

        #- 192.168.160.135:20202

        #- 192.168.160.135:20203



channel-service:

  group-id: 1 # sdk实际连接的群组

  agency-name: fisco # 机构名称



accounts:

  pem-file: classpath:fiscobcos-${spring.profiles.active}/0x9ff96dcf17f27ddd643c23bc1236733aa92a1f20.pem #账户

#   p12-file: 0x98333491efac02f8ce109b0c499074d47e7779a6.p12

#   password: 123456



contract-address:

  kVPerson: "0x3cc40ecd5000f58c3458fef29b91114bd5e18da3"#合约地址
  • pom.xml

引用fisco-bcos-web3sdk的2.6.1版本

 

 

拷贝证书

集群的链证书、机构证书、机构私钥复制项目fiscobcos-dev文件下

 

控制台下账户复制项目fiscobcos-dev文件下

 

控制台部署合约

deploy KVPerson

transaction hash: 0x72908963644b7e897bf03d0a9ddb9f76428f5b1684aee89eb251d0adf15bdb75

contract address: 0x3cc40ecd5000f58c3458fef29b91114bd5e18da3

 

拷贝合约地址

把合约地址复制到项目的application-dev.yml配置文件里,通过合约地址来加载合约,获取合约对象。

 

生成java文件

使用web3sdk api将合约转换成java文件。执行SolidityGeneratorTest的compileSolFilesToJava(),在com.fish1208.temp包下生成java文件。

@Test
public void compileSolFilesToJava() throws IOException {
    File solFile = new File("D:\\_CodeSource\\java\\fish1208-fiscobcos-web3sdk\\contract\\solidity\\KVPerson.sol");
    SolidityCompiler.Result res = SolidityCompiler.compile(solFile, false, true, ABI, BIN, INTERFACE, METADATA);
    log.info("Out: '{}'" , res.getOutput());
    log.info("Err: '{}'" , res.getErrors());
    CompilationResult result = CompilationResult.parse(res.getOutput());
    log.info("contractname  {}" , solFile.getName());
    String contractname = solFile.getName().split("\\.")[0];
    CompilationResult.ContractMetadata a = result.getContract(solFile.getName().split("\\.")[0]);
    log.info("abi   {}" , a.abi);
    log.info("bin   {}" , a.bin);
    FileUtils.writeStringToFile(new File("src/test/resources/solidity/" + contractname + ".abi"), a.abi);
    FileUtils.writeStringToFile(new File("src/test/resources/solidity/" + contractname + ".bin"), a.bin);
    String binFile;
    String abiFile;
    String tempDirPath = new File("src/test/java/").getAbsolutePath();
    String packageName = "com.fish1208.temp";
    String filename = contractname;
    abiFile = "src/test/resources/solidity/" + filename + ".abi";
    binFile = "src/test/resources/solidity/" + filename + ".bin";
    SolidityFunctionWrapperGenerator.main(Arrays.asList(
            "-a", abiFile,
            "-b", binFile,
            "-p", packageName,
            "-o", tempDirPath
    ).toArray(new String[0]));
}

 

 

将转换后的java文件复制到项目com.fish1208.contract包里

 

代码开发

AccountConfig.java

通过application-dev.yml配置文件的accounts项,获取签名,Credentials对象

package com.fish1208.bcos.config;

import org.fisco.bcos.channel.client.P12Manager;
import org.fisco.bcos.channel.client.PEMManager;
import org.fisco.bcos.web3j.crypto.Credentials;
import org.fisco.bcos.web3j.crypto.ECKeyPair;
import org.fisco.bcos.web3j.crypto.EncryptType;
import org.fisco.bcos.web3j.crypto.gm.GenCredential;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;

@Configuration
@ConfigurationProperties(prefix = "accounts")
public class AccountConfig {

    private String pemFile;
    private String p12File;
    private String password;    
    private static final Logger log = LoggerFactory.getLogger(AccountConfig.class);
    @Autowired
    private EncryptType encryptType;

    @Bean
    public Credentials getCredentials()
            throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException,
                    InvalidKeySpecException, NoSuchProviderException, CertificateException,
                    IOException {

        return loadPemAccount();
        //return GenCredential.create();
        // return loadP12Account();
    }

    // load pem account file
    private Credentials loadPemAccount()
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
                    NoSuchProviderException, InvalidKeySpecException, UnrecoverableKeyException {
        log.info("pem accounts : {}", pemFile);
        PEMManager pem = new PEMManager();
        pem.setPemFile(pemFile);
        pem.load();
        ECKeyPair keyPair = pem.getECKeyPair();
        Credentials credentials = GenCredential.create(keyPair.getPrivateKey().toString(16));
        log.info("credentials address : {}", credentials.getAddress());
        return credentials;
    }

    // load p12 account file
    private Credentials loadP12Account()
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
                    NoSuchProviderException, InvalidKeySpecException, UnrecoverableKeyException {
        log.info("p12 accounts : {}", p12File);
        P12Manager p12Manager = new P12Manager();
        p12Manager.setP12File("classpath:" + p12File);
        p12Manager.setPassword(password);
        p12Manager.load();
        ECKeyPair keyPair = p12Manager.getECKeyPair();
        Credentials credentials = GenCredential.create(keyPair.getPrivateKey().toString(16));
        System.out.println(credentials.getAddress());
        return credentials;
    }

    /**
     * @return the pemFile
     */
    public String getPemFile() {
        return pemFile;
    }

    /**
     * @param pemFile the pemFile to set
     */
    public void setPemFile(String pemFile) {
        this.pemFile = pemFile;
    }

    /**
     * @return the p12File
     */
    public String getP12File() {
        return p12File;
    }

    /**
     * @param p12File the p12File to set
     */
    public void setP12File(String p12File) {
        this.p12File = p12File;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }
    
    
}

 

GroupChannelConnectionsPropertyConfig.java

通过application-dev.yml配置文件的group-channel-connections-config项,获取群组连接信息

package com.fish1208.bcos.config;

import org.fisco.bcos.channel.handler.ChannelConnections;
import org.fisco.bcos.channel.handler.GroupChannelConnectionsConfig;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;

import java.util.ArrayList;
import java.util.List;

@Configuration
@ConfigurationProperties(prefix = "group-channel-connections-config")
public class GroupChannelConnectionsPropertyConfig {

    List<ChannelConnections> allChannelConnections = new ArrayList<>();
    private Resource caCert;
    private Resource sslCert;
    private Resource sslKey;
    private Resource gmCaCert;
    private Resource gmEnSslCert;
    private Resource gmEnSslKey;
    private Resource gmSslCert;
    private Resource gmSslKey;

    @Bean
    public GroupChannelConnectionsConfig getGroupChannelConnections() {
        GroupChannelConnectionsConfig groupChannelConnectionsConfig =
                new GroupChannelConnectionsConfig();
        groupChannelConnectionsConfig.setCaCert(caCert);
        groupChannelConnectionsConfig.setSslCert(sslCert);
        groupChannelConnectionsConfig.setSslKey(sslKey);
        //gm
        groupChannelConnectionsConfig.setGmCaCert(gmCaCert);
        groupChannelConnectionsConfig.setGmEnSslCert(gmEnSslCert);
        groupChannelConnectionsConfig.setGmEnSslKey(gmEnSslKey);
        groupChannelConnectionsConfig.setGmSslCert(gmSslCert);
        groupChannelConnectionsConfig.setGmSslKey(gmSslKey);
        groupChannelConnectionsConfig.setAllChannelConnections(allChannelConnections);
        return groupChannelConnectionsConfig;
    }

    /**
     * @return the caCert
     */
    public Resource getCaCert() {
        return caCert;
    }

    /**
     * @param caCert the caCert to set
     */
    public void setCaCert(Resource caCert) {
        this.caCert = caCert;
    }

    /**
     * @return the sslCert
     */
    public Resource getSslCert() {
        return sslCert;
    }

    /**
     * @param sslCert the sslCert to set
     */
    public void setSslCert(Resource sslCert) {
        this.sslCert = sslCert;
    }

    /**
     * @return the sslKey
     */
    public Resource getSslKey() {
        return sslKey;
    }

    /**
     * @param sslKey the sslKey to set
     */
    public void setSslKey(Resource sslKey) {
        this.sslKey = sslKey;
    }

    public Resource getGmCaCert() {
        return gmCaCert;
    }

    public void setGmCaCert(Resource gmCaCert) {
        this.gmCaCert = gmCaCert;
    }

    public Resource getGmEnSslCert() {
        return gmEnSslCert;
    }

    public void setGmEnSslCert(Resource gmEnSslCert) {
        this.gmEnSslCert = gmEnSslCert;
    }

    public Resource getGmEnSslKey() {
        return gmEnSslKey;
    }

    public void setGmEnSslKey(Resource gmEnSslKey) {
        this.gmEnSslKey = gmEnSslKey;
    }

    public Resource getGmSslCert() {
        return gmSslCert;
    }

    public void setGmSslCert(Resource gmSslCert) {
        this.gmSslCert = gmSslCert;
    }

    public Resource getGmSslKey() {
        return gmSslKey;
    }

    public void setGmSslKey(Resource gmSslKey) {
        this.gmSslKey = gmSslKey;
    }

    /**
     * @return the allChannelConnections
     */
    public List<ChannelConnections> getAllChannelConnections() {
        return allChannelConnections;
    }

    /**
     * @param allChannelConnections the allChannelConnections to set
     */
    public void setAllChannelConnections(List<ChannelConnections> allChannelConnections) {
        this.allChannelConnections = allChannelConnections;
    }
    
}

 

ServiceConfig.java

通过application-dev.yml配置文件的channel-service项,获取Service对象

package com.fish1208.bcos.config;

import com.fish1208.common.constant.ConnectConstants;
import org.fisco.bcos.channel.client.Service;
import org.fisco.bcos.channel.handler.GroupChannelConnectionsConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author ASUS
 */
@Configuration
@ConfigurationProperties(prefix = "channel-service")
public class ServiceConfig {

    private String agencyName;
    private int groupId;
    private static final Logger log = LoggerFactory.getLogger(ServiceConfig.class);

    @Bean
    public Service getService(GroupChannelConnectionsConfig groupChannelConnectionsConfig) {
        Service channelService = new Service();
        channelService.setConnectSeconds(ConnectConstants.CONNECT_SECONDS);
        channelService.setOrgID(agencyName);
        log.info("agencyName : {}", agencyName);
        channelService.setConnectSleepPerMillis(ConnectConstants.CONNECT_SLEEP_PER_MILLIS);
        channelService.setGroupId(groupId);
        channelService.setAllChannelConnections(groupChannelConnectionsConfig);
        return channelService;
    }

    /**
     * @return the agencyName
     */
    public String getAgencyName() {
        return agencyName;
    }

    /**
     * @param agencyName the agencyName to set
     */
    public void setAgencyName(String agencyName) {
        this.agencyName = agencyName;
    }

    /**
     * @return the groupId
     */
    public int getGroupId() {
        return groupId;
    }

    /**
     * @param groupId the groupId to set
     */
    public void setGroupId(int groupId) {
        this.groupId = groupId;
    }
    
    
}

 

Web3jConfig.java

获取web3j对象

package com.fish1208.bcos.config;

import com.fish1208.common.constant.ConnectConstants;
import org.fisco.bcos.channel.client.Service;

import org.fisco.bcos.web3j.protocol.Web3j;
import org.fisco.bcos.web3j.protocol.channel.ChannelEthereumService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Web3jConfig {

    @Bean
    public Web3j getWeb3j(Service service) throws Exception {
        ChannelEthereumService channelEthereumService = new ChannelEthereumService();
        service.run();
        channelEthereumService.setChannelService(service);
        channelEthereumService.setTimeout(ConnectConstants.TIME_OUT);
        return Web3j.build(channelEthereumService, service.getGroupId());
    }
}

ContractConfig.java

通过application-dev.yml配置文件的contract-address得到合约地址,用来加载合约,获取合约对象

package com.fish1208.bcos.config;

import com.fish1208.bcos.ContractAddress;
import com.fish1208.common.constant.GasConstants;
import com.fish1208.contract.KVPerson;
import lombok.extern.slf4j.Slf4j;
import org.fisco.bcos.web3j.crypto.Credentials;
import org.fisco.bcos.web3j.protocol.Web3j;
import org.fisco.bcos.web3j.tx.gas.StaticGasProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
@Configuration
@ConfigurationProperties(prefix = "contract-address")
public class ContractConfig {

    private String kVPerson;

    @Autowired
    private Web3j web3j;

    @Autowired
    private Credentials credentials;

    @Bean
    public KVPerson loadTokenERC20(){
        return KVPerson.load(kVPerson, web3j, credentials, new StaticGasProvider(GasConstants.GAS_PRICE, GasConstants.GAS_LIMIT));
    }

    @Bean
    public ContractAddress setAddress(){
        log.info("kVPerson={}", kVPerson);
        ContractAddress contractAddress = new ContractAddress();
        contractAddress.setKVPerson(kVPerson);
        return contractAddress;
    }

    public String getkVPerson() {
        return kVPerson;
    }

    public void setkVPerson(String kVPerson) {
        this.kVPerson = kVPerson;
    }
}

 

PersonController.java

调用合约的set、get方法,进行数据上链、链上数据查询。

package com.fish1208.controller;

import com.alibaba.fastjson.JSON;
import com.fish1208.common.response.Result;
import com.fish1208.contract.KVPerson;
import lombok.extern.slf4j.Slf4j;
import org.fisco.bcos.web3j.protocol.core.methods.response.TransactionReceipt;
import org.fisco.bcos.web3j.tuples.generated.Tuple4;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigInteger;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/contract/person")
public class PersonController {

    @Autowired
    private KVPerson person;

    /**
     *
     * @param id
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/get", method = RequestMethod.GET)
    public Result<?> get(@RequestParam String id) throws Exception {
        if (person != null) {
            log.info("KVPerson address is: {}", person.getContractAddress());
            Tuple4<Boolean, String, BigInteger, String> tuple = person.get(id).send();
            return Result.data(tuple);
        }
        return Result.fail("执行KVPerson合约失败");
    }

    @RequestMapping(value = "/set", method = RequestMethod.POST)
    public Result<?> set(@RequestBody Map<String,Object> param) throws Exception {
        if (person != null) {
            log.info("KVPerson address is: {}", person.getContractAddress());
            String id = (String)param.get("id");
            String name = (String) param.get("name");
            BigInteger age = BigInteger.valueOf((Integer) param.get("age"));
            String sex = (String) param.get("sex");
            TransactionReceipt receipt = person.set(id, name, age, sex).send();
            log.info("KVPerson receipt = {}", JSON.toJSONString(receipt));
            return Result.data(receipt);
        }
        return Result.fail("执行KVPerson合约失败");
    }
}

 

 

项目启动

 

调用接口

执行KVPerson合约set方法

http://127.0.0.1:7022/contract/person/set

 

请求

POST /contract/person/set HTTP/1.1

Content-Type: application/json

{

"id":"3",

"name":"成功",

"age":1000,

"sex":"女"

}

执行KVPerson合约get方法

http://127.0.0.1:7022/contract/person/get?id=3

 

请求

GET /contract/person/get HTTP/1.1  

id=3

 

 

Github地址

https://github.com/hongfish/fish1208-fiscobcos-web3sdk

 

猜你喜欢

转载自blog.csdn.net/yuch_hong/article/details/115540408