关于利用webase-front节点控制台一键导出的java项目解析

news2024/11/18 8:40:27

搭建区块链系统和管理平台分别用的的fisco、webase

关于我们在利用java开发DApp(去中心化引用),与区块链系统交互,可以用:

1.webase前置服务给开发者提供的api:我们在搭建好fisco链之后,在搭一个webase-front服务,我们就能通过front服务提供的api,间接在fisco上面,进行部署、调用合约、获取块高,等与区块链系统交互的行为。

webase-front接口说明: 接口说明 — WeBASE v1.5.5 文档 (webasedoc.readthedocs.io)

 2.利用fisco官方为Java开发者提供的 fisco-sdk:通过引入他调用相关的方法,与区块链系统交互。

fisco-java-sdk快速入门: 快速入门 — FISCO BCOS v2 v2.9.0 文档 (fisco-bcos-documentation.readthedocs.io)

嗯,...但是按照官方文档,一旦我们项目大起来,其实就相对比较麻烦了(也不麻烦),然后我们可以利用webase-front节点控制台,将合约上传后,将合约对应的Java项目一键导出。

如下图:

这次我们利用webase-front搭建好,默认自带的Asset合约,来进行演示。

PS: 利用fisco-sdk 开发Dapp,先建议看fisco、webase有一定的基础之后,再建议尝试。

利用fisco-jdk第一次交互,可以看看这个,里面引用了Linux的IDEA、Maven、Java的安装:fisco Java-sdk 快速入门案例-CSDN博客

梦开始的地方

项目导出后,是一个boot项目,包管理工具是gradle,我习惯用Maven,因此我新建一个Maven项目,并将包移植到我自己的项目里。

pom.xml

我的 jdk 是 14。测试了jdk 11、8、14  ,就14不会报错对应fisco-sdk 2.9.2

<?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.example</groupId>
    <artifactId>fiscoDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>14</java.version>
        <spring-boot.version>2.6.13</spring-boot.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>
    <dependencies>
        <!-- web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 单元测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.36</version>
        </dependency>
        <!-- fisco bcos -->
        <dependency>
            <groupId>org.fisco-bcos.java-sdk</groupId>
            <artifactId>fisco-bcos-java-sdk</artifactId>
            <version>2.9.2</version>
            <!-- 2.7.2 version, I think  do not match jdk-14 -->
            <exclusions>
                <exclusion>
                    <artifactId>*</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
 



    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>

        </plugins>
    </build>


</project>

项目结构大体概览图 

contracts:存放合约的目录,没啥用。

第二个红框:

接触java web之后,应该都知道。

第三个红框:

abi:与合约交互用的abi; bin: 合约编译之后生成二进制文件;  conf: 存放证书用到的目录。

 接下来,我们从第2个红框开始,从上往下,依次讲解学习主要的的目录:

 config

SystemConfig

package org.example.demo.config;

import java.lang.String;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.springframework.context.annotation.Configuration;

/**
 * 自动配置类 对应 配置文件信息(网络/群组/证书文件。。。)
 */
@Data
@Configuration
@ConfigurationProperties(
    prefix = "system"
)
public class SystemConfig {
  private String peers;

  private int groupId = 1;

  private String certPath;

  private String hexPrivateKey;

  @NestedConfigurationProperty
  private ContractConfig contract;
}

 boot的自动装配类,当boot项目启动时,自动读取application.properties/yaml/yml中的自定义配置信息。并且,我们可以在spring 容器中获取到他。

对应的配置信息:

application.properties

# 搭建区块链第一个节点(node0)的,ip:port
system.peers=127.0.0.1:20200
# 合约所属群组id
system.groupId=1
# 证书所放的目录
system.certPath=conf
# 可选: 私钥文件
system.hexPrivateKey=19eb7fd7a47a487265c6c109d560929deaee8e378fd4990dcce7cebd8a34f195
#可选: 合约地址
system.contract.assetAddress=0x385dfad96f483042686273d5fda5c379b111bb20


server.port=8088
server.session.timeout=60
banner.charset=UTF-8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

ContractConfig

@Data
public class ContractConfig {
  private String assetAddress;
}

自动配置类所需要的类,创建对应的对象,将地址填充进去对应的字段。 

PS:属性名要对应配置字段。

SdkBeanConfig

package org.example.demo.config;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


/**
 *  读取我们配置类的信息,初始化Client
 **/
@Configuration
@Slf4j
public class SdkBeanConfig {

    @Autowired
    private SystemConfig config;

    /**
     * 读取配置信息,初始化client并返回
     */
    @Bean
    public Client client() throws Exception {
        String certPaths = this.config.getCertPath();
        String[] possibilities = certPaths.split(",|;");
        for(String certPath: possibilities ) {
            try{
                ConfigProperty property = new ConfigProperty();
                configNetwork(property); // concat network
                configCryptoMaterial(property,certPath); // concat cerpath

                ConfigOption configOption = new ConfigOption(property);
                Client client = new BcosSDK(configOption).getClient(config.getGroupId());

                BigInteger blockNumber = client.getBlockNumber().getBlockNumber();
                log.error("Chain connect successful. Current block number {}", blockNumber);

                configCryptoKeyPair(client);
                log.error("is Gm:{}, address:{}", client.getCryptoSuite().cryptoTypeConfig == 1, client.getCryptoSuite().getCryptoKeyPair().getAddress());
                return client;
            }
            catch (Exception ex) {
                log.error(ex.getMessage());
                try{
                    Thread.sleep(5000);
                }catch (Exception e) {}
            }
        }
        throw new ConfigException("Failed to connect to peers:" + config.getPeers());
    }

    /** 
     * 设置 network
     * @param configProperty 
     */
    public void configNetwork(ConfigProperty configProperty) {
        String peerStr = config.getPeers();
        List<String> peers = Arrays.stream(peerStr.split(",")).collect(Collectors.toList());
        Map<String, Object> networkConfig = new HashMap<>();
        networkConfig.put("peers", peers);

        configProperty.setNetwork(networkConfig);
    }

    /**
     * 设置 证书
     * @param configProperty 
     * @param certPath
     */
    public void configCryptoMaterial(ConfigProperty configProperty,String certPath) {
        Map<String, Object> cryptoMaterials = new HashMap<>();
        cryptoMaterials.put("certPath", certPath);
        configProperty.setCryptoMaterial(cryptoMaterials);
       
        
    }

    /**
     * 设置密钥
     * @param client 
     */
    public void configCryptoKeyPair(Client client) {
        if (config.getHexPrivateKey() == null || config.getHexPrivateKey().isEmpty()){
            client.getCryptoSuite().setCryptoKeyPair(client.getCryptoSuite().createKeyPair());
            return;
        }
        String privateKey;
        if (!config.getHexPrivateKey().contains(",")) {
            privateKey = config.getHexPrivateKey();
        } else {
            String[] list = config.getHexPrivateKey().split(",");
            privateKey = list[0];
        }
        if (privateKey.startsWith("0x") || privateKey.startsWith("0X")) {
            privateKey = privateKey.substring(2);
            config.setHexPrivateKey(privateKey);
        }
        client.getCryptoSuite().setCryptoKeyPair(client.getCryptoSuite().createKeyPair(privateKey));
    }
}

我们读取了SystemConfig中的配置信息,封装到ConfigProperty对象里,并又将其封装到ConfigOption这个对象里面,通过下面这段代码

 Client client = new BcosSDK(configOption).getClient(config.getGroupId());

获得了一个Client,通过调用Client的方法我们能与fisco交互,可以获取块高等..。

 service

AssetService

package org.example.demo.service;

import java.lang.Exception;
import java.lang.String;
import java.util.Arrays;
import javax.annotation.PostConstruct;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.example.demo.model.bo.AssetBalancesInputBO;
import org.example.demo.model.bo.AssetIssueInputBO;
import org.example.demo.model.bo.AssetSendInputBO;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.transaction.manager.AssembleTransactionProcessor;
import org.fisco.bcos.sdk.transaction.manager.TransactionProcessorFactory;
import org.fisco.bcos.sdk.transaction.model.dto.CallResponse;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 *  对应合约的Service,方法 -> 合约变量 和 合约函数
 *  发送交易 获取 响应
 */
@Service
@NoArgsConstructor
@Data
public class AssetService {
  public static final String ABI = org.example.demo.utils.IOUtil.readResourceAsString("abi/Asset.abi");

  public static final String BINARY = org.example.demo.utils.IOUtil.readResourceAsString("bin/ecc/Asset.bin");

  public static final String SM_BINARY = org.example.demo.utils.IOUtil.readResourceAsString("bin/ecc/Asset.bin");

  @Value("${system.contract.assetAddress}")
  private String address;

  @Autowired
  private Client client;

  AssembleTransactionProcessor txProcessor;

  @PostConstruct
  public void init() throws Exception {
    this.txProcessor = TransactionProcessorFactory.createAssembleTransactionProcessor(this.client, this.client.getCryptoSuite().getCryptoKeyPair());
  }

  public TransactionResponse issue(AssetIssueInputBO input) throws Exception {
    return this.txProcessor.sendTransactionAndGetResponse(this.address, ABI, "issue", input.toArgs());
  }

  public TransactionResponse send(AssetSendInputBO input) throws Exception {
    return this.txProcessor.sendTransactionAndGetResponse(this.address, ABI, "send", input.toArgs());
  }

  public CallResponse balances(AssetBalancesInputBO input) throws Exception {
    return this.txProcessor.sendCall(this.client.getCryptoSuite().getCryptoKeyPair().getAddress(), this.address, ABI, "balances", input.toArgs());
  }

  public CallResponse issuer() throws Exception {
    return this.txProcessor.sendCall(this.client.getCryptoSuite().getCryptoKeyPair().getAddress(), this.address, ABI, "issuer", Arrays.asList());
  }
}

AssertService就是webase-front遵循业务层规则,生成的基于fisco-sdk封装的service类。通过这个service类,我们能与合约进行交互。

看代码,我们都是调用了这个 AssembleTransactionProcessor对象的上方法,

1.调用合约函数,是调用了这个方法。

方法参数为: 调用函数的合约地址、合约abi、被调用合约函数的函数名、函数参数列表

2.获取状态变量,是调用这个方法。

方法参数为:调用者的地址、调用函数的合约地址、合约abi、被调用合约函数的函数名、函数参数列表

 

 raw

Asset

package org.example.demo.raw;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.fisco.bcos.sdk.abi.FunctionReturnDecoder;
import org.fisco.bcos.sdk.abi.TypeReference;
import org.fisco.bcos.sdk.abi.datatypes.Address;
import org.fisco.bcos.sdk.abi.datatypes.Event;
import org.fisco.bcos.sdk.abi.datatypes.Function;
import org.fisco.bcos.sdk.abi.datatypes.Type;
import org.fisco.bcos.sdk.abi.datatypes.generated.Uint256;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2;
import org.fisco.bcos.sdk.client.Client;
import org.fisco.bcos.sdk.contract.Contract;
import org.fisco.bcos.sdk.contract.precompiled.crud.TableCRUDService;
import org.fisco.bcos.sdk.crypto.CryptoSuite;
import org.fisco.bcos.sdk.crypto.keypair.CryptoKeyPair;
import org.fisco.bcos.sdk.eventsub.EventCallback;
import org.fisco.bcos.sdk.model.CryptoType;
import org.fisco.bcos.sdk.model.TransactionReceipt;
import org.fisco.bcos.sdk.model.callback.TransactionCallback;
import org.fisco.bcos.sdk.transaction.model.exception.ContractException;

/**
 * 这里就是我们能跟区块链系统中的合约对应交互的java类
 * 发送交易 获取凭证
 *
 * 这两个最终执行逻辑是同一个类上的不同方法
 */
@SuppressWarnings("unchecked")
public class Asset extends Contract {
    public static final String[] BINARY_ARRAY = {"608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061044f806100606000396000f300608060405260043610610062576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680631d1438481461006757806327e235e3146100be578063867904b414610115578063d0679d3414610162575b600080fd5b34801561007357600080fd5b5061007c6101af565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156100ca57600080fd5b506100ff600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506101d4565b6040518082815260200191505060405180910390f35b34801561012157600080fd5b50610160600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506101ec565b005b34801561016e57600080fd5b506101ad600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610299565b005b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60016020528060005260406000206000915090505481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561024757610295565b80600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055505b5050565b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156102e55761041f565b80600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555080600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055507f3990db2d31862302a685e8086b5755072a6e2b5b780af1ee81ece35ee3cd3345338383604051808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001828152602001935050505060405180910390a15b50505600a165627a7a723058204e0edbb0e9bfd782dfaee2a435005414f5f84d50f4ead01144060672399fe6720029"};

    public static final String BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", BINARY_ARRAY);

    public static final String[] SM_BINARY_ARRAY = {};

    public static final String SM_BINARY = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", SM_BINARY_ARRAY);

    public static final String[] ABI_ARRAY = {"[{\"constant\":true,\"inputs\":[],\"name\":\"issuer\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"name\":\"\",\"type\":\"address\"}],\"name\":\"balances\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"issue\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"receiver\",\"type\":\"address\"},{\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"send\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"Sent\",\"type\":\"event\"}]"};

    public static final String ABI = org.fisco.bcos.sdk.utils.StringUtils.joinAll("", ABI_ARRAY);

    // 调用合约对应的函数名 和状态变量名
    public static final String FUNC_ISSUER = "issuer";

    public static final String FUNC_BALANCES = "balances";

    public static final String FUNC_ISSUE = "issue";

    public static final String FUNC_SEND = "send";

    public static final Event SENT_EVENT = new Event("Sent", 
            Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}, new TypeReference<Address>() {}, new TypeReference<Uint256>() {}));


    /**
     * 下面 load函数本质上和这个一样都是根据现有合约地址加载,以调用
     * @param contractAddress
     * @param client
     * @param credential
     */
    protected Asset(String contractAddress, Client client, CryptoKeyPair credential) {
        super(getBinary(client.getCryptoSuite()), contractAddress, client, credential);
    }

    public static String getBinary(CryptoSuite cryptoSuite) {
        return (cryptoSuite.getCryptoTypeConfig() == CryptoType.ECDSA_TYPE ? BINARY : SM_BINARY);
    }

    public String issuer() throws ContractException {
        final Function function = new Function(FUNC_ISSUER, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}));
        return executeCallWithSingleValueReturn(function, String.class);
    }

    public BigInteger balances(String param0) throws ContractException {
        final Function function = new Function(FUNC_BALANCES, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Address(param0)), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Uint256>() {}));
        return executeCallWithSingleValueReturn(function, BigInteger.class);
    }

    /**
     * 无回调函数的对应和合约调用
     * 
     * @param receiver
     * @param amount
     * @return  TransactionReceipt 交易凭证
     */
    public TransactionReceipt issue(String receiver, BigInteger amount) {
        final Function function = new Function(
                FUNC_ISSUE, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Address(receiver), 
                new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)), 
                Collections.<TypeReference<?>>emptyList());
        return executeTransaction(function);
    }

    /**
     * 调用合约函数,并传入一个回调函数
     *
     * @param receiver
     * @param amount
     * @param callback
     */
    public void issue(String receiver, BigInteger amount, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_ISSUE, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Address(receiver), 
                new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)), 
                Collections.<TypeReference<?>>emptyList());
                asyncExecuteTransaction(function, callback);
    }

    /**
     * 获取Issue合约函数的交易签名
     * @param receiver
     * @param amount
     * @return
     */
    public String getSignedTransactionForIssue(String receiver, BigInteger amount) {
        final Function function = new Function(
                FUNC_ISSUE, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Address(receiver), 
                new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)), 
                Collections.<TypeReference<?>>emptyList());
        return createSignedTransaction(function);
    }


    /**
     * 获取 IssurInpt输入的参数
     * @param transactionReceipt
     * @return 元组(封装输入的数据)
     */
    public Tuple2<String, BigInteger> getIssueInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_ISSUE, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}, new TypeReference<Uint256>() {}));
        List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());

        return new Tuple2<String, BigInteger>(

                (String) results.get(0).getValue(), 
                (BigInteger) results.get(1).getValue()
                );
    }



    public TransactionReceipt send(String receiver, BigInteger amount) {
        final Function function = new Function(
                FUNC_SEND, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Address(receiver), 
                new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)), 
                Collections.<TypeReference<?>>emptyList());
        return executeTransaction(function);
    }

    public void send(String receiver, BigInteger amount, TransactionCallback callback) {
        final Function function = new Function(
                FUNC_SEND, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Address(receiver), 
                new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)), 
                Collections.<TypeReference<?>>emptyList());
                asyncExecuteTransaction(function, callback);
    }

    public String getSignedTransactionForSend(String receiver, BigInteger amount) {
        final Function function = new Function(
                FUNC_SEND, 
                Arrays.<Type>asList(new org.fisco.bcos.sdk.abi.datatypes.Address(receiver), 
                new org.fisco.bcos.sdk.abi.datatypes.generated.Uint256(amount)), 
                Collections.<TypeReference<?>>emptyList());
        return createSignedTransaction(function);
    }

    public Tuple2<String, BigInteger> getSendInput(TransactionReceipt transactionReceipt) {
        String data = transactionReceipt.getInput().substring(10);
        final Function function = new Function(FUNC_SEND, 
                Arrays.<Type>asList(), 
                Arrays.<TypeReference<?>>asList(new TypeReference<Address>() {}, new TypeReference<Uint256>() {}));
        List<Type> results = FunctionReturnDecoder.decode(data, function.getOutputParameters());
        return new Tuple2<String, BigInteger>(

                (String) results.get(0).getValue(), 
                (BigInteger) results.get(1).getValue()
                );
    }

    public List<SentEventResponse> getSentEvents(TransactionReceipt transactionReceipt) {
        List<Contract.EventValuesWithLog> valueList = extractEventParametersWithLog(SENT_EVENT, transactionReceipt);
        ArrayList<SentEventResponse> responses = new ArrayList<SentEventResponse>(valueList.size());
        for (Contract.EventValuesWithLog eventValues : valueList) {
            SentEventResponse typedResponse = new SentEventResponse();
            typedResponse.log = eventValues.getLog();
            typedResponse.from = (String) eventValues.getNonIndexedValues().get(0).getValue();
            typedResponse.to = (String) eventValues.getNonIndexedValues().get(1).getValue();
            typedResponse.amount = (BigInteger) eventValues.getNonIndexedValues().get(2).getValue();
            responses.add(typedResponse);
        }
        return responses;
    }

    public void subscribeSentEvent(String fromBlock, String toBlock, List<String> otherTopics, EventCallback callback) {
        String topic0 = eventEncoder.encode(SENT_EVENT);
        subscribeEvent(ABI,BINARY,topic0,fromBlock,toBlock,otherTopics,callback);
    }

    public void subscribeSentEvent(EventCallback callback) {
        String topic0 = eventEncoder.encode(SENT_EVENT);
        subscribeEvent(ABI,BINARY,topic0,callback);
    }
    /**
     * 加载已有的合约地址,返回一个已有的Contract对象
     * @param contractAddress
     * @param client
     * @param credential
     * @return
     */
    public static Asset load(String contractAddress, Client client, CryptoKeyPair credential) {
        return new Asset(contractAddress, client, credential);
    }

    /**
     * 通过此方法,我们可以部署合约,产生一个新的Contract对象
     * @param client
     * @param credential
     * @return
     * @throws ContractException
     */
    public static Asset deploy(Client client, CryptoKeyPair credential) throws ContractException {
        return deploy(Asset.class, client, credential, getBinary(client.getCryptoSuite()), "");
    }

    public static class SentEventResponse {
        public TransactionReceipt.Logs log;

        public String from;

        public String to;

        public BigInteger amount;
    }
}

其实对比上述AssetService和Asset上封装调用的方法,发现最终都是调用一类对象上的不同方法。因此,看看就可以了。

AssembleTransactionProcessor 是AssetService层封装调用的。

TransactionProcessor 是Aseet层封装调用的。

abi、bin、conf

  • abi:存放合约abi的目录。定义外部调用合约的一种规则,本质上就是json文件,通过他,外部能与合约进行交互。
  • bin:bin文件存放目录。合约编译之后,形成的二进制文件、我们部署合约需要用到他。
  • conf: 存放fisco证书的目录。

测试文件

package org.example.demo;





import org.example.demo.model.bo.AssetBalancesInputBO;
import org.example.demo.model.bo.AssetIssueInputBO;
import org.example.demo.model.bo.AssetSendInputBO;
import org.example.demo.raw.Asset;
import org.example.demo.service.AssetService;
import org.fisco.bcos.sdk.abi.datatypes.generated.tuples.generated.Tuple2;
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.fisco.bcos.sdk.transaction.model.dto.CallResponse;
import org.fisco.bcos.sdk.transaction.model.dto.TransactionResponse;
import org.fisco.bcos.sdk.transaction.model.exception.ContractException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.math.BigInteger;

@SpringBootTest
public class AssetTest {

   @Autowired
   private AssetService assetService;

    @Test
    public void testAssetService() throws Exception {
        String testAddress1 = "0xb537616a39a710d7590716c4422977953518c555";
        String testAddress2 = "0x7700375543650bd19b716bb2a1d5bf609177ba39";
        // 初始化
        assetService.init();
        // 调用issue
        AssetIssueInputBO input = new AssetIssueInputBO();
        input.setReceiver(testAddress1);
        input.setAmount(new BigInteger("2"));
        TransactionResponse issue = assetService.issue(input);
        System.out.println(issue.getReturnMessage());
        // 调用send
        AssetSendInputBO send = new AssetSendInputBO();
        send.setAmount(new BigInteger("1"));
        send.setReceiver(testAddress2);
        TransactionResponse send1 = assetService.send(send);
        System.out.println(send1.getReturnMessage());

        // 调用balances
        AssetBalancesInputBO balancesBo = new AssetBalancesInputBO();
        balancesBo.setArg0("0xb537616a39a710d7590716c4422977953518c555"); // 因为balances是一个map,因此我们需要传入一个用户地址,用来获取balance
        CallResponse balances = assetService.balances(balancesBo);
        System.out.println(1);



    }

    @Autowired
    private Client client;

    @Test
    public void testAsset() throws ContractException {
        String receiver = "0x7700375543650bd19b716bb2a1d5bf609177ba39";
        BigInteger amount = new BigInteger("2");

        CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().getCryptoKeyPair();
        // 1.部署新合约
        Asset newInstance = Asset.deploy(client, cryptoKeyPair);
        // 2.实现TransactionCallback类
        TransactionCallback transactionCallback = new TransactionCallback() { //
            @Override
            // 这代码有问题,反正成功调用,这代码就是不调用
            public void onResponse(TransactionReceipt receipt) {
                System.out.println("我被调用了");

//                String newAddress = receipt.getContractAddress();
//                Asset load = Asset.load(newAddress, client, cryptoKeyPair);// 加载返回新合约的地址
//                TransactionReceipt issue = load.issue(receiver, amount);
            }
        };
        // 3.调用issue方法
       newInstance.issue(receiver, amount,transactionCallback);
       System.out.println(1);
        TransactionReceipt transactionReceipt = newInstance.issue(receiver, amount);
        // 4.获取issue方法的输入参数
        Tuple2<String, BigInteger> issueInput = newInstance.getIssueInput(transactionReceipt);


    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1112989.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Ceph存储

数据存储类型 块存储 存储设备与客户端主机是 一对一 的关系&#xff0c;块存储设备只能被一个主机挂载使用&#xff0c;数据以块为单位进行存储的&#xff0c;典型代表&#xff1a;硬盘 文件存储 一对多&#xff0c;能被多个主机同时挂载/传输使用&#xff0c;数据以文件的…

新年学新语言Go之四

一、前言 任何编程语言都有类型系统&#xff0c;类型系统解决了数据的存取问题&#xff0c;它决定了使用这个类型需要开辟内存空间大小以及数据是如何存放的&#xff0c;也解决如何读出数据&#xff0c;因为在内存中相同二进制值不同类型的含义是不一样的&#xff0c;关于Go基…

单链表的相关操作(初阶)

链表的概念 链表是线性表的一种&#xff0c;它是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻 辑顺序是通过链表中的指针链接次序实现的 。其实链表就相当于一列火车&#xff1a; 链表的结构跟⽕⻋⻋厢相似&#xff0c;淡季⻋厢会相应减少&#xff0c…

再添合作 | 大势智慧与长沙市规划信息服务中心签订战略合作协议

10月18日&#xff0c;武汉大势智慧科技有限公司&#xff08;以下简称&#xff1a;大势智慧&#xff09;与长沙市规划信息服务中心&#xff08;以下简称&#xff09;战略合作签约仪式在长沙举行。大势智慧CTO张帆与长沙市规划信息服务中心生产经营总监杨凤京代表双方签署战略合作…

如何处理前端无障碍(Accessibility)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

酷开会员值得回味的经典老剧还记得吗?酷开系统家庭影院带你重温

那些年&#xff0c;大家的娱乐生活主要集中在那一台9寸的黑白电视机中&#xff1b;那些年&#xff0c;家家户户的孩子们晚上都会聚到电视机前欢声笑语&#xff1b;那些年&#xff0c;是诸多经典的电视剧陪伴了很多人的闲暇时光……那些年陪伴我们成长&#xff0c;在记忆中熠熠生…

向量数据库Transwarp Hippo1.1多个新特性升级,帮助用户实现降本增效

例如,当查询“A公司业务发展情况”时,通过向量检索可以检索出A公司“主要业务”、“经营模式”、“财务情况”、“市场地位”等信息,通过全文检索可以检索出知识库中和关键字“业务”、“发展”相关的结果作为补充,通过将两者检索的结果进行结合,可以使得大模型回答的结果…

nexus私服安装

1.将文件上传到linux服务器中 2.解压、重命名 tar -zxvf nexus-3.7.1-02-unix.tar.gz //解压 mv nexus-3.7.1-02 nexus //重命名 3.自定义配置虚拟机可打开 nexus.vmoptions 文件进行配置 如果Linux硬件配置比较低的话&#xff0c;建议修改为合适的大小&…

前端(十九)——vue/react脚手架的搭建方式

&#x1f604;博主&#xff1a;小猫娃来啦 &#x1f604;文章核心&#xff1a;前端&#xff08;十九&#xff09;——vue/react脚手架的搭建方式 文章目录 前言Vue脚手架搭建方法Vue CLI脚手架Vite脚手架其他方式 React脚手架搭建方法Create React App脚手架Vite脚手架其他方式…

element 日期选择器禁止选择指定日期前后时间

画圈重点&#xff1a;disabledDate的写法要用箭头函数&#xff0c;不能用普通函数写法&#xff0c;否则this指向就错了&#xff0c;会报 undefined <el-date-picker v-model"time" type"date" value-format"yyyy-MM-dd" :…

使用CPR库和Python编写程序

以下是一个使用CPR库和Python编写的爬虫程序&#xff0c;用于爬取。此程序使用了proxy的代码。 import requests from cpr import CPR ​ def get_proxy():url "https://www.duoip.cn/get_proxy"headers {"User-Agent": "Mozilla/5.0 (Windows NT …

C++标准模板(STL)- 类型支持 (数值极限,min,lowest,max)

数值极限 提供查询所有基础数值类型的性质的接口 定义于头文件 <limits> template< class T > class numeric_limits; numeric_limits 类模板提供查询各种算术类型属性的标准化方式&#xff08;例如 int 类型的最大可能值是 std::numeric_limits<int>::ma…

01、MySQL-------性能优化

目录 一、影响性能的相关因素存储过程&#xff1a; 二、sql优化1>、Mysql系统架构2>、引擎区别&#xff1a; 3>、索引1、什么是索引&#xff1f;联合主键索引理解&#xff1a;索引长度理解&#xff1a;什么是慢查询&#xff1f; 1&#xff09;、索引理解2&#xff09;…

Win系统VMware虚拟机安装配置(一)(附激活码安装包)

VMware软件包&#xff08;Mac和Win&#xff09;提取码:hzxyhttps://www.123pan.com/s/JRpSVv-vKnjv.html 一、VMware 安装 一台电脑本身是可以装多个操作系统的&#xff0c;但是做不到多个操作系统切换自如&#xff0c;所以我们 需要一款软件帮助我们达到这个目的&#xff0c…

MIKE水动力笔记16_MIKE中的u、v、Speed、Direction之间的关系

本文目录 前言Step 1 MIKE中u、v、Speed、Direction的界定Step 2 从MIKE中导出u、v、Speed、Direction数据Step 3 数据导入Excel验证 前言 这两天饶有兴趣的做了一下关于MIKE中u、v、Speed、Direction之间关系的小测试&#xff0c;其实主要是为了探究利用u、v得到的角度和Dire…

下笔如有神:用VS Code写markdown

文章目录 Markdown All in One快捷键指令 输出PDFMarkdown Preview Enhancedmarkdown基本语法 Markdown All in One VS Coode中最推荐的Markdown插件是Markdown All in One&#xff0c;下文简称为mdAIO。千万别搜完markdown后下一个叫Markdown的插件&#xff0c;这个插件的名字…

Axi_Lite接口的IP核与地址与缓冲与AxiGP0

AXI Interconnect互连内核将一个或多个 AXI 内存映射主设备连接到一个或多个内存映射从设备。 AXI_GP 接口 AXI_GP 接口是直接连接主机互联和从机互联的端口的。 AXI_HP 接口具有一个 1kB 的数据 FIFO 来做缓冲 [4]&#xff0c;但是 AXI_GP 接口与它不同&#xff0c;没…

相同的树[简单]

一、题目 给你两棵二叉树的根节点p和q&#xff0c;编写一个函数来检验这两棵树是否相同。如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出&#xff1a;true 示例…

Linux常用命令——col命令

在线Linux命令查询工具 col 过滤控制字符 补充说明 col命令是一个标准输入文本过滤器&#xff0c;它从标注输入设备读取文本内容&#xff0c;并把内容显示到标注输出设备。在许多UNIX说明文件里&#xff0c;都有RLF控制字符。当我们运用shell特殊字符>和>>&#x…

基于SSM的工资管理系统

基于SSM的工资管理系统 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringSpringMVCMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 登录界面 管理员界面 通知公告 考勤管理 工资管理 请假管理 摘要 基于SSM&#xff08;Spring、S…