web3j实现离线发起交易

1 使用web3j发起交易的俩种方式

使用web3j封装的json-RPC方法来访问geth客户端,并且向geth端发起交易,可以有俩种方式方式来发起交易的方法。方式1,用户解锁用的keyStore文件保存在geth节点上,用户使用解锁账户的方式发起交易,这种方式适用于中心化的方式比如交易所。方式2,用户的keyStore文件存在本地,用户使用钱包文件给交易签名的方式来发起交易,这种方式适用于DApp方式比如imToken等。

2 使用解锁方式发起交易

解锁方式发起交易,用户的钱包文件存在geth节点,发起交易时要先使用密码解锁账户,然后再发起交易。使用该方式来转账以太坊的函数可以写成:

    //以太坊转账
    //from:转出方账户
    //password:转出方密码
    //addrTo:收款账户
    //value:转账额
    public  String transferEth(String from,String password,String to,BigInteger value) throws  Exception
    {
        EthGetTransactionCount ethGetTransactionCount = ethClient.ethGetTransactionCount(
                from, DefaultBlockParameterName.LATEST).sendAsync().get();
        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
       PersonalUnlockAccount personalUnlockAccount = ethClient.personalUnlockAccount(from,password).send();
       if (personalUnlockAccount.accountUnlocked())//解锁账户,需要钱包文件存在要访问的geth节点上
        {
            BigInteger gasPrice = Contract.GAS_PRICE;
            //BigInteger gasPrice = new BigInteger("12000000000000");
            BigInteger gasLimit = new BigInteger("90000");//Contract.GAS_LIMIT.divide(new BigInteger("2"));
            synchronized(TestLocal.class) {
                Transaction transaction = Transaction.createEtherTransaction(from,nonce,gasPrice,gasLimit,to,value);
                EthSendTransaction transactionResponse = ethClient.ethSendTransaction(transaction).sendAsync().get();;
                if(transactionResponse.hasError()){
                    String message=transactionResponse.getError().getMessage();
                    System.out.println("transaction failed,info:"+message);
                    Utils.writeFile("F:/testErr.txt","transaction failed,info:"+message);
                    return message;
                }else{
                    String hash=transactionResponse.getTransactionHash();
                    EthGetTransactionReceipt send = ethClient.ethGetTransactionReceipt(hash).send();
                    System.out.println("transaction from "+from+" to "+to+" amount:"+value);
                    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    Utils.writeFile("F:/log1.txt","transaction from "+from+" to "+to+" amount:"+value+" time:"+df.format(new Date()));

                    //use this code to get gasUsed and gasPrice
                    BigInteger gas_quility = ethClient.ethEstimateGas(transaction).send().getAmountUsed();
                    BigInteger gas_price = ethClient.ethGasPrice().send().getGasPrice();
                    BigInteger bgasUsed = gas_quility.multiply(gas_price);
                    BigDecimal gasUsed = Convert.fromWei(bgasUsed.toString(),Convert.Unit.ETHER);
                    System.out.println("transaction gas_quility:"+gas_quility+",gas_price:"+gas_price+",gasUsed:"+gasUsed);
                    return  hash;
                }
            }

        }
        return null;
    }

使用该方式来发起智能合约转账的方式:

    //调用Test智能合约的算法函数来批量转账以太币
    //fromAddress:转出方地址 toAddressList:转入方地址列表
    //scoresList:分数列表  sum:分母   amount:分配额度,转出金额=ratio*amount/sum
    //password:fromAddress的密码   coinTypeAddress:合约地址
    public String multiTransferEther_Test(List<Address> toAddressList, List<Uint256> moneyList,BigInteger sum,String fromAddress,String password, String coinTypeAddress) throws  Exception{
        EthGetTransactionCount ethGetTransactionCount = ethClient.ethGetTransactionCount(
                fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get();
        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
        if(gNoce == null)
            gNoce = nonce;
        BigInteger gasPrice = Contract.GAS_PRICE;
        //BigInteger gasLimit = Contract.GAS_LIMIT.divide(new BigInteger("5"));
        BigInteger gasLimit = new BigInteger("90000");
                List<Type> inputParameters = new ArrayList<>();
        inputParameters.add(new DynamicArray(toAddressList));
        inputParameters.add(new DynamicArray(moneyList));
        inputParameters.add(new Uint256(sum));

        Function function = new Function("batchTransferEther",
                inputParameters,
                Collections.<TypeReference<?>>emptyList());
        String functionEncoder = FunctionEncoder.encode(function);
        PersonalUnlockAccount personalUnlockAccount = ethClient.personalUnlockAccount(fromAddress,password).send();
        if (personalUnlockAccount.accountUnlocked()) {//解锁账户,需要钱包文件存在要访问的geth节点
            // send a transaction
            Transaction transaction = Transaction.createFunctionCallTransaction(
                    fromAddress, gNoce, gasPrice,
                    gasLimit, coinTypeAddress, new BigInteger("0"),
                    functionEncoder);
            gNoce = gNoce.add(new BigInteger("1"));
            EthSendTransaction transactionResponse =
                    ethClient.ethSendTransaction(transaction).sendAsync().get();
            if(transactionResponse.hasError()){
                String message=transactionResponse.getError().getMessage();
                System.out.println("transaction failed,info:"+message);
                return message;
            }else{
                String hash=transactionResponse.getTransactionHash();
                return  hash;
            }
        }
        return  null;
    }

3 使用钱包文件签名的方式发起交易

使用这种方式需要钱包文件保存在调用端本地,先加载钱包文件来生成钱包许可对象,然后使用钱包许可对象来对只读型交易进行签名。使用该方式发起以太坊转账的交易如下:

   //本地调用keystore文件转账方式
    public void localSendEther(String from,String password,String keyStore,String to,BigInteger value) throws Exception
    {
        //加载本地KeyStore文件生成Credentials对象
        Credentials credentials = WalletUtils.loadCredentials(password,keyStore);
        EthGetTransactionCount ethGetTransactionCount = ethClient.ethGetTransactionCount(
                from, DefaultBlockParameterName.LATEST).sendAsync().get();
        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
        BigInteger gasPrice = new BigInteger("120000000000");
        BigInteger gasLimit = Contract.GAS_LIMIT.divide(new BigInteger("2"));
        //生成RawTransaction交易对象
        RawTransaction rawTransaction  = RawTransaction.createTransaction(nonce,gasPrice,gasLimit,to,value,"abcde123");//可以额外带数据
        //使用Credentials对象对RawTransaction对象进行签名
        byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction,credentials);
        String hexValue = Numeric.toHexString(signedMessage);
        EthSendTransaction ethSendTransaction = ethClient.ethSendRawTransaction(hexValue).sendAsync().get();
        String transactionHash = ethSendTransaction.getTransactionHash();
        if(ethSendTransaction.hasError())
        {
            String message=ethSendTransaction.getError().getMessage();
            System.out.println("transaction failed,info:"+message);
            Utils.writeFile("F:/testErr.txt","transaction failed,info:"+message);
        }
        else
        {
            String hash=ethSendTransaction.getTransactionHash();
            EthGetTransactionReceipt send = ethClient.ethGetTransactionReceipt(hash).send();
            System.out.println("transaction from "+from+" to "+to+" amount:"+value);
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Utils.writeFile("F:/log1.txt","transaction from "+from+" to "+to+" amount:"+value+" time:"+df.format(new Date()));
        }
    }

转账以太坊还有一种不用设置Nonce的简单方式:

    //本地调用keystore文件转账方式,不用设置Nonce和交易费用,相当于geth客户端的eth.sendTransaction
    public String localTransferEther(String password,String keyStore,String to,BigInteger value) throws Exception
    {
        Credentials credentials = WalletUtils.loadCredentials(password,keyStore);
        try{
            TransactionReceipt transactionReceipt = Transfer.sendFunds(ethClient, credentials, to,
                    new BigDecimal(value), Convert.Unit.WEI).send();
            return transactionReceipt.getTransactionHash();
        }catch (Exception e)//转账失败会打印错误信息
        {
            System.out.println(e);
            return e.toString();
        }
    }

对智能合约转账进行签名的函数:

   //在本地调用智能合约实现批量转账
    public void multiTransferEtherLocal(List<Address> toAddressList, List<Uint256> scoresList, BigInteger sum,String from,String keyStore,String password, String contractAddress) throws  Exception
    {
        Credentials credentials = WalletUtils.loadCredentials(password,keyStore);
        EthGetTransactionCount ethGetTransactionCount = ethClient.ethGetTransactionCount(
                from, DefaultBlockParameterName.LATEST).sendAsync().get();
        BigInteger nonce = ethGetTransactionCount.getTransactionCount();
        //BigInteger gasPrice = Contract.GAS_PRICE;
        BigInteger gasPrice = new BigInteger("12000000000000");
        BigInteger gasLimit = new BigInteger("90000");

        List<Type> inputParameters = new ArrayList<>();
        inputParameters.add(new DynamicArray(toAddressList));
        inputParameters.add(new DynamicArray(scoresList));
        inputParameters.add(new Uint256(sum));

        Function function = new Function("batchTransferEther",
                inputParameters,
                Collections.<TypeReference<?>>emptyList());
        String functionEncoder = FunctionEncoder.encode(function);
        
        RawTransaction transaction = RawTransaction.createTransaction(nonce,gasPrice,gasLimit,contractAddress,functionEncoder);
        byte[] signedMessage = TransactionEncoder.signMessage(transaction,credentials);
        String hexValue = Numeric.toHexString(signedMessage);
        EthSendTransaction ethSendTransaction = ethClient.ethSendRawTransaction(hexValue).sendAsync().get();
        String transactionHash = ethSendTransaction.getTransactionHash();
        if(ethSendTransaction.hasError())
        {
            String message=ethSendTransaction.getError().getMessage();
            System.out.println("transaction failed,info:"+message);
            Utils.writeFile("F:/testErr.txt","transaction failed,info:"+message);
        }
        else
        {
            String hash=ethSendTransaction.getTransactionHash();
            EthGetTransactionReceipt send = ethClient.ethGetTransactionReceipt(hash).send();
            System.out.println("multiTransferEtherLocal send success");
        }
    }




评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值