阐明一个事:以太坊和比特币都不是区块链,它们是基于区块链的一种应用,区块链可以理解为各种技术的组合或者一直新型的“数据库”。想要了解更多,可以去度娘下载相关的白皮书蓝皮书看看,这里有些pdf的白皮书可以下载观摩。
说明:以下样例和代码操作都是基于Java版的钱包应用来描述的。
标签:比特币钱包开发,区块链钱包开发,bitcoin钱包开发,bitcoinj接口使用,比特币测试网络,获取比特币测试币
比特币提供的测试网络:
a)TestNet2、TestNet3 测试网络
b)UnitTest 测试网络,针对单元测试的特殊网络
c)RegTest 私有网络,主要是个人或企业自己搭建的网络
d)MainNet、ProdNet,正式网络,生产网络,生产环境使用
bitcoinj, gtihub: https://github.com/bitcoinj/bitcoinj
bitcoinj是一个使用比特币协议的库。它可以维护钱包,发送/接收交易而无需比特币核心的本地副本,并具有许多其他高级功能。它是用Java实现的,但可以从任何JVM兼容语言中使用:包括Python和JavaScript中的示例。
它附带完整的文档,并在其上构建了许多大型,众所周知的比特币应用程序和服务。
特征
高度优化的轻量级简化支付验证(SPV)模式。在这种模式下,只下载了一小部分区块链,使比特币适合在智能手机或廉价虚拟专用服务器等受限设备上使用。 实验性完整验证模式,与比特币核心执行相同的验证工作。在此模式下,计算未使用的事务输出集(UTXO集),并且由于PostgreSQL存储,可以将其索引到数据库中,以便按地址快速查找余额。 带有加密,费用计算,多重签名,确定性密钥派生,可插入硬币选择/硬币控制,扩展支持和事件监听器的钱包类,让您及时了解余额变化。 支持微支付渠道,允许您在客户端和服务器之间建立多签名合同,然后在渠道上进行协商,允许快速小额支付,以避免矿工费用。 为网络IO 提供异步和每线程连接,允许您在可伸缩性和仅阻塞功能(如SOCKS / Tor代理)之间进行选择。 轻松实现使用比特币合约功能的应用程序。 一个简单的GUI钱包应用程序,您可以将其用作自己的应用程序的基础。观看或阅读有关如何自定义它的教程,并构建不需要Java的本机安装程序。。
js的版本:https://github.com/bitcoinjs/bitcoinjs-lib,可自行参考。
maven依赖
<dependency>
<groupId>org.bitcoinjgroupId>
<artifactId>bitcoinj-coreartifactId>
<version>0.14.7version>
dependency>
//# 创建钱包
WalletAppKit walletAppKit = new WalletAppKit(networkParam(), new File("."), walletName);
walletAppKit.startAsync();
walletAppKit.awaitRunning();
Wallet wallet = walletAppKit.wallet();
DeterministicSeed keyChainSeed = wallet.getKeyChainSeed();
DeterministicKeyChain deterministicKeyChain = DeterministicKeyChain.builder().seed(keyChainSeed).build();
BigInteger privateKey = deterministicKeyChain.getKeyByPath(parsePath("M"), true).getPrivKey();
ECKey ecKey = ECKey.fromPrivate(privateKey);
wallet.importKey(ecKey);
Address watchedAddresses = LegacyAddress.fromKey(networkParam(), ecKey);
wallet.addWatchedAddress(watchedAddresses);
Address address = wallet.getWatchedAddresses().get(0);
List<String> mnemonicCode = wallet.getKeyChainSeed().getMnemonicCode();
String seedCode = String.join(" ", mnemonicCode);
log.info("walletAddress={}", address.toString());
log.info("privateKey={}", ecKey.getPrivKey());
log.info("encode privateKey={}", ecKey.getPrivateKeyEncoded(networkParam()));
log.info("hex privateKey={}", ecKey.getPrivateKeyAsHex());
log.info("wif privateKey={}", ecKey.getPrivateKeyAsWiF(networkParam()));
log.info("seedCode={}", seedCode); //# 助记词
//# 查询账户余额,address是0x开头地址
WalletAppKit walletAppKit = new WalletAppKit(networkParam(), new File("."), walletName);
walletAppKit.startAsync();
walletAppKit.awaitRunning();
Wallet wallet = walletAppKit.wallet();
Coin balance = wallet.getBalance();
//# 转账,返回交易hash
WalletAppKit kit = new WalletAppKit(params, new File("."), walletName);
kit.startAsync();
kit.awaitRunning();
log.warn("==================================================================");
log.warn("========================= update completed =========================");
log.warn("==================================================================");
Coin value = Coin.parseCoin("0.02");
LegacyAddress to = LegacyAddress.fromBase58(params, "monEGqJ2uTNSAbHudVPCCszx7mWMH2oL3z");
log.info("send money[{}] to address[{}]", value.getValue(), to.toString());
System.out.println("balance= "+kit.wallet().getBalance().getValue());
System.out.println("balance= "+kit.wallet().getBalance().toFriendlyString());
try {
SendRequest sendRequest = SendRequest.to(to, value);
Wallet.SendResult result = kit.wallet().sendCoins(sendRequest);
//# 返回交易hash
log.info("coins sent. transaction hash: {}", result.tx.getHashAsString());
} catch (InsufficientMoneyException e) {
log.error("send money[{}] to address[{}] error", value.getValue(), to.toString());
log.error("not enough coins in your wallet. Missing {} satoshis are missing (including fees)", e.missing.getValue());
}
ListenableFuture<Coin> balanceFuture = kit.wallet().getBalanceFuture(value, Wallet.BalanceType.AVAILABLE);
FutureCallback<Coin> callback = new FutureCallback<Coin>() {
@Override
public void onSuccess(Coin balance) {
log.info("----------- **************************************************** ----------------------");
log.info("----------- coins arrived and the wallet now has enough balance ----------------------");
log.info("----------- **************************************************** ----------------------");
}
@Override
public void onFailure(Throwable t) {
log.error(".....................................");
log.error("@ something went wrong #");
log.error(".....................................");
}
};
Futures.addCallback(balanceFuture, callback);
testnet环境:
https://live.blockcypher.com/btc-testnet/address/monEGqJ2uTNSAbHudVPCCszx7mWMH2oL3z
https://chain.so/address/BTCTEST/monEGqJ2uTNSAbHudVPCCszx7mWMH2oL3z
公钥和私钥成对出现
公开的密钥叫公钥,只有自己知道的叫私钥
用公钥加密的数据只有对应的私钥可以解密
用私钥加密的数据只有对应的公钥可以解密
如果可以用公钥解密,则必然是对应的私钥加的密
如果可以用私钥解密,则必然是对应的公钥加的密
Keystore+密码=银行卡号+银行卡密码
Keystore ≠ 私钥
Keystore+密码=私钥
Keystore不是私钥,常见于以太坊钱包,一般你创建以太坊钱包后,会让你备份Keystore,输入密码,会出现一串字符这就是 Keystore。Keystore的本质是加密后的私钥,Keystore必须配合你的钱包密码来使用。用途:在导入钱包的时候,选择官方钱包,输入 Keystore 和密码,就能进入钱包了。需要说明的是,这和用私钥或助记词导入钱包不一样,用私钥或助记词导入钱包,不需要知道密码。
私钥:私钥可以计算出公钥,公钥可以经过一系列数字签名生成钱包地址。所以, 私钥的持有者才是数字货币的持有者。你可以把它看成是你的银行卡密码。
公钥:它是密码学上的概念,由私钥推算出来。公开密钥的算法属于不对称加密算法,该算法拥有两个密钥:公钥和私钥。使用私钥加密的数据可以用公钥解密,反之亦可。通过公钥可以算出钱包地址。
钱包地址:地址由公钥转换而来,地址被用于接收数字货币,一个地址上收到数字货币后,只有使用该地址所对应的私钥才能花费这个地址上的钱。可以把钱包地址想象成一个银行卡号,别人可以给你的钱包地址打钱。一般地址和私钥是成对出现的,他们的关系就像银行卡号和密码。地址就像银行卡号一样用来记录你在该钱包地址上存有多少币。我们可以简单的把钱包地址理解成为银行卡号,该钱包地址的私钥理解成为所对应银行卡号的密码。只有你在知道银行密码的情况下才能使用银行卡号上的钱。所以,在使用钱包时请保存好你的地址和私钥。
除了开发过程使用,其他时候没有任何实际价值,表当真^_^, 谁认真谁输.....
https://testnet.manu.backend.hamburg/faucet 这个水龙头好像呜呼哀哉了~
http://bitcoinfaucet.uo1.net/send.php 这个偶尔可以用,现在也不稳定了~
写的不好,不喜勿喷! 谢谢~~
如果觉得申请比特币测试币麻烦,可以加我获取,有偿提供测试币~~~
企鹅号: 631722350