FiscoBcos uses Java to call the contract [first method]

环境 : ubuntu20
fisco : 2.8.0
java:1.8
solidity: 0.6.10

Preface

This article will explain how to use the export function of WeBASE to deploy and call contracts.
Please start the fisco node and webase-front in advance

Contract writing and deployment

We prepare a simple contractHelloWorld.sol

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;
    }
}

After writing, we will deploy it and get the contract address.
Insert image description here

Export java project

Insert image description here
There are three function buttons in the functional area in the upper right corner of webase-front
Export java file: This function is to export a java file according to the contract , which contains abi, bin attributes, deployment contracts, calling contracts and other methods, but this is not a complete project. You also need to configure the springboot project and import related dependency packages yourself
SDK certificate download
Export java project: This function is to download the sdk certificate of the node, because when calling contract-related functions, you need to connect to the node, and then you need the certificate to connect

Insert image description here
The project name and package name need to be customized
Insert image description here
The contract needs to be compiled before it can be deployed. We have just deployed it

Click Confirm, and a zip package will be downloaded, which contains a SpringBoot project built by gradle.
Insert image description here

We unzip it and open this project using idea

Analyze the contents of the exported project

If there is a gradle environment locally, you can configure it in Settings. If not, the project will help you download a gradle environment and apply it to this project by default.

  • Analyze the directory structure of the project
    Insert image description here

In the resource folder of resources, there are abi and bin files, and the conf folder contains the sdk file connecting the node.
Field explanation of application.properties file

### Required, node's {ip:port} to connect.
system.peers=127.0.0.1:20200  # 节点地址
### Required
system.groupId=1  # 群组id
### Optional. Default will search conf,config,src/main/conf/src/main/config
system.certPath=conf,config,src/main/resources/conf,src/main/resources/config  # 项目配置文件存放的路径
### Optional. If don't specify a random private key will be used
system.hexPrivateKey=14681fb9c2e4774ab61ce97afb3a522b09d2c09b01647ad1b8ab807a60968f16 # 私钥文件【刚刚导出项目中选中的用户私钥】
### Optional. Please fill this address if you want to use related service
system.contract.helloWorldAddress=0xbdc8ef2968e775d68aad1480bb39fe19def2f4b7 # 合约地址
### ### Springboot server config
server.port=8080 # web项目启动端口
server.session.timeout=60
banner.charset=UTF-8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
spring.jackson.time-zone=GMT+8

Insert image description here
There are a lot of java files here, so I will focus on them
The service folder is HelloWorldService.java

@Service
@NoArgsConstructor
@Data
public class HelloWorldService {
    
    
  public static final String ABI = org.yijiuyiyi.HelloWorld.utils.IOUtil.readResourceAsString("abi/HelloWorld.abi");

  public static final String BINARY = org.yijiuyiyi.HelloWorld.utils.IOUtil.readResourceAsString("bin/ecc/HelloWorld.bin");

  public static final String SM_BINARY = org.yijiuyiyi.HelloWorld.utils.IOUtil.readResourceAsString("bin/sm/HelloWorld.bin");

  @Value("${system.contract.helloWorldAddress}")
  private String address; // 合约地址

  @Autowired
  private Client client;  // 这个是Fisco的Client ,调用方法都需要放置其对象,Client对象在项目初始化的时候已经装配好交给spirng进行管理了

  AssembleTransactionProcessor txProcessor;

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


//合约里面对应着set方法
  public TransactionResponse set(HelloWorldSetInputBO input) throws Exception {
    
    
    return this.txProcessor.sendTransactionAndGetResponse(this.address, ABI, "set", input.toArgs());
  }
// 合约里面对应着get方法
  public CallResponse get() throws Exception {
    
    
    return this.txProcessor.sendCall(this.client.getCryptoSuite().getCryptoKeyPair().getAddress(), this.address, ABI, "get", Arrays.asList());
  }
}

There is SdkBeanConfig.java under the config folder, which has aclient() method. The bean injected is the Client object corresponding to HelloWorldService.java


@Configuration
@Slf4j
public class SdkBeanConfig {
    
    

    @Autowired
    private SystemConfig config;

    @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);
                configCryptoMaterial(property,certPath);

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

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

                configCryptoKeyPair(client);
                log.info("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());
    }

    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);
    }

    public void configCryptoMaterial(ConfigProperty configProperty,String certPath) {
    
    
        Map<String, Object> cryptoMaterials = new HashMap<>();
        cryptoMaterials.put("certPath", certPath);
        configProperty.setCryptoMaterial(cryptoMaterials);
    }

    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));
    }
}

Write a Controller layer to test methods

Let's create a new TestController.java to test whether the two methods of the contract can be called successfully.

as follows


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.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.yijiuyiyi.HelloWorld.model.bo.HelloWorldSetInputBO;
import org.yijiuyiyi.HelloWorld.service.HelloWorldService;

@RestController
public class TestController {
    
    
    
    
    @Autowired
    private HelloWorldService helloWorldService;
    
    @PostMapping("/set")
    public  TransactionResponse  set(@RequestBody HelloWorldSetInputBO dto) throws Exception {
    
    

        TransactionResponse result = helloWorldService.set(dto);
        
        return result;
    }
    
    @GetMapping("/get")
    public  CallResponse  get() throws Exception {
    
    
        CallResponse response = helloWorldService.get();
        
        return response;
    }
}

Testing process

Startup project
Insert image description here

Use postman to test the set method
Insert image description here
The returned data is

{
    
    
    "returnCode": 0,
    "returnMessage": "Success",
    "transactionReceipt": {
    
    
        "transactionHash": "0xa8ef9e7d336cad7e5e1866e3ac69caa58c46af0cb5364877c797433edbc437ad",
        "transactionIndex": "0x0",
        "root": "0x09c34e425a209106252eddaa8791c053312d30ae1ddc3432f1827b218adfe6dd",
        "blockNumber": "0x767",
        "blockHash": "0x564b98257e5352a1c61b5c5b648254781fec21938302839670faf7a9f493e24c",
        "from": "0xac1c2d0b763bcc592a886ea9cd7e86cf15a689a5",
        "to": "0xbdc8ef2968e775d68aad1480bb39fe19def2f4b7",
        "gasUsed": "0x7235",
        "contractAddress": "0x0000000000000000000000000000000000000000",
        "logs": [],
        "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "status": "0x0",
        "statusMsg": "None",
        "input": "0x4ed3885e000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000087465737474657374000000000000000000000000000000000000000000000000",
        "output": "0x",
        "txProof": null,
        "receiptProof": null,
        "message": null,
        "statusOK": true
    },
    "contractAddress": "0x0000000000000000000000000000000000000000",
    "values": "[]",
    "events": "{}",
    "receiptMessages": "Success",
    "returnObject": [],
    "returnABIObject": [],
    "valuesList": []
}

Use postman to test the get method
Insert image description here
Return data

{
    
    
    "returnCode": 0,
    "returnMessage": "Success",
    "values": "[\"testtest\"]",
    "returnObject": [
        "testtest"
    ],
    "returnABIObject": [
        {
    
    
            "name": "",
            "type": "VALUE",
            "valueType": "STRING",
            "numericValue": null,
            "bytesValue": null,
            "bytesLength": 0,
            "addressValue": null,
            "boolValue": null,
            "dynamicBytesValue": null,
            "stringValue": {
    
    
                "value": "testtest",
                "typeAsString": "string"
            },
            "listType": null,
            "listValues": null,
            "listLength": 0,
            "listValueType": null,
            "structFields": null,
            "dynamic": true
        }
    ]
}

It can be seen that the two methods are successfully called. Usually, after calling the contract method, its data needs to be processed, such as judging its transaction status, or extracting the data that needs to be displayed. There is no need to display all transaction data. .

Conclusion

This method is more convenient to call the contract. We only need to use WeBASE to help us configure the project file. In the next article, I will introduce the second method to use JavaSDK to call the contract.

Guess you like

Origin blog.csdn.net/weixin_52865146/article/details/133267309