以太坊钱包开发(二)

全栈工程师修炼  2018-12-06  新手入门/区块链知识栏目  
七.使用keystore存储地址和私钥的方式开发钱包(不使用助记词)

  使用keystore方式开发以太坊钱包是可以不需要助记词这一类的东西的,咱们将使用ethereumjs中的keythereum、ethereumjs-tx和web3js来开发钱包,webjs是和web3j类似的一个NodeJs库。咱们此处的钱包开发只是把生成keystore,导出导入keystore,导入导出私钥,交易签名,发送转账和转账确定的片段的nodeJS代码编写出来,如何你想学习怎么用keythereum、ethereumjs-tx和web3js开发一个以太坊钱包,请阅读本书的项目实战一。项目实战一部分将详细地讲解一个以太坊钱包的设计,开发,测试和上线部署的整个流程。我们的这个钱包将实现的本地私钥的存储,私钥将由钱包的客户端进行管理。

1.keystore

  下面的代码是按照keystore相关的代码,包含了生成keystore,导出导入keystore,导入导出私钥。这是笔者基于NodeJs封装的一个模块库,如果你有需求,可以直接使用

const keythereum = require("keythereum"); const fs = require('fs'); var libKeystore = {}; const paramsErr = {code:1000, message:"input params is null"}; const createDkErr = {code:1001, message:"create dk error"}; const createKeystoreErr = {code:1002, message:"create keystore fail"}; /** * @param password * @returns {*} */ // 生成keystore libKeystore.createKeystore = function (password) {    if(!password) {        return paramsErr;    }    var keystore = '';    var params = { keyBytes: 32, ivBytes: 16 };    var dk = keythereum.create(params);    var kdf = "pbkdf2";    var options = {        kdf: "pbkdf2",        cipher: "aes-128-ctr",        kdfparams: {            c: 262144,            dklen: 32,            prf: "hmac-sha256"        }    };    var dk = keythereum.create(params)    if (!dk) {        return createDkErr;    }    keystore = keythereum.dump(password, dk.privateKey, dk.salt, dk.iv, options);    if(!keystore) {        return createKeystoreErr;    }    return keystore; } /** * @param keyObject * @param path if your path is null, export keystore by default way; if path has value, export keystore by your way * @returns {{code: number, message: string}} */ // 导出keystore libKeystore.exportKeystore = function(keyObject, path) {    if(!keyObject) {        return paramsErr;    }    if(!path){        keythereum.exportToFile(keyObject);    } else {        var json = JSON.stringify(keyObject);        var outfile = keythereum.generateKeystoreFilename(keyObject.address);        var outpath = path "/" outfile;        console.log(outpath);        fs.writeFile(outpath, json, function (err) {            if (err) {                return err;            } else{                outpath;            }        });    } } /** * @param address * @param datadir * @returns {*} */ // 导入keystore libKeystore.importKeystore = function(address, datadir) {    if(!address || !datadir) {        return paramsErr;    }    return keythereum.importFromFile(address, datadir); } /** * @param keyObject * @param password * @returns {*} */ // 导出私钥 libKeystore.exportPrivateKey = function(keyObject, password) {    if(!keyObject || !password) {        return paramsErr;    }    return keythereum.recover(password, keyObject); } /** * @param privateKey * @param password * @returns {*} */ // 导入私钥并生成keystore libKeystore.importPrivateKey = function(privateKey ,password) {    if(!password || privateKey) {        return paramsErr;    }    var keystore = '';    var params = { keyBytes: 32, ivBytes: 16 };    var dk = keythereum.create(params);    var kdf = "pbkdf2";    var options = {        kdf: "pbkdf2",        cipher: "aes-128-ctr",        kdfparams: {            c: 262144,            dklen: 32,            prf: "hmac-sha256"        }    };    var dk = keythereum.create(params)    if (!dk) {        return createDkErr;    }    keystore = keythereum.dump(password, privateKey, dk.salt, dk.iv, options);    if(!keystore) {        return createKeystoreErr;    }    return keystore; } module.exports = libKeystore;4.交易签名

  以下代码是以太坊交易签名的代码

const util = require('ethereumjs-util'); const transaction = require('ethereumjs-tx'); var ethOrErc20Sign = {}; /** * @param privateKey * @param nonce * @param toAddress * @param sendAmount * @param gasPrice * @param gasLimit * @returns {*} */ ethOrErc20Sign.ethereumSign = function (privateKey, nonce, toAddress, sendAmount, gasPrice, gasLimit) {    var errData = {code:400, message:"param is null"};    var serializedErr = {code:400, message:"Serialized transaction fail"};    if(!privateKey || !nonce || !toAddress || !sendAmount || !gasPrice || !gasLimit) {        console.log("one of fromAddress, toAddress, sendToBalance, sendFee is null, please give a valid param");        return errData;    } else {        var transactionNonce = parseInt(nonce).toString(16);        var numBalance = parseFloat(sendAmount);        var balancetoWei = web3.toWei(numBalance, "ether");        var oxNumBalance = parseInt(balancetoWei).toString(16);        var gasPriceHex = parseInt(gasPrice).toString(16);        var gasLimitHex = parseInt(gasLimit).toString(16);        var privateKeyBuffer =  Buffer.from(privateKey, 'hex');        var rawTx = {            nonce:'0x' transactionNonce,            gasPrice: '0x' gasPriceHex,            gas:'0x' gasLimitHex,            to:toAddress,            value:'0x' oxNumBalance,        };        alert(JSON.stringify(rawTx));        var tx = new transaction(rawTx);        tx.sign(privateKeyBuffer);        var serializedTx = tx.serialize();        if(serializedTx == null) {            return serializedErr;        } else {            if (tx.verifySignature()) {                console.log('Signature Checks out!');            } else {                return serializedErr;            }        }    }    return '0x' serializedTx.toString('hex'); } module.exports = ethOrErc20Sign;

  解释一下上面的代码,privateKey:是私钥,你在生成账户的过程中生成的私钥,私钥是开启你账户大门的钥匙,请谨慎保管;nonce:交易nonce,是保证交易唯一性的标识;toAddress:转入地址,你要转给的那个用户的账户地址,类似于银行卡号;sendAmount:转账金额; gasPrice和gasLimit请参照上面gas,gasPrice和gasLimit一节处查看。

  代码中的nonce,gasPrice,gas,to,value等一系列的签名参数都是十六进制字符串,前缀加0x;上面的签名代码中,你也可以使用chainId:1,chainId=1表示将交易发到主网。

5.发送交易到区块链网络

  发送签名的交易到区块链网络有很多种方式,可以使用web3j,web3js等库,也可以自己发起一个http请求。咱们这里使用的是web3js发送交易到区块链网络,要使用web3js发送交易到区块链网络。得做下面几件事。

5.1.初始化web3jsvar Web3 = require("web3") if (typeof web3 !== 'undefined'){   web3 = new Web3(web3.currentProvider); }else{   web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); }5.2.获取你的账户上的余额

  获取你账户上的余额的目的是为了在你转账的时候校验一下你是否有足够的钱转出,这样能防止你签名的交易发送失败。

web3.eth.getBalance("0xfa319c8ea9b00513bb1a112de2073263aa92c930", function(err, result){   if (err == null){      console.log('~balance:' result);   }else{      console.log('~balance:' result);   } });

  0xfa319c8ea9b00513bb1a112de2073263aa92c930是账户地址,如果你用的是你的账户,请把这个地址替换成你的地址

5.3.发送交易到区块链网络web3.eth.sendRawTransaction(十六进制的签名串, function (err, hash){   console.log('交易结果:' hash);   if (callback && typeof(callback) === "function"){      if(!err){         callback(null, hash);      }else{         callback(err, null);      }   } });

  “十六进制的签名串”这儿的位置是你签名的字符串转换成十六进制的串,加前缀0x即可

6.转账交易确认

  转账确认有很多种机制来实现,列如利用事件通知机制,区块数确认机制等。在咱项目实战的时候咱们会详细讲解各种确认机制,这里只提供一种简单的确认机制,获取区块数,当你发送交易到区块链网络时,你获取一下当前的区块数量,转完账之后,实时获取区块数量,当你的区块数达到确认的块数之后,可认为转账成功。

  下面是获取区块数量的代码

var bnum = web3.eth.blockNumber; console.log(bnum);八.基于节点的钱包开发

  所谓的基于节点的钱,就是依托钱包节点来开发钱包,你的地址和私钥一系列的信息都存储在钱包节点上,不在本地存储。这种开发钱包的方式总体来说就是调用JSON-RPC接口来开发钱包。咱们这里也是使用web3js来开发,当然你也可以使用HTTP的方式请求接口。

1.创建账户1.1.在钱包节点上创建一个账户

  调用personal.newAccount()函数在钱包节点上生成一个账户keystore,例如:

personal.newAccount("123456")

  生成一个密码为123456的账号地址

1.2.在钱包节点上查看这个账户的地址1.2.1.发送获取账户列表的请求curl -X POST --data '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}'1.2.1.返回账户列表结果{  "id":1,  "jsonrpc": "2.0",  "result": ["0xc94770007dda54cF92009BFF0dE90c06F603a09f"] }

  这里的accounts显示的是你在这个钱包节点上创建的所有用户的地址,取得地址之后,你就可以去创建一笔交易了。

1.3.获取账户余额

  调用eth_getBalance函数获取给出的地址的账户余额

1.3.1.参数

  账户地址 区块数量:latest表示最新区块

params: [   '0xc94770007dda54cF92009BFF0dE90c06F603a09f',   'latest' ]1.3.2.返回值

  返回十六进制的字符,转换成十进制表示的,币的单位是wei

1.3.3.发送请求curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0xc94770007dda54cF92009BFF0dE90c06F603a09f", "latest"],"id":1}'1.3.4.返回结果{  "id":1,  "jsonrpc": "2.0",  "result": "0x0234c8a3397aab58" }1.4.创建交易并发送出去

  在钱包节点上创建交易和在本地签名交易的主要区别就在这里,在钱包节点上创建交易是你把整笔交易发送到钱包节点,钱包节点来完成签名和转账。咱们调用的是eth_sendTransaction函数。

1.4.1.参数

  from:转出地址。 to:转入地址。 gas:交易执行需要提供的气体 gasPrice:每种付费气体的gasPrice的整数 value:转账的金额 data:ERC20代币转账信息数据 nonce:标识交易的nonce,依次递增。

params: [{  "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",  "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",  "gas": "0x76c0", // 30400  "gasPrice": "0x9184e72a000", // 10000000000000  "value": "0x9184e72a", // 2441406250  "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" }]1.4.2.请求curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{see above}],"id":1}'1.4.3.返回结果

  成功返回该笔交易的Hash

{  "id":1,  "jsonrpc": "2.0",  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331" }

  使用eth_getTransactionReceipt函数可以获取到合约地址。

1.5.转账确认

  转账确认有很多种机制来实现,列如利用事件通知机制,区块数确认机制等。在咱项目实战的时候咱们会详细讲解各种确认机制,这里只提供一种简单的确认机制,获取区块数,当你发送交易到区块链网络时,你获取一下当前的区块数量,转完账之后,实时获取区块数量,当你的区块数达到确认的块数之后,可认为转账成功。

  通过调用eth_blockNumber函数来获取区块的数量,改函数返回最新的区块数量

1.5.1.发送请求curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":83}'1.5.2.返回结果{  "id":83,  "jsonrpc": "2.0",  "result": "0xc94" }九.非确定性以太坊钱包开发十.分层确定性以太坊钱包开发

  关于分层确定性钱包的优势,在前面的内容中我们已经介绍过,这里就不再多做介绍了。以太坊在BIP分层协议中的序号是60;关于Bip分层协议的内容,请看BIP分层协议一章的内容。

  下图是ETH在分层协议中的位置

1.本地生成以太坊分层确定性钱包的账户体系

  为了更直观地理解以太坊的地址生成,下面的代码将包含着助记词的东西

var bip39 = require('bip39') var hdkey = require('ethereumjs-wallet/hdkey') var util = require('ethereumjs-util') // 生成助记词 var mnemonic = bip39.generateMnemonic() // 生成随机种子 var seed = bip39.mnemonicToSeed(mnemonic) // 生成钱包私钥 var hdWallet = hdkey.fromMasterSeed(seed) // 生成第一个账户的私钥 var key = hdWallet.derivePath("m/44'/60'/0'/0/0") // 生成地址 var address = util.pubToAddress(key._hdkey._publicKey, true)   // 导出私钥 var privateKey = key._hdkey._privateKey.toString('hex') console.log("address = " address "  privateKey = " privateKey)

  上面生成的地址和私钥,你可以将使用本地数据库或者文件管理起来,具体怎么管理,在咱们后面的项目实战中将详细地说明

2.交易签名

  单个交易签名

function ethereumSign(privateKey, nonce, toAddress, sendToBalance, gasPrice, gasLimit) {  var errData = {code:400, message:"param is null"};  var serializedErr = {code:400, message:"Serialized transaction fail"};  if(!privateKey || !nonce || !toAddress || !sendToBalance || !gasPrice || !gasLimit) {    console.log("one of fromAddress, toAddress, sendToBalance, sendFee is null, please give a valid param");    return errData;  } else {    var transactionNonce = parseInt(nonce).toString(16);    var numBalance = parseFloat(sendToBalance);    var balancetoWei = web3.toWei(numBalance, "ether");    var oxNumBalance = parseInt(balancetoWei).toString(16);    var gasPriceHex = parseInt(gasPrice).toString(16);    var gasLimitHex = parseInt(gasLimit).toString(16);    var privateKeyBuffer =  Buffer.from(privateKey, 'hex');    var rawTx = {      nonce:'0x' transactionNonce,      gasPrice: '0x' gasPriceHex,      gas:'0x' gasLimitHex,      to:toAddress,      value:'0x' oxNumBalance,    };    alert(JSON.stringify(rawTx));    var tx = new transaction(rawTx);    tx.sign(privateKeyBuffer);    var serializedTx = tx.serialize();    if(serializedTx == null) {      return serializedErr;    } else {      if (tx.verifySignature()) {        console.log('Signature Checks out!');      } else {        return serializedErr;      }    }  }  return '0x' serializedTx.toString('hex'); }

  多笔转账签名

function MultiEthSign(sendData) {  if(sendData == null) {    console.log("param is invalid, sendData is null");  }  console.log("param is valid, start multiSign transaction");  var calcNonce = sendData.nonce;  var arrData = sendData.signDta;  var outArr = [];  for(var i = 0; i < arrData.length; i ){    var transactionNonce = parseInt(calcNonce).toString(16);    var balancetoWei = web3.toWei(parseFloat(sendData.signDta[i].totalAmount), "ether");    var balanceValue = parseInt(balancetoWei).toString(16);    var oxGas = parseInt(sendData.gasLimit).toString(16);    var oxGasPrice = parseInt(sendData.gasPrice).toString(16);    var privateKeyBuffer =  Buffer.from(sendData.privateKey, 'hex');    var rawTx = {      nonce:'0x' transactionNonce,      gasPrice: '0x' oxGasPrice,      gas:'0x' oxGas,      to: sendData.signDta[i].toAddress,      value:'0x' balanceValue    };    var tx = new transaction(rawTx);    tx.sign(privateKeyBuffer);    var serializedTx = tx.serialize();    if(serializedTx == null) {      console.log("Serialized transaction fail")    } else {      outArr = outArr.concat('0x' serializedTx.toString('hex'))      if (tx.verifySignature()) {        console.log('Signature Checks out!')      } else {        console.log("Signature checks fail")      }    }    calcNonce = calcNonce 1;  }  return { signCoin:"ETH", signDataArr:outArr} }

  发送交易和交易确认如果用NodeJs的话和上面的是一致的

  下面咱们使用web3j来发送交易,SSM的代码,使用SpringMVC

  交易发送控制器

   package com.biwork.controller;    import java.util.ArrayList;    import java.util.HashMap;    import java.util.List;    import java.util.Map;    import javax.servlet.http.HttpServletRequest;    import org.apache.commons.lang3.StringUtils;    import org.slf4j.Logger;    import org.slf4j.LoggerFactory;    import org.springframework.beans.factory.annotation.Autowired;    import org.springframework.stereotype.Controller;    import org.springframework.web.bind.annotation.RequestBody;    import org.springframework.web.bind.annotation.RequestMapping;    import org.springframework.web.bind.annotation.ResponseBody;    import org.springframework.web.bind.annotation.RequestMethod;    import com.biwork.entity.RawTx;    import com.biwork.exception.BusiException;    import com.biwork.po.RespPojo;    import com.biwork.po.request.BatchRawTxFlowPojo;    import com.biwork.po.request.RawTxFlowPojo;    import com.biwork.po.RawTxPojo;    import com.biwork.service.RawTxService;    import com.biwork.util.Constants;    import io.swagger.annotations.Api;    import io.swagger.annotations.ApiOperation;    import io.swagger.annotations.ApiParam;    @Controller    @RequestMapping("/v1")    @Api(value = "/v1", description = "发送签名后交易数据到区块链网络")    public class RawTxController {        private Logger logger = LoggerFactory.getLogger(getClass());        //发送签名后交易到区块链网络        @Autowired        RawTxService rawTxService;        @ResponseBody        @RequestMapping(value = "/eth_sendBatchRawTransaction", method=RequestMethod.POST, produces="application/json;charset=utf-8;")        @ApiOperation(value = "批量发送签名后交易数据到以太坊区块链网络", notes = "批量发送签名后交易数据到以太坊区块链网络",httpMethod = "POST")        public RespPojo getBatchEthRawTx(HttpServletRequest request, @RequestBody                @ApiParam(name="发送签名后交易对象",value="传入json格式",required=true) BatchRawTxFlowPojo batchRwatxFlowPojo){            logger.info("---批量发送签名后交易数据到以太坊区块链网络---");            RawTxPojo rawTx_pojo=new RawTxPojo();            RespPojo resp=new RespPojo();            String signCoin = batchRwatxFlowPojo.getSignCoin();            List<String> arrList = new ArrayList<>();            arrList = batchRwatxFlowPojo.getSignDataArr();            System.out.println("signCoin = " signCoin);            System.out.println("sign = " arrList.get(0));            if(StringUtils.isBlank(signCoin) || arrList.size() == 0){                  resp.setRetCode(Constants.PARAMETER_CODE);                  resp.setRetMsg("批量签名后数据不能为空");                  return resp;            }            RawTx rawTx;            List<String> hashArray = new ArrayList<>();            try {                for(int i = 0; i < arrList.size(); i ) {                    rawTx = rawTxService.getEthRawTx(arrList.get(i));                    hashArray.add(rawTx.getRawTx());                }            }catch(BusiException e){                 logger.error("批量发送签名后交易数据到以太坊区块链网络异常-业务异常{}",e);                  resp.setRetCode(e.getCode());                  resp.setRetMsg(e.getMessage());                  return resp;            }            catch (Exception e) {                  logger.error("批量发送签名后交易数据到以太坊区块链网络异常-普通异常{}",e);                  resp.setRetCode(Constants.FAIL_CODE);                  resp.setRetMsg(Constants.FAIL_MESSAGE);                  return resp;            }            resp.setRetCode(Constants.SUCCESSFUL_CODE);            resp.setRetMsg(Constants.SUCCESSFUL_MESSAGE);            resp.setData(hashArray);            System.out.println("hashArray = " hashArray);            return resp;        }        @ResponseBody        @RequestMapping(value = "/eth_sendRawTransaction", method=RequestMethod.POST, produces="application/json;charset=utf-8;")        @ApiOperation(value = "发送签名后交易数据到以太坊区块链网络", notes = "发送签名后交易数据到以太坊区块链网络",httpMethod = "POST")        public RespPojo getEthRawTx(HttpServletRequest request, @RequestBody                @ApiParam(name="发送签名后交易对象",value="传入json格式",required=true) RawTxFlowPojo rwatxFlowPojo){            logger.info("---发送签名后交易数据到以太坊区块链网络方法---");            RawTxPojo rawTx_pojo=new RawTxPojo();            RespPojo resp=new RespPojo();            String data = rwatxFlowPojo.getData();            System.out.println("data = " data);            if(StringUtils.isBlank(data)){                  resp.setRetCode(Constants.PARAMETER_CODE);                  resp.setRetMsg("签名后数据不能为空");                  return resp;            }            RawTx rawTx;            try {                rawTx = rawTxService.getEthRawTx(data);            }catch(BusiException e){                 logger.error("发送签名后交易数据到以太坊区块链网络异常{}",e);                  resp.setRetCode(e.getCode());                  resp.setRetMsg(e.getMessage());                  return resp;            }            catch (Exception e) {                  logger.error("发送签名后交易数据到以太坊区块链网络异常{}",e);                  resp.setRetCode(Constants.FAIL_CODE);                  resp.setRetMsg(Constants.FAIL_MESSAGE);                  return resp;            }            if(rawTx!=null){                rawTx_pojo = new RawTxPojo();                rawTx_pojo.setRawTx(rawTx.getRawTx());                Map<String, Object> rtnMap = new HashMap<String, Object>();                rtnMap.put("transactionHash", rawTx.getRawTx());                resp.setRetCode(Constants.SUCCESSFUL_CODE);                resp.setRetMsg(Constants.SUCCESSFUL_MESSAGE);                resp.setData(rtnMap);                return resp;            }            return resp;        }        @ResponseBody        @RequestMapping(value="/btc_sendRawTransaction", method=RequestMethod.POST, produces="application/json;charset=utf-8;") @ApiOperation(value = "发送签名后交易数据到BTC区块链网络", notes = "发送签名后交易数据到BTC区块链网络",httpMethod = "POST")        public RespPojo getBtcRawTx(HttpServletRequest request,@RequestBody                @ApiParam(name="流程对象",value="传入json格式",required=true) RawTxFlowPojo rwatxFlowPojo){            logger.info("---发送签名后交易数据到BTC区块链网络方法---");            RawTxPojo rawTx_pojo=new RawTxPojo();            RespPojo resp=new RespPojo();            String data = rwatxFlowPojo.getData();            System.out.println("data = " data);            if(StringUtils.isBlank(data)){                  resp.setRetCode(Constants.PARAMETER_CODE);                  resp.setRetMsg("签名后数据不能为空");                  return resp;            }            RawTx rawTx;            try {                rawTx = rawTxService.getBtcRawTx(data);            }catch(BusiException e){                 logger.error("发送签名后交易数据到BTC区块链网络异常{}",e);                  resp.setRetCode(e.getCode());                  resp.setRetMsg(e.getMessage());                  return resp;            }            catch (Exception e) {                  logger.error("发送签名后交易数据到BTC区块链网络异常{}",e);                  resp.setRetCode(Constants.FAIL_CODE);                  resp.setRetMsg(Constants.FAIL_MESSAGE);                  return resp;            }            if(rawTx!=null){                rawTx_pojo = new RawTxPojo();                rawTx_pojo.setRawTx(rawTx.getRawTx());                Map<String, Object> rtnMap = new HashMap<String, Object>();                rtnMap.put("transactionHash", rawTx.getRawTx());                resp.setRetCode(Constants.SUCCESSFUL_CODE);                resp.setRetMsg(Constants.SUCCESSFUL_MESSAGE);                resp.setData(rtnMap);                return resp;            }            return resp;        }    }  

  服务的代码

package com.biwork.service.Impl; import org.springframework.stereotype.Service; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.biwork.entity.RawTx; import com.biwork.service.RawTxService; import org.web3j.protocol.Web3j; import org.web3j.protocol.core.methods.response.EthSendTransaction; import org.web3j.protocol.http.HttpService; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import com.biwork.exception.BusiException; import com.biwork.util.HttpUtil; import com.neemre.btcdcli4j.core.BitcoindException; import com.neemre.btcdcli4j.core.CommunicationException; import com.neemre.btcdcli4j.core.client.BtcdClient; import com.neemre.btcdcli4j.core.client.BtcdClientImpl; import java.util.HashMap; import java.util.Map; import java.util.Properties; @Service("RawTxService") public class RawTxServiceImpl implements RawTxService {    static Logger log = LoggerFactory.getLogger(RawTxService.class);    private static final String PRO_URL = "https://mainnet.infura.io/PVMw2QL6TZTb2TTgIgrs";    @Override    public RawTx getEthRawTx(String data) throws Exception {        RawTx rawTx = new RawTx();        Web3j web3j = Web3j.build(new HttpService(PRO_URL, true));        EthSendTransaction ethSendTransaction = new EthSendTransaction();        String hash = "";        try {            ethSendTransaction = web3j.ethSendRawTransaction(data).send();        } catch (IOException e) {            e.printStackTrace();        }        if (ethSendTransaction.hasError()) {            throw new BusiException(Integer.toString(ethSendTransaction.getError().getCode()), ethSendTransaction.getError().getMessage());        } else {            hash = ethSendTransaction.getTransactionHash();        }        rawTx.setRawTx(hash);        return rawTx;    }    @Override    public RawTx getBtcRawTx(String data) throws Exception {        RawTx rawTx = new RawTx();        String txid = "";        Map<String,String> params=new HashMap<String,String>();        System.out.println("dataTwo = " data);        params.put("tx", data);         try {             txid =  HttpUtil.testPost(params, "https://blockchain.info/pushtx");             System.out.println("txid =" txid);         } catch (Exception e) {             throw new BusiException("pushtx",  e.getMessage());         }        rawTx.setRawTx(txid);        return rawTx;    } }

  到目前为止,以太坊钱包开发一章算是完成,想要学习更多的内容,请继续关注,项目实战中将会有更多的干货。

版权信息
作者:郭世江
来源:全栈工程师修炼

关于我们

联系我们

作者进驻

手机版

Copyright © 2013 比特巴 www.btb8.com
始建于2013年,提供比特币 区块链及数字货币新闻、技术教程、测评、项目周报、人物等资讯
本页面提供的是新手入门教程资讯,提供入门级的比特币知识、区块链知识以及各类数字货币知识,是数字货币爱好者入门、精通的好导师。