参考资料
搭建私链
编写创世文件
在要存放私链数据的目录(比如E:\ligl\ethereum\geth\privateChain
)下新建genesis.json
创世文件
{
"config": {
"chainId": 14,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x0200",
"extraData" : "",
"gasLimit" : "0x2fefd8",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00"
}
初始化
使用指令geth --datadir E:\ligl\ethereum\geth\privateChain init genesis.json
可以初始化私链环境,目录下会生成geth
和keystore
两个文件夹,其中keystore
文件夹里面存放的是地址以及加密的私钥组成的keystore文件。
为了方便反复测试,可以在当前目录新建一个init.bat批处理文件如下:
rd/s/q geth
::不删除keystore文件夹,否则密钥需要重新导入
::rd/s/q keystore
geth --datadir E:\ligl\ethereum\geth\privateChain init genesis.json
以后只要双击就可以初始化私链环境。
启动
在当前目录下新建run.bat批处理文件如下:
geth --networkid 14 --nodiscover --datadir "E:\ligl\ethereum\geth\privateChain" --rpc --rpcapi "net,eth,web3,personal" --rpcaddr "10.0.0.154" --rpcport "8545" --rpccorsdomain "*" console
双击运行run.bat
文件即可启动私链。
注意:为了外边可以访问到,rpc服务的ip地址需要设置成本机的ip地址,这样手机端app才能通过ip地址访问到rpc服务。
联调测试交易
手机端APP如何访问到服务端
为了方便,可以将服务端搭建在笔记本电脑上,然后让笔记本电脑开启wifi热点,手机连上热点即可访问服务端的JSON-RPC接口。
如何在win7的笔记本电脑上开启wifi热点
访问服务端需要使用到JSON-RPC接口,这里使用web3j库来实现:
implementation 'org.web3j:core:3.3.1-android'
生成两个ECC的密钥对并导入到私链中
因为Geth服务貌似不支持私钥导出,所以换一种方法,先在外边生成私钥,然后导入到私链中。
使用web3j在手机端来生成私钥代码:
// log test
logBuffer.setLength(0);
try {
ECKeyPair ecKeyPair1 = Keys.createEcKeyPair();
ECKeyPair ecKeyPair2 = Keys.createEcKeyPair();
String address1 = Keys.getAddress(ecKeyPair1);
String address2 = Keys.getAddress(ecKeyPair2);
logBuffer.append("address1=").append(address1);
logBuffer.append("\n(1) pri=").append(ecKeyPair1.getPrivateKey().toString(16));
logBuffer.append("\n(1) pub=").append(ecKeyPair1.getPublicKey().toString(16));
logBuffer.append("\naddress2=").append(address2);
logBuffer.append("\n(2) pri=").append(ecKeyPair2.getPrivateKey().toString(16));
logBuffer.append("\n(2) pub=").append(ecKeyPair2.getPublicKey().toString(16));
} catch (Exception e) {
e.printStackTrace();
logBuffer.append("生成地址error:").append(e);
}
Log.i("test", logBuffer.toString());
showDialogMsg(logBuffer.toString());
运行的log如下:
address1=5378ad743b9263587eb117b0c4658cf03c906baa
(1) pri=d36d0bb6c8f2ec5e3ea59b0b8a17fd78e2091c9e77d2a70267c01cf10a38fc48
(1) pub=34a1d310e41a8b4de639ff48d8edea8702c654207fe93783cede051f261e42e8e33d5180bdd176b45d9dd97120b7b882bd9450322fb9b04ef31cb285a72f347c
address2=370dccebbf4d24059ae57fddbb651259a86a172a
(2) pri=d90b9e5b063cd5d8e56c536c341260048f563c5e8740e071145e72e4208bf883
(2) pub=ece19a85208e5198a412ab2710a992356d837726db7e06d745d31d667339e923e92409c00d17b969545a2557b8cd3869e4fa4d90c3ca23d58c693c34247a1dab
新建一个prv1.txt
文件,将私钥的hex串复制进去保存,然后在服务端的console中使用指令:
geth --datadir E:\ligl\ethereum\geth\privateChain account import E:\ligl\ethereum\geth\privateChain\test_key\prv1.txt
即可导入第一个地址,同理再导入第二个地址。
通过挖矿给第一个地址加钱
在服务端使用指令eth.coinbase
可以获取挖矿的收益地址,第一次运行会默认将上面导入的第一个地址当做挖矿收益地址。
然后使用命令miner.start(1)
启动挖矿,因为创世文件设置的难度特别低,所以很快就能挖到大量的以太币。
使用命令miner.stop()
命令停止挖矿。
编写APP端JSON-RPC的访问代码
手机端测试需要访问JSON-RPC接口,这里使用web3j库来访问。
根据myetherwallet网站开源代码中的接口(接口点这里),模仿写一个java的接口:
EtherNode.java
import java.math.BigInteger;
import rx.Observable;
/**
* 根据myetherwallet.com定义的api接口定义
* 用来实现以太坊的交易以及合同的发布时的网络接口
*/
public interface EtherNode {
/**
* 获取ChainId,用于EIP155签名时用
* @return chainId
*/
int getChainId();
/**
* // Request
* curl -X POST --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":83}'
*
* // Result
* {
* "id":83,
* "jsonrpc": "2.0",
* "result": "0x4b7" // 1207
* }
*
* Returns the number of most recent block.
* @return QUANTITY - integer of the current block number the client is on.
*/
Observable<BigInteger> getCurrentBlock();
/**
* // Request
* curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"],"id":1}'
*
* // Result
* {
* "id":1,
* "jsonrpc": "2.0",
* "result": "0x0234c8a3397aab58" // 158972490234375000
* }
*
* Returns the balance of the account of given address.
* @param address 20 Bytes - address to check for balance.
* @return latest balance
*/
Observable<BigInteger> getBalance(String address);
/**
* // Request
* curl -X POST --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":1}'
*
* // Result
* {
* "id":1,
* "jsonrpc":"2.0",
* "result": {
* "hash":"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
* "nonce":"0x",
* "blockHash": "0xbeab0aa2411b7ab17f30a99d3cb9c6ef2fc5426d6ad6fd9e2a26a6aed1d1055b",
* "blockNumber": "0x15df", // 5599
* "transactionIndex": "0x1", // 1
* "from":"0x407d73d8a49eeb85d32cf465507dd71d507100c1",
* "to":"0x85h43d8a49eeb85d32cf465507dd71d507100c1",
* "value":"0x7f110", // 520464
* "gas": "0x7f110", // 520464
* "gasPrice":"0x09184e72a000",
* "input":"0x603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360",
* }
* }
*
* Returns the information about a transaction requested by transaction hash.
*
* @param transactionHash 32 Bytes - hash of a transaction
* @return
*/
Observable<org.web3j.protocol.core.methods.response.Transaction> getTransaction(String transactionHash);
class TransactionData {
private String address;
private BigInteger balance;
private BigInteger gasPrice;
private BigInteger nonce;
public TransactionData() {}
public TransactionData(String address, BigInteger balance, BigInteger gasPrice, BigInteger nonce) {
this.address = address;
this.balance = balance;
this.gasPrice = gasPrice;
this.nonce = nonce;
}
public String getAddress() {
return address;
}
public BigInteger getBalance() {
return balance;
}
public BigInteger getGasPrice() {
return gasPrice;
}
public BigInteger getNonce() {
return nonce;
}
@Override
public String toString() {
return "TransactionData{" +
"address='" + address + '\'' +
", balance=" + balance +
", gasPrice=" + gasPrice +
", nonce=" + nonce +
'}';
}
}
/**
* 根据MyEtherWallet网站的接口定义,返回一个地址的余额、gasPrice、nonce,看用法应该是用来生成新的交易的时候用的
* 可以分别调用eth_getBalance获取余额,调用eth_gasPrice获取gasPrice,调用eth_getTransactionCount获取nonce
*
* @param address 20 Bytes - address to check for balance.
* @return
*/
Observable<TransactionData> getTransactionData(String address);
/**
* // Request
* curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":[{see above}],"id":1}'
*
* // Result
* {
* "id":1,
* "jsonrpc": "2.0",
* "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
* }
*
* Creates new message call transaction or a contract creation for signed transactions.
* @param signedTransactionData
* @return 交易的hash值
*/
Observable<String> sendRawTransaction(String signedTransactionData);
/**
* // Request
* curl -X POST --data '{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{see above}],"id":1}'
*
* // Result
* {
* "id":1,
* "jsonrpc": "2.0",
* "result": "0x5208" // 21000
* }
*
* Generates and returns an estimate of how much gas is necessary to allow the transaction to complete.
* The transaction will not be added to the blockchain.
* Note that the estimate may be significantly more than the amount of gas actually used by the transaction,
* for a variety of reasons including EVM mechanics and node performance.
*
* @param transaction
* @return the amount of gas used.
*/
Observable<BigInteger> getEstimatedGas(org.web3j.protocol.core.methods.request.Transaction transaction);
/**
*
* // Request
* curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{see above}],"id":1}'
*
* // Result
* {
* "id":1,
* "jsonrpc": "2.0",
* "result": "0x"
* }
*
* Executes a new message call immediately without creating a transaction on the block chain.
* param use 'pending'
* see <a href='https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_call'>https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_call</a>
* @param transaction The transaction call object
* @return the return value of executed contract.
*/
Observable<String> getEthCall(org.web3j.protocol.core.methods.request.Transaction transaction);
}
然后写一个实现CustomNodeImpl.java:
import android.util.Log;
import com.hengbao.hdwallet.network.ether.EtherNode;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.Web3jFactory;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.protocol.core.methods.response.EthCall;
import org.web3j.protocol.core.methods.response.EthEstimateGas;
import org.web3j.protocol.core.methods.response.EthGasPrice;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.EthTransaction;
import org.web3j.protocol.core.methods.response.Transaction;
import org.web3j.protocol.http.HttpService;
import java.math.BigInteger;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import rx.Observable;
import rx.exceptions.Exceptions;
import rx.functions.Func1;
import rx.functions.Func3;
/**
* 符合web3j的JSON-RPC接口的节点实现
*/
public class CustomNodeImpl implements EtherNode {
/**
* chainId,see {@link org.web3j.tx.ChainId}
*/
private int chainId;
/**
* 服务器的url,ex:http://localhost:8545/
*/
private String url;
private Web3j web3j;
/**
* 构造
* @param url 服务器的url,ex:http://localhost:8545/
* @param chainId chainId,see {@link org.web3j.tx.ChainId}
*/
public CustomNodeImpl(String url, int chainId) {
this.url = url;
this.chainId = chainId;
OkHttpClient.Builder builder = new OkHttpClient.Builder();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(
new HttpLoggingInterceptor.Logger() {
@Override
public void log(String msg) {
Log.i("http", msg);
}
});
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(logging);
this.web3j = Web3jFactory.build(new HttpService(url, builder.build(), true));
}
@Override
public Observable<BigInteger> getCurrentBlock() {
return web3j.ethGetBlockByNumber(DefaultBlockParameterName.LATEST, true)
.observable()
.map(new Func1<EthBlock, BigInteger>() {
@Override
public BigInteger call(EthBlock ethBlock) {
if(ethBlock.hasError()) {
throw Exceptions.propagate(JsonRpcException.crate(ethBlock.getError()));
} else {
return ethBlock.getBlock().getNumber();
}
}
});
}
@Override
public Observable<BigInteger> getBalance(String address) {
return web3j.ethGetBalance(address, DefaultBlockParameterName.LATEST)
.observable()
.map(new Func1<EthGetBalance, BigInteger>() {
@Override
public BigInteger call(EthGetBalance ethGetBalance) {
if(ethGetBalance.hasError()) {
throw Exceptions.propagate(JsonRpcException.crate(ethGetBalance.getError()));
} else {
return ethGetBalance.getBalance();
}
}
});
}
@Override
public Observable<Transaction> getTransaction(String transactionHash) {
return web3j.ethGetTransactionByHash(transactionHash)
.observable()
.map(new Func1<EthTransaction, Transaction>() {
@Override
public Transaction call(EthTransaction ethTransaction) {
if(ethTransaction.hasError()) {
throw Exceptions.propagate(JsonRpcException.crate(ethTransaction.getError()));
} else {
return ethTransaction.getTransaction();
}
}
});
}
@Override
public Observable<TransactionData> getTransactionData(final String address) {
Observable<BigInteger> balanceObservable = web3j.ethGetBalance(address, DefaultBlockParameterName.PENDING)
.observable()
.map(new Func1<EthGetBalance, BigInteger>() {
@Override
public BigInteger call(EthGetBalance ethGetBalance) {
if(ethGetBalance.hasError()) {
throw Exceptions.propagate(JsonRpcException.crate(ethGetBalance.getError()));
} else {
return ethGetBalance.getBalance();
}
}
});
Observable<BigInteger> gasPriceObservable = web3j.ethGasPrice()
.observable()
.map(new Func1<EthGasPrice, BigInteger>() {
@Override
public BigInteger call(EthGasPrice ethGasPrice) {
if(ethGasPrice.hasError()) {
throw Exceptions.propagate(JsonRpcException.crate(ethGasPrice.getError()));
} else {
return ethGasPrice.getGasPrice();
}
}
});
Observable<BigInteger> nonceObservable = web3j.ethGetTransactionCount(address, DefaultBlockParameterName.PENDING)
.observable()
.map(new Func1<EthGetTransactionCount, BigInteger>() {
@Override
public BigInteger call(EthGetTransactionCount ethGetTransactionCount) {
if(ethGetTransactionCount.hasError()) {
throw Exceptions.propagate(JsonRpcException.crate(ethGetTransactionCount.getError()));
} else {
return ethGetTransactionCount.getTransactionCount();
}
}
});
return Observable.zip(balanceObservable, gasPriceObservable, nonceObservable,
new Func3<BigInteger, BigInteger, BigInteger, TransactionData>() {
@Override
public TransactionData call(BigInteger balance, BigInteger gasPrice, BigInteger nonce) {
return new TransactionData(address, balance, gasPrice, nonce);
}
});
}
@Override
public Observable<String> sendRawTransaction(String signedTransactionData) {
return web3j.ethSendRawTransaction(signedTransactionData)
.observable()
.map(new Func1<EthSendTransaction, String>() {
@Override
public String call(EthSendTransaction ethSendTransaction) {
if(ethSendTransaction.hasError()) {
throw Exceptions.propagate(JsonRpcException.crate(ethSendTransaction.getError()));
} else {
return ethSendTransaction.getTransactionHash();
}
}
});
}
@Override
public Observable<BigInteger> getEstimatedGas(org.web3j.protocol.core.methods.request.Transaction transaction) {
return web3j.ethEstimateGas(transaction)
.observable()
.map(new Func1<EthEstimateGas, BigInteger>() {
@Override
public BigInteger call(EthEstimateGas ethEstimateGas) {
if(ethEstimateGas.hasError()) {
throw Exceptions.propagate(JsonRpcException.crate(ethEstimateGas.getError()));
} else {
return ethEstimateGas.getAmountUsed();
}
}
});
}
@Override
public Observable<String> getEthCall(org.web3j.protocol.core.methods.request.Transaction transaction) {
return web3j.ethCall(transaction, DefaultBlockParameterName.PENDING)
.observable()
.map(new Func1<EthCall, String>() {
@Override
public String call(EthCall ethCall) {
if(ethCall.hasError()) {
throw Exceptions.propagate(JsonRpcException.crate(ethCall.getError()));
} else {
return ethCall.getValue();
}
}
});
}
@Override
public int getChainId() {
return chainId;
}
public String getUrl() {
return url;
}
}
APP端查询余额
查询地址1余额:
final String address1 = "0x5378ad743b9263587eb117b0c4658cf03c906baa";
...省略部分代码...
etherNode.getBalance(address1)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<BigInteger>() {
@Override
public void call(BigInteger bigInteger) {
showDialogMsg(String.format("地址%s的余额为:%s(wei)", address1, bigInteger.toString()));
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
showDialogMsg("查询余额失败:" + throwable);
}
});
查询地址2余额:
final String address2 = "0x370dccebbf4d24059ae57fddbb651259a86a172a";
...省略部分代码...
etherNode.getBalance(address2)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<BigInteger>() {
@Override
public void call(BigInteger bigInteger) {
showDialogMsg(String.format("地址%s的余额为:%s(wei)", address2, bigInteger.toString()));
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
showDialogMsg("查询余额失败:" + throwable);
}
});
运行截图:
APP端转账
转账代码:
// 两个地址的测试数据
final String address1 = "0x5378ad743b9263587eb117b0c4658cf03c906baa";
final ECKeyPair ecKeyPair1 = new ECKeyPair(
new BigInteger("d36d0bb6c8f2ec5e3ea59b0b8a17fd78e2091c9e77d2a70267c01cf10a38fc48", 16),
new BigInteger("34a1d310e41a8b4de639ff48d8edea8702c654207fe93783cede051f261e42e8e33d5180bdd176b45d9dd97120b7b882bd9450322fb9b04ef31cb285a72f347c", 16));
final String address2 = "0x370dccebbf4d24059ae57fddbb651259a86a172a";
final ECKeyPair ecKeyPair2 = new ECKeyPair(
new BigInteger("d90b9e5b063cd5d8e56c536c341260048f563c5e8740e071145e72e4208bf883", 16),
new BigInteger("ece19a85208e5198a412ab2710a992356d837726db7e06d745d31d667339e923e92409c00d17b969545a2557b8cd3869e4fa4d90c3ca23d58c693c34247a1dab", 16));
...省略部分代码...
// 清空log buffer
logBuffer.setLength(0);
final BigInteger amount = new BigInteger("9000");
Observable<BigInteger> currBlockObs = etherNode.getCurrentBlock();
org.web3j.protocol.core.methods.request.Transaction estimatedGasTran =
new org.web3j.protocol.core.methods.request.Transaction(
address1,
null, // nonce
new BigInteger("051da038cc", 16), // gasPrice
new BigInteger("ffffff", 16), // gasLimit
address2, // to
amount, // value
null);
Observable<BigInteger> estimatedGasObs = etherNode.getEstimatedGas(estimatedGasTran);
Observable<EtherNode.TransactionData> transactionDataObs = etherNode.getTransactionData(address1);
Observable.zip(currBlockObs, estimatedGasObs, transactionDataObs, new Func3<BigInteger ,BigInteger, EtherNode.TransactionData, RawTransaction>() {
@Override
public RawTransaction call(BigInteger currBlock, BigInteger gas_limit, EtherNode.TransactionData transactionData) {
// test log
logBuffer.append("\n获取到的currBlock=").append(currBlock);
logBuffer.append("\n获取到的gas_limit=").append(gas_limit);
logBuffer.append("\n获取到的transactionData=").append(transactionData);
// test log
logBuffer.append("\n组交易之前:\nnonce=").append(transactionData.getNonce().toString(16))
.append("\ngasPrice=").append(transactionData.getGasPrice().toString(16))
.append("\ngasLimit=").append(gas_limit.toString(16))
.append("\ntoAddress=").append(address2)
.append("\namount=").append(amount.toString(16))
.append("\ndata=null");
// 需要为每个交易
RawTransaction tx = RawTransaction.createTransaction(
transactionData.getNonce(),
transactionData.getGasPrice(),
gas_limit,
address2,
amount,
""
);
return tx;
}
}).map(new Func1<RawTransaction, String>() {
@Override
public String call(RawTransaction rawTransaction) {
// TODO 直接使用EIP155的规范进行签名,会不会出现问题?
Credentials keys = Credentials.create(ecKeyPair1);
byte[] signed = TransactionEncoder.signMessage(rawTransaction, (byte) etherNode.getChainId(), keys);
String signTx = ByteUtils.toHexString(signed);
logBuffer.append("\n签名以后的数据为:").append(signTx);
return signTx;
}
}).flatMap(new Func1<String, Observable<String>>() {
@Override
public Observable<String> call(String tx) {
logBuffer.append("\n调用发布交易接口...");
if(tx != null && !tx.startsWith("0x") && !tx.startsWith("0X")) {
tx = "0x" + tx;
}
return etherNode.sendRawTransaction(tx);
}
}).subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
logBuffer.append("\n交易发布成功,hash为:").append(s);
showDialogMsg(logBuffer.toString());
Log.i("test", logBuffer.toString());
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
throwable.printStackTrace();
logBuffer.append("\n交易发布失败,throwable=").append(throwable);
showDialogMsg(logBuffer.toString());
Log.i("test", logBuffer.toString());
}
});
注意:为了转账的交易得到确认,需要开启挖矿,让交易被确认,这样地址二查询余额才能看到变化。
转账代码中,logBuffer部分的log:
获取到的gas_limit=21000
获取到的transactionData=TransactionData{address='0x5378ad743b9263587eb117b0c4658cf03c906baa', balance=59999999999999991000, gasPrice=18000000000, nonce=1}
组交易之前:
nonce=1
gasPrice=430e23400
gasLimit=5208
toAddress=0x370dccebbf4d24059ae57fddbb651259a86a172a
amount=2328
data=null
签名以后的数据为:f86601850430e2340082520894370dccebbf4d24059ae57fddbb651259a86a172a8223288040a003877e44f1d4777d668f37a0332159c40b7ad1b7fb67a782371286f4de973fb7a065d480bb839347a1ffcb7eef61f41e9c78cf0c37102a892d7d7c2485ac9ac23b
调用发布交易接口...
交易发布成功,hash为:0x47bd8331440bb31d8a6d5e27a7cf2a0a357f10ed911959549ccc0d3ef69d8a9b
OKHttp访问JSON-RPC接口的log:
07-04 11:45:23.861 20334-20564/com.hengbao.hdwallet I/http: --> POST http://10.0.0.154:8545/ http/1.1
07-04 11:45:23.871 20334-20564/com.hengbao.hdwallet I/http: Content-Type: application/json; charset=utf-8
Content-Length: 225
{"jsonrpc":"2.0","method":"eth_estimateGas","params":[{"from":"0x5378ad743b9263587eb117b0c4658cf03c906baa","gas":"0xffffff","gasPrice":"0x51da038cc","to":"0x370dccebbf4d24059ae57fddbb651259a86a172a","value":"0x2328"}],"id":0}
--> END POST (225-byte body)
07-04 11:45:23.891 20334-20564/com.hengbao.hdwallet I/http: <-- 200 OK http://10.0.0.154:8545/ (26ms)
Content-Type: application/json
Vary: Origin
Date: Wed, 04 Jul 2018 03:47:05 GMT
Content-Length: 43
{"jsonrpc":"2.0","id":0,"result":"0x5208"}
<-- END HTTP (43-byte body)
07-04 11:45:23.921 20334-20564/com.hengbao.hdwallet I/http: --> POST http://10.0.0.154:8545/ http/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 116
{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x5378ad743b9263587eb117b0c4658cf03c906baa","pending"],"id":1}
--> END POST (116-byte body)
07-04 11:45:23.931 20334-20564/com.hengbao.hdwallet I/http: <-- 200 OK http://10.0.0.154:8545/ (10ms)
Content-Type: application/json
Vary: Origin
Date: Wed, 04 Jul 2018 03:47:05 GMT
Content-Length: 56
{"jsonrpc":"2.0","id":1,"result":"0x340aad21b3b6fdcd8"}
<-- END HTTP (56-byte body)
07-04 11:45:23.941 20334-20564/com.hengbao.hdwallet I/http: --> POST http://10.0.0.154:8545/ http/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 60
{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":2}
--> END POST (60-byte body)
07-04 11:45:23.951 20334-20564/com.hengbao.hdwallet I/http: <-- 200 OK http://10.0.0.154:8545/ (9ms)
Content-Type: application/json
Vary: Origin
Date: Wed, 04 Jul 2018 03:47:05 GMT
Content-Length: 48
{"jsonrpc":"2.0","id":2,"result":"0x430e23400"}
<-- END HTTP (48-byte body)
--> POST http://10.0.0.154:8545/ http/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 125
07-04 11:45:23.961 20334-20564/com.hengbao.hdwallet I/http: {"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0x5378ad743b9263587eb117b0c4658cf03c906baa","pending"],"id":3}
--> END POST (125-byte body)
07-04 11:45:23.981 20334-20564/com.hengbao.hdwallet I/http: <-- 200 OK http://10.0.0.154:8545/ (23ms)
Content-Type: application/json
Vary: Origin
Date: Wed, 04 Jul 2018 03:47:05 GMT
Content-Length: 40
{"jsonrpc":"2.0","id":3,"result":"0x1"}
<-- END HTTP (40-byte body)
07-04 11:45:24.101 20334-20564/com.hengbao.hdwallet I/http: --> POST http://10.0.0.154:8545/ http/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 282
{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["0xf86601850430e2340082520894370dccebbf4d24059ae57fddbb651259a86a172a8223288040a003877e44f1d4777d668f37a0332159c40b7ad1b7fb67a782371286f4de973fb7a065d480bb839347a1ffcb7eef61f41e9c78cf0c37102a892d7d7c2485ac9ac23b"],"id":4}
--> END POST (282-byte body)
07-04 11:45:24.141 20334-20564/com.hengbao.hdwallet I/http: <-- 200 OK http://10.0.0.154:8545/ (34ms)
Content-Type: application/json
Vary: Origin
Date: Wed, 04 Jul 2018 03:47:05 GMT
Content-Length: 103
{"jsonrpc":"2.0","id":4,"result":"0x47bd8331440bb31d8a6d5e27a7cf2a0a357f10ed911959549ccc0d3ef69d8a9b"}
<-- END HTTP (103-byte body)
文档信息
- 本文作者:itlgl
- 本文链接:https://itlgl.com/note/2018/07/04/issues-22/
- 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)