以太坊区块链java开发:web3j

以太坊 java开发依赖

        <dependency>
            <groupId>org.web3j</groupId>
            <artifactId>core</artifactId>
            <version>3.5.0</version>
        </dependency>

连接到以太坊同步节点

private String gethURL = "http://localhost:8545";

    private void connectGeth() {
        // --rpcport value HTTP-RPC服务器监听端口(默认值:8545)
        this.web3j = Admin.build(new HttpService(gethURL));
        if(null==web3j) {
            System.out.println("connectGeth error");
        }
    }

创建账户,需要输入密码,返回账户地址 0x00000...

    public String addAccount(String password) {
        // walletId:$|chainId:$|account:$
        if (web3j == null)
            connectGeth();
        String account = "";
        try {

            String fileName = WalletUtils.generateNewWalletFile(password, new File(keystorePath));
            Credentials credentials = WalletUtils.loadCredentials(password, keystorePath + "/" + fileName);
            account = credentials.getAddress();

        } catch (InvalidAlgorithmParameterException e1) {
            e1.printStackTrace();
        } catch (NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (NoSuchProviderException e1) {
            e1.printStackTrace();
        } catch (CipherException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        addCredentials(account, password);
        return account;
    }

以太币(矿币)转账

    private void transfer_ETH(String _from, String password, String _to, BigInteger value, Long logId) {
        Credentials credentials = loadCredentials(_from, password);
        try {
            //获取nonce
            EthGetTransactionCount count=web3j.ethGetTransactionCount(_from, DefaultBlockParameterName.LATEST).send();
            BigInteger nonce=count.getTransactionCount();
            //创建交易
            //BigInteger val=Convert.toWei(new BigDecimal(value), Unit.ETHER).toBigInteger();
            RawTransaction rawTransaction=RawTransaction.createEtherTransaction(nonce, GAS_PRICE, GAS_LIMIT, _to, value);
            //验证签名
            byte[] signMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
            String hexValue=Numeric.toHexString(signMessage);
            //发送交易
            CompletableFuture<EthSendTransaction> sendAsync = web3j.ethSendRawTransaction(hexValue).sendAsync();
            sendAsync.whenComplete((v,e)->{
                //交易回调
                new Thread(() -> {
                    callBackService.callbackEthSendTransaction(v, logId, e);
                }).start();
            });
        }catch(Exception e) {
			
        }
    }

加载已有账户的凭证

keystorePath是凭证文件保存的文件夹地址,例如:/home/geth/keystore

这里读取文件之前,先去全局map(预加载)里检查是否能拿到凭证

    private Credentials loadCredentials(String address,String password){
        Credentials credentials=credentialsMap.get(address);
        if(CommonUtil.isNull(credentials)){
            //往map里加
            credentials=addCredentials(address,password);
        }
        return credentials;
    }
    private  Credentials addCredentials(String address,String password){
        Credentials credentials=null;
        try {
            File file = new File(keystorePath);
            File[] files = file.listFiles();
            if(files!=null && files.length>0){
                for (File f : files) {
                    String a=address.trim().substring(2);
                    if (f.getName().contains(a)) {
                        //取到这个文件,并生成credentials对象
                        credentials = WalletUtils.loadCredentials(password, f);
                        break;
                    }
                }
            }
            if (!CommonUtil.isNull(credentials)){
                credentialsMap.putIfAbsent(address, credentials);
            }else {
                throw new RuntimeException("读取凭证错误,请检查钱包文件是否存在");
            }
        } catch (IOException  | CipherException e) {
            e.printStackTrace();
        }
        return credentials;
    }

以太坊还包括合约发布的代币-虚拟币

加载执行合约也是非常常见的

智能合约由solidity语言开发,可以编译为java文件

可以使用VScode下载solidity插件,将合约编译 .sol ---> .bin .abi .json

使用codegen-3.5.0.jar 的 SolidityFunctionWrapperGenerator.class 的 mian方法

<!-- https://mvnrepository.com/artifact/org.web3j/codegen -->

<dependency>

<groupId>org.web3j</groupId>

<artifactId>codegen</artifactId>

<version>3.5.0</version>

</dependency>

并需要附带参数

#来自https://docs.web3j.io/smart_contracts.html

$ web3j solidity generate [--javaTypes|--solidityTypes] /path/to/<smart-contract>.bin /path/to/<smart-contract>.abi -o /path/to/src/main/java -p com.your.organisation.name
private static final String USAGE = "solidity generate "
    + "[--javaTypes|--solidityTypes] "
    + "<input binary file>.bin <input abi file>.abi "
    + "-p|--package <base package name> "
    + "-o|--output <destination base directory>";

从输出文件夹拿到编译好的java合约代码

调用合约方法 加载合约需要合约地址

//GAS_PRICE可以动态获取
private BigInteger GAS_PRICE = BigInteger.valueOf(22_000_000_000L);
//GAS_LIMIT参数固定
private final BigInteger GAS_LIMIT = BigInteger.valueOf(43_000);
/**
* USDT的转账方法
*/
private void transfer_USDT(String _from, String password, String _to, BigInteger value, Long logId) {
    //拿到凭证
    Credentials credentials = loadCredentials(_from, password);
    //使用凭证加载合约 需要知道合约的地址 这里涉及到GAS 是为交易手续费 从合约调用方账户上扣除以太币
    TetherToken contract = TetherToken.load(USDTAddress, getWeb3j(), credentials, GAS_PRICE, GAS_LIMIT);
    //调用合约方法
    RemoteCall<TransactionReceipt> transfer = contract.transfer(_to, value);
    CompletableFuture<TransactionReceipt> sendAsync = transfer.sendAsync();
    //异步执行 并添加回调方法
    sendAsync.whenComplete((v,e)->{
        new Thread(() -> {
            callBackService.callbackTransactionReceipt(v, logId, e);
        }).start();
    });
}

有一部分合约并不公开源码

在无法编译得到java合约代码的情况下,可以使用 abi+合约二进制代码+合约地址 调用

abi包括一个合约所有方法、参数、返回值

以下做一个简单的示例,并不支持很多参数类型

import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Bool;
import org.web3j.abi.datatypes.Int;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.Uint;
import org.web3j.abi.datatypes.Utf8String;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.tx.Contract;

import com.alibaba.fastjson.JSON;
import okkpp.function.Function;
import okkpp.function.Param;

public class WidelyContract extends Contract {

    private List<Function> functions;

    @SuppressWarnings("deprecation")
    protected WidelyContract(String abi, String contractBinary, String contractAddress, Web3j web3j,
            Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
        super(contractBinary, contractAddress, web3j, credentials, gasPrice, gasLimit);
        this.functions = JSON.parseArray(abi, Function.class);
    }

    public static WidelyContract load(String abi, String contractBinary, String contractAddress, Web3j web3j,
            Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) {
        return new WidelyContract(abi, contractBinary, contractAddress, web3j, credentials, gasPrice, gasLimit);
    }

    @SuppressWarnings("rawtypes")
    public Type<?> excute(String functionName, String... params) throws IOException {
        List<Type> inputs = null;
        List<TypeReference<?>> outputs = null;
        for (Function f : functions) {
            if (functionName.equals(f.getName())) {
                inputs = getInputs(f.getInputs(), params);
                outputs = getOutputs(f.getOutputs());
            }
        }
        return executeCallSingleValueReturn(new org.web3j.abi.datatypes.Function(functionName, inputs, outputs));
    }

    @SuppressWarnings("rawtypes")
    private List<Type> getInputs(List<Param> inputs, String[] params) {
        int size = inputs.size();
        List<Type> result = new ArrayList<Type>();
        for (int i = 0; i < size; i++) {
            result.add(getParam(inputs.get(i).getType(), params[i]));
        }
        return result;
    }

    private List<TypeReference<?>> getOutputs(List<Param> outputs) {
        int size = outputs.size();
        List<TypeReference<?>> result = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            result.add(getType(outputs.get(i).getType()));
        }
        return result;
    }

    private TypeReference<?> getType(String type) {
        switch (type) {
        case "address": {
            return new TypeReference<Address>() {
            };
        }
        case "string": {
            return new TypeReference<Utf8String>() {
            };
        }
        case "bool": {
            return new TypeReference<Bool>() {
            };
        }
        }
        if (type.startsWith("uint")) {
            return new TypeReference<Uint>() {
            };
        }
        if (type.startsWith("int")) {
            return new TypeReference<Int>() {
            };
        }
        return null;
    }

    @SuppressWarnings("rawtypes")
    private Type getParam(String type, String input) {
        switch (type) {
        case "address": {
            return new Address(input);
        }
        case "string": {
            return new Utf8String(input);
        }
        case "bool": {
            return new Bool(input.equals("true"));
        }
        }
        if (type.startsWith("uint")) {
            return new Uint(new BigInteger(input));
        }
        if (type.startsWith("int")) {
            return new Int(new BigInteger(input));
        }
        return null;
    }
}

另附自定义Function类

import java.util.List;

public class Function {

    private boolean constant;
    private String name;
    private boolean payable;
    private String stateMutability;
    private String type;
    private List<Param> inputs;
    private List<Param> outputs;

    public boolean isConstant() {
        return constant;
    }

    public void setConstant(boolean constant) {
        this.constant = constant;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isPayable() {
        return payable;
    }

    public void setPayable(boolean payable) {
        this.payable = payable;
    }

    public String getStateMutability() {
        return stateMutability;
    }

    public void setStateMutability(String stateMutability) {
        this.stateMutability = stateMutability;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public List<Param> getInputs() {
        return inputs;
    }

    public void setInputs(List<Param> inputs) {
        this.inputs = inputs;
    }

    public List<Param> getOutputs() {
        return outputs;
    }

    public void setOutputs(List<Param> outputs) {
        this.outputs = outputs;
    }

    @Override
    public String toString() {
        return "Function [constant=" + constant + ", name=" + name + ", payable=" + payable + ", stateMutability="
                + stateMutability + ", type=" + type + ", inputs=" + inputs + ", outputs=" + outputs + "]";
    }
}

与Param类

public class Param {

    private String name;
    private String type;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Param [name=" + name + ", type=" + type + "]";
    }
}

猜你喜欢

转载自blog.csdn.net/qq_29126023/article/details/84346341