前言

首先,还是一贯的思路,带着问题学习。

在最后,附带上我的Gitee代码,因为国内访问github有时候真的很蛋疼。

提问

1.Solidity是什么?

2.java如何调用Solidity?

解答:

1.Solidity是什么呢?

Solidity是一种语言,为了编写智能合约的一种语言。以*.sol结尾的(类似test.java结尾的java文件)。该语言类似javaScript语法。易上手。

展示个小案例。

// SPDX-License-Identifier: GPL-3.0pragma solidity >=0.7.0 <0.9.0;/*** @title Storage* @dev Store & retrieve value in a variable* @custom:dev-run-script ./scripts/deploy_with_ethers.ts*/contract Storage {uint256 number;/*** @dev Store value in variable* @param num value to store*/function store(uint256 num) public {number = num;}/*** @dev Return value* @return value of 'number'*/function retrieve() public view returns (uint256){return number;}}

其中于java比较不同的是,里面的数据类型及方法访问定义。

Solidity目前的ide有:remix (一款线上的编辑工具),

及基于node环境的vscode(基于vscode编译需要安装Solidity的环境)。

编译器的差别、

remix:

优点:免安装,可直接使用,易上手,集成基础功能。

缺点:没有本地保存,刷新后,会直接清空当前编写的合同,易丢失文件

vscode:

优点:不易丢失文件

缺点:需要安装插件,需要本地部署,安装框架

2.合约部署,这个是属于区块链的东西,针对后端的java攻城狮们,并不是太了解。

那么接下来说的就是,在java中,如何调用智能合约。

首先,java调用智能合约,原理就是,智能合约部署到区块链后,java调用区块链api。

简单理解为,我们就是调用第三方的api。但是呢,区块链针对这块做了很多加密算法的工作。并不像原始的http那样显示的方式直接调用。这里就需要使用到一些java已经封装好的包了。

引入对应的maven包(具体的版本,到时候看对应的发布)

 org.web3jcore5.0.0org.web3jcodegen5.0.0

引入对于的包,是第一步,那么接下来就是如何调用了。

首先可以看一个开源的案例。

https://github.com/web3j/sample-project-gradle

该项目的项目结构为这样的。

该图中,包含了sol文件,及java的调用文件Application。

其中有个问题。

就是虽然导入sol文件,但是在java中,并不属于java文件,这个时候,是无法调用的。

那么,我们需要先将sol文件,转为java文件,然后才能调用。

怎么转呢???

两种方式,

前面的步骤都是一样的。具体的合约编译自行查询下。我知道的暂时就是两种,一种是使用npm下载的Solidity编译,还有一个是使用remix编译。

编写好后,直接在remix中点击编译即可。

编译前:

编译后:(这里需要注意的是,需要选中对应的sol文件,才会对相应的sol文件编译,否则编译按钮会显示灰色,例如下图2显示

编译完后对,就需要获取对应的abi于bin文件了。

点击该abi按钮后,对自动复制的粘贴板中,可直接复制到文件或对于的数据中

点击该bytecode按钮后,对自动复制的粘贴板中,可直接复制到文件或对于的数据中

一、使java插件的web3j库,生成对应的java文件。

首选,需要创建一个生成对于文件的java类。

package org.saiwen.paul.util;import org.web3j.codegen.SolidityFunctionWrapperGenerator;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.util.Arrays;import java.util.stream.Stream;/** * @Author paul.peng * @Date 2022/5/10 * @Version 1.0 */public class SolidityGenerateUtil {// 私有实例,类初始化就加载private static SolidityGenerateUtil solidityGenerateUtil = new SolidityGenerateUtil();// 私有构造方法private SolidityGenerateUtil() {}// 公共的、静态的获取实例方法public static SolidityGenerateUtil getInstance() {return solidityGenerateUtil;}public static void genAbiAndBin(){String abi= "[\n" +"\t{\n" +"\t\t\"inputs\": [],\n" +"\t\t\"name\": \"retrieve\",\n" +"\t\t\"outputs\": [\n" +"\t\t\t{\n" +"\t\t\t\t\"internalType\": \"uint256\",\n" +"\t\t\t\t\"name\": \"\",\n" +"\t\t\t\t\"type\": \"uint256\"\n" +"\t\t\t}\n" +"\t\t],\n" +"\t\t\"stateMutability\": \"view\",\n" +"\t\t\"type\": \"function\"\n" +"\t},\n" +"\t{\n" +"\t\t\"inputs\": [\n" +"\t\t\t{\n" +"\t\t\t\t\"internalType\": \"uint256\",\n" +"\t\t\t\t\"name\": \"num\",\n" +"\t\t\t\t\"type\": \"uint256\"\n" +"\t\t\t}\n" +"\t\t],\n" +"\t\t\"name\": \"store\",\n" +"\t\t\"outputs\": [],\n" +"\t\t\"stateMutability\": \"nonpayable\",\n" +"\t\t\"type\": \"function\"\n" +"\t}\n" +"]";String bin = "{\n" +"\t\"functionDebugData\": {},\n" +"\t\"generatedSources\": [],\n" +"\t\"linkReferences\": {},\n" +"\t\"object\": \"608060405234801561001057600080fd5b50610150806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea2646970667358221220314b4c9cabe40fdbaade24da458a24445455e8c74197270e57df53f1ccf13fea64736f6c63430008070033\",\n" +"\t\"opcodes\": \"PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x150 DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x36 JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x2E64CEC1 EQ PUSH2 0x3B JUMPI DUP1 PUSH4 0x6057361D EQ PUSH2 0x59 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x43 PUSH2 0x75 JUMP JUMPDEST PUSH1 0x40 MLOAD PUSH2 0x50 SWAP2 SWAP1 PUSH2 0xD9 JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST PUSH2 0x73 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x6E SWAP2 SWAP1 PUSH2 0x9D JUMP JUMPDEST PUSH2 0x7E JUMP JUMPDEST STOP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0x97 DUP2 PUSH2 0x103 JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xB3 JUMPI PUSH2 0xB2 PUSH2 0xFE JUMP JUMPDEST JUMPDEST PUSH1 0x0 PUSH2 0xC1 DUP5 DUP3 DUP6 ADD PUSH2 0x88 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH2 0xD3 DUP2 PUSH2 0xF4 JUMP JUMPDEST DUP3 MSTORE POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 ADD SWAP1 POP PUSH2 0xEE PUSH1 0x0 DUP4 ADD DUP5 PUSH2 0xCA JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x10C DUP2 PUSH2 0xF4 JUMP JUMPDEST DUP2 EQ PUSH2 0x117 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 BALANCE 0x4B 0x4C SWAP13 0xAB 0xE4 0xF 0xDB 0xAA 0xDE 0x24 0xDA GASLIMIT DUP11 0x24 DIFFICULTY SLOAD SSTORE 0xE8 0xC7 COINBASE SWAP8 0x27 0xE JUMPI 0xDF MSTORE8 CALL 0xCC CALL EXTCODEHASH 0xEA PUSH5 0x736F6C6343 STOP ADDMOD SMOD STOP CALLER \",\n" +"\t\"sourceMap\": \"199:356:0:-:0;;;;;;;;;;;;;;;;;;;\"\n" +"}";String abiFileName = "Storage.abi";String binFileName = "Storage.bin";generateAbiAndBin(abi,bin,abiFileName,binFileName);}public static void generateAbiAndBin(String abi,String bin,String abiFileName,String binFileName){File abiFile = new File("src/main/"+abiFileName);File binFile = new File("src/main/"+binFileName);BufferedOutputStream abiBos = null;BufferedOutputStream binBos = null;try{FileOutputStream abiFos = new FileOutputStream(abiFile);FileOutputStream binFos = new FileOutputStream(binFile);abiBos = new BufferedOutputStream(abiFos);binBos = new BufferedOutputStream(binFos);abiBos.write(abi.getBytes());abiBos.flush();binBos.write(bin.getBytes());binBos.flush();generateJavaFile(abiFile.getPath(),binFile.getPath());}catch (Exception e){e.printStackTrace();}finally {if(abiBos != null){try{abiBos.close();;}catch (IOException e){e.printStackTrace();}}if(binBos != null){try {binBos.close();}catch (IOException e){e.printStackTrace();}}}}public static void generateJavaFile(String abiFile, String binFile){String generateFile = "src/main/java/org/saiwen/paul/solidity/";generateClass(abiFile,binFile,generateFile);}public static void generateClass(String abiFile,String binFile,String generateFile){String[] args = Arrays.asList("-a",abiFile,"-b",binFile,"-p","","-o",generateFile).toArray(new String[0]);Stream.of(args).forEach(System.out::println);SolidityFunctionWrapperGenerator.main(args);}}

自定义位置启动(genAbiAndBin)方法即可。

然后在项目中,就可以查找到对于的Storage.abi,Storage.bin与Storage.java了。

二、使用web3j命令行,生成对应的java文件

先下载web3j命令行工具。找到对应的zip

然后解压到自己的目录中。

进入bin目录。然后手动创建两个对应的文件。***.abi及***.bin。在把刚刚编译的对应合约码的abi与bytecode码拷贝到相应的文件中。然后在当前目录进入cmd。执行

web3j solidity generate ***.bin ***.abi -o java -p com.eth

用Storage.abi为例。

web3j solidity generate Storage.bin Storage.abi -o java -p com.eth

然后就会在当前目录生成对应的java文件。

git地址:link-sol: 智能合约

然后将java文件导入到项目对应存放的地址即可(记住,导入后需要修改package 的路径)

至此,简单的合约编译,合约导入完成。下一节在讲讲如何调用钱包等。