SpringBoot区块链之以太坊开发(整合Web3j)

最近公司需要ETH兑换功能,ETH转账需要区块打包,这个时候就需要区块检测,目前只是简单整合,后面会将区块自动检测代码上传致QQ群对于区块链开发不太熟悉的童鞋,可以看看:区块链开发(零)如何开始学习以太坊及区块链欢迎大家加企鹅群一起讨论:260532022首先引入一下依赖pom.xml,主要依赖是 org.web3j



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.8.RELEASE
         
    
    com.xiaobin
    eth-demo
    0.0.1-SNAPSHOT
    eth-demo
    Demo project for Spring Boot

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
        
            org.projectlombok
            lombok
            true
        
        
            org.web3j
            core
            3.4.0
        

        
            com.github.briandilley.jsonrpc4j
            jsonrpc4j
            1.4.6
        
        
            com.mashape.unirest
            unirest-java
            1.4.9
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

接下来在application.yml文件中配置以太坊节点路径,这个节点可以使用测试节点

spring:
  application:
    name: xiaobin-eth-demo
server:
  port: 8080
web3j:
  client-address: http://localhost:8545

再就是需要将Web3j对象交给Spring进行管理

package com.xiaobin.ethdemo.config;

import com.googlecode.jsonrpc4j.JsonRpcHttpClient;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
 * 创建时间: 2019/9/23  23:21
 * 备注:
 * 码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事
 **/
@Configuration
public class EthConfig {


    @Value("${web3j.client-address}")
    private String rpc;

    @Bean
    public Web3j web3j() {
        OkHttpClient.Builder builder = new OkHttpClient.Builder();
        builder.connectTimeout(30*1000, TimeUnit.MILLISECONDS);
        builder.writeTimeout(30*1000, TimeUnit.MILLISECONDS);
        builder.readTimeout(30*1000, TimeUnit.MILLISECONDS);
        OkHttpClient httpClient = builder.build();
        Web3j web3j = Web3j.build(new HttpService(rpc,httpClient,false));
        return web3j;
    }
}

Controller测试一下

package com.xiaobin.ethdemo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthBlockNumber;


/**
* 创建时间: 2019/9/23  23:32
* 备注:
* 码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事
**/
@RestController
@RequestMapping("/eth")
public class WalletController {
    @Autowired
    private Web3j web3j;


    @GetMapping("height")
    public long getHeight() {
        try {
            EthBlockNumber blockNumber = web3j.ethBlockNumber().send();
            long blockHeight = blockNumber.getBlockNumber().longValue();
            return blockHeight;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}

获取当前以太坊节点高度,访问结果图SpringBoot区块链之以太坊开发(整合Web3j)_第1张图片

当然还有更多的方法,这里没有去测试了,大家有空可以自己测测哦

获取账户的Nonce

public static BigInteger getNonce(Web3j web3j, String addr) {
        try {
            EthGetTransactionCount getNonce = web3j.ethGetTransactionCount(addr, DefaultBlockParameterName.PENDING).send();

            if (getNonce == null){
                throw new RuntimeException("net error");
            }
            return getNonce.getTransactionCount();
        } catch (IOException e) {
            throw new RuntimeException("net error");
        }
    }

获取ETH余额

public static BigInteger getNonce(Web3j web3j, String addr) {
        try {
            EthGetTransactionCount getNonce = web3j.ethGetTransactionCount(addr, DefaultBlockParameterName.PENDING).send();

            if (getNonce == null){
                throw new RuntimeException("net error");
            }
            return getNonce.getTransactionCount();
        } catch (IOException e) {
            throw new RuntimeException("net error");
        }
    }

获取代币余额

public static BigInteger getTokenBalance(Web3j web3j, String fromAddress, String contractAddress) {

        String methodName = "balanceOf";
        List inputParameters = new ArrayList<>();
        List> outputParameters = new ArrayList<>();
        Address address = new Address(fromAddress);
        inputParameters.add(address);

        TypeReference typeReference = new TypeReference() {
        };
        outputParameters.add(typeReference);
        Function function = new Function(methodName, inputParameters, outputParameters);
        String data = FunctionEncoder.encode(function);
        Transaction transaction = Transaction.createEthCallTransaction(fromAddress, contractAddress, data);

        EthCall ethCall;
        BigInteger balanceValue = BigInteger.ZERO;
        try {
            ethCall = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
            List results = FunctionReturnDecoder.decode(ethCall.getValue(), function.getOutputParameters());
            balanceValue = (BigInteger) results.get(0).getValue();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return balanceValue;
    }

转账ETH

public static String transferETH(Web3j web3j, String fromAddr, String privateKey, String toAddr, BigDecimal amount, String data){
        // 获得nonce
        BigInteger nonce = getNonce(web3j, fromAddr);
        // value 转换
        BigInteger value = Convert.toWei(amount, Convert.Unit.ETHER).toBigInteger();

        // 构建交易
        Transaction transaction = Transaction.createEtherTransaction(fromAddr, nonce, gasPrice, null, toAddr, value);
        // 计算gasLimit
        BigInteger gasLimit = getTransactionGasLimit(web3j, transaction);

        // 查询调用者余额,检测余额是否充足
        BigDecimal ethBalance = getBalance(web3j, fromAddr);
        BigDecimal balance = Convert.toWei(ethBalance, Convert.Unit.ETHER);
        // balance < amount   gasLimit ??
        if (balance.compareTo(amount.add(new BigDecimal(gasLimit.toString()))) < 0) {
            throw new RuntimeException("余额不足,请核实");
        }

        return signAndSend(web3j, nonce, gasPrice, gasLimit, toAddr, value, data, chainId, privateKey);
    }

对交易签名,并发送交易

public static String signAndSend(Web3j web3j, BigInteger nonce, BigInteger gasPrice, BigInteger gasLimit, String to, BigInteger value, String data, byte chainId, String privateKey) {
        String txHash = "";
        RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, gasPrice, gasLimit, to, value, data);
        if (privateKey.startsWith("0x")){
            privateKey = privateKey.substring(2);
        }

        ECKeyPair ecKeyPair = ECKeyPair.create(new BigInteger(privateKey, 16));
        Credentials credentials = Credentials.create(ecKeyPair);

        byte[] signMessage;
        if (chainId > ChainId.NONE){
            signMessage = TransactionEncoder.signMessage(rawTransaction, chainId, credentials);
        } else {
            signMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
        }

        String signData = Numeric.toHexString(signMessage);
        if (!"".equals(signData)) {
            try {
                EthSendTransaction send = web3j.ethSendRawTransaction(signData).send();
                txHash = send.getTransactionHash();
                System.out.println(JSON.toJSONString(send));
            } catch (IOException e) {
                throw new RuntimeException("交易异常");
            }
        }
        return txHash;
    }

有什么问题或者缺少什么依赖包,可以加QQ群哦

码农自学交流小群:260532022,欢迎大家的加入,分享学习是一件开心事

你可能感兴趣的