草庐IT

区块链之java调用智能合约(一)编译智能合约

paul.peng 2023-04-05 原文

前言

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

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

提问

1.Solidity是什么?

2.java如何调用Solidity?

解答:

1.Solidity是什么呢?

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

展示个小案例。

// SPDX-License-Identifier: GPL-3.0

pragma 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包(具体的版本,到时候看对应的发布)

 <!--web3j-->
    <dependency>
      <groupId>org.web3j</groupId>
      <artifactId>core</artifactId>
      <version>5.0.0</version>
    </dependency>

    <dependency>
      <groupId>org.web3j</groupId>
      <artifactId>codegen</artifactId>
      <version>5.0.0</version>
    </dependency>

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

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

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 的路径)

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

有关区块链之java调用智能合约(一)编译智能合约的更多相关文章

  1. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  2. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  3. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  4. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  5. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  6. ruby - Sinatra set cache_control to static files in public folder编译错误 - 2

    我不知道为什么,但是当我设置这个设置时它无法编译设置:static_cache_control,[:public,:max_age=>300]这是我得到的syntaxerror,unexpectedtASSOC,expecting']'(SyntaxError)set:static_cache_control,[:public,:max_age=>300]^我只想将“过期”header设置为css、javaascript和图像文件。谢谢。 最佳答案 我猜您使用的是Ruby1.8.7。Sinatra文档中显示的语法似乎是在Ruby1.

  7. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  8. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  9. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  10. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

随机推荐