加密貨幣是一種安全、去中心化的價值儲存方式,採用點對點(P2P)網路進行交易的傳播和驗證。
BitcoinJ是一個 Java 庫,它簡化了建立比特幣應用程式的過程,使使用者能夠無縫地執行加密貨幣交易。
在本教程中,我們將深入研究 BitcoinJ 的主要功能和元件。此外,我們還將探索如何建立錢包、為錢包充值以及如何將一些硬幣傳送到另一個錢包。
什麼是BitcoinJ?
BitcoinJ 是一個 Java 庫,用於簡化建立比特幣應用程式的過程。它提供了建立和管理比特幣錢包、傳送和接收交易以及與比特幣主網 mainnet、testnet 和 regtest 網路整合的工具。
此外,它還提供簡化支付驗證(SPV)來與比特幣網路互動,而無需下載整個區塊鏈。
BitcoinJ 的特點
BitcoinJ 允許我們輕鬆建立比特幣錢包,包括生成地址、管理私鑰和公鑰以及處理用於錢包恢復的種子短語。
此外,它還提供傳送和接收比特幣交易的功能,使我們能夠構建一個可以處理比特幣轉賬的應用程式。
此外,它還支援與現實世界中進行比特幣交易的比特幣主網 (mainnet) 整合。此外,它還支援用於測試和原型設計的 testnet 和 regtest 網路。
最後,它允許事件監聽器響應各種事件,例如傳入的交易或區塊鏈中的變化。
基本設定
要開始與庫互動,讓我們將bitcoinj-core依賴項新增到pom.xml:
<dependency> <groupId>org.bitcoinj</groupId> <artifactId>bitcoinj-core</artifactId> <version>0.17-alpha4</version> </dependency>
|
此依賴項提供了Wallet和WalletKitApp類來建立比特幣錢包。此外,讓我們新增用於日誌記錄的slf4j-api和slf4j-simple 依賴項:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>2.1.0-alpha1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>2.1.0-alpha1</version> </dependency>
|
這些依賴關係對於記錄應用程式的活動至關重要。.錢包類
錢包是加密貨幣的重要組成部分,因為它提供了管理交易的功能。BitcoinJ 庫提供了Wallet和WalletKitApp類來建立錢包。
1. 建立錢包
在建立錢包之前,我們需要定義錢包與之互動的網路。
BitcoinJ 支援三種型別的網路——用於生產的主網、用於測試的測試網和用於本地迴歸測試的 regtest。
讓我們建立NetworkParameters物件來連線到測試網路:
NetworkParameters params = TestNet3Params.get();
接下來,讓我們建立一個接受NetworkParameters作為引數的Wallet例項:
void createWallet() throws IOException { Wallet wallet = Wallet.createDeterministic(params, Script.ScriptType.P2PKH); File walletFile = new File(<font>"baeldung.dat"); wallet.saveToFile(walletFile); }
|
在上述方法中,我們建立了一個與測試網路互動的Wallet 。我們使用P2PKH 指令碼型別,該指令碼型別代表 Pay-to-Pubkey-Hash 地址,這是比特幣地址的常見型別。最後,我們將錢包儲存為baeldung.dat。值得注意的是,錢包地址、種子短語以及公鑰和私鑰是在建立錢包時生成的。
2. 檢索錢包詳細資訊
建立錢包後,我們可以檢索地址、公鑰、私鑰和種子短語等基本詳細資訊:
Wallet loadWallet() throws IOException, UnreadableWalletException { File walletFile = new File(<font>"baeldung.dat"); Wallet wallet = Wallet.loadFromFile(walletFile); logger.info("Address: " + wallet.currentReceiveAddress().toString()); logger.info("Seed Phrase: " + wallet.getKeyChainSeed().getMnemonicString()); logger.info("Balance: " + wallet.getBalance().toFriendlyString()); logger.info("Public Key: " + wallet.findKeyFromAddress(wallet.currentReceiveAddress()).getPublicKeyAsHex()); logger.info("Private Key: " + wallet.findKeyFromAddress(wallet.currentReceiveAddress()).getPrivateKeyAsHex()); return wallet; }
|
在這裡,我們透過呼叫Wallet例項上的loadFromFile()方法從baeldung.dat檔案載入錢包。然後,我們將錢包的地址、種子短語和餘額記錄到控制檯。此外,我們將公鑰和私鑰記錄到控制檯。
3. 恢復錢包
如果我們無法訪問錢包檔案但有種子短語,我們可以使用種子短語恢復錢包:
Wallet loadUsingSeed(String seedWord) throws UnreadableWalletException { DeterministicSeed seed = new DeterministicSeed(seedWord, null, <font>"", Utils.currentTimeSeconds()); return Wallet.fromSeed(params, seed); }
|
在上面的程式碼中,我們建立了一個DeterministicSeed 物件,它接受種子短語和時間作為引數。然後我們呼叫Wallet.fromSeed()方法,傳遞params和seed作為引數。這將根據提供的種子短語和網路引數建立一個新的Wallet例項。4. 保護錢包
我們需要確保私鑰和種子短語不被未經授權的訪問。獲得私鑰的訪問許可權可讓攻擊者訪問我們的錢包並花掉可用資金。
BitcoinJ 提供了encrypt()方法來為我們的錢包設定密碼:
<font>// ...<i> wallet.encrypt("password"); wallet.saveToFile(walletFile); // ...<i>
|
在這裡,我們在Wallet 物件上呼叫encrypt() 方法。它接受預期的密碼作為引數。錢包加密後,任何人都無法在不先解密錢包的情況下訪問私鑰:<font>// ...<i> Wallet wallet = Wallet.loadFromFile(walletFile); wallet.decrypt("password"); // ...<i>
|
在這裡,我們使用加密錢包的密碼來解密錢包。值得注意的是,務必將錢包檔案、種子短語和私鑰保密,不讓外部來源獲取。連線到對等組網路
目前,我們的錢包處於隔離狀態,無法識別交易,因為它與區塊鏈不同步。我們需要連線到對等組網路:
void connectWalletToPeer() throws BlockStoreException, UnreadableWalletException, IOException { Wallet wallet = loadWallet(); BlockStore blockStore = new MemoryBlockStore(params); BlockChain chain = new BlockChain(params, wallet, blockStore); PeerGroup peerGroup = new PeerGroup(params, chain); peerGroup.addPeerDiscovery(new DnsDiscovery(params)); peerGroup.addWallet(wallet); peerGroup.start(); peerGroup.downloadBlockChain(); }
|
在這裡,我們首先載入錢包,然後建立一個BlockStore例項,將區塊鏈儲存在記憶體中。此外,我們建立一個BlockChain例項,用於管理比特幣背後的資料結構。最後,我們建立一個PeerGroup 例項來建立網路連線。這些類對於與測試網路互動以及將我們的錢包與網路同步是必需的。
但是下載整個區塊鏈可能會耗費大量資源。因此,WalletKitApp 類預設使用 SPV 來簡化此過程。
WalletKitApp 類
BitcoinJ 提供了WalletKitApp類,簡化了設定錢包的過程。該類抽象了建立BlockStore、BlockChain和PeerGroup例項,使其更容易與比特幣網路配合使用。
讓我們使用 WalletKitApp 建立一個錢包,並在建立後記錄錢包詳細資訊:
NetworkParameters params = TestNet3Params.get(); WalletAppKit kit = new WalletAppKit(params, new File(<font>"."), "baeldungkit") { @Override protected void onSetupCompleted() { logger.info("Wallet created and loaded successfully."); logger.info("Receive address: " + wallet().currentReceiveAddress()); logger.info("Seed Phrase: " + wallet().getKeyChainSeed()); logger.info("Balance: " + wallet().getBalance().toFriendlyString()); logger.info("Public Key: " + wallet().findKeyFromAddress(wallet().currentReceiveAddress()) .getPublicKeyAsHex()); logger.info("Private Key: " + wallet().findKeyFromAddress(wallet().currentReceiveAddress()) .getPrivateKeyAsHex()); wallet().encrypt("password"); } }; kit.startAsync(); kit.awaitRunning(); kit.setAutoSave(true);;
|
在這裡,我們使用測試網引數設定一個新錢包,並指定儲存錢包資料的目錄。我們非同步啟動WalletAppKit物件。我們啟用自動儲存以在本地儲存最新的錢包資訊。以下是錢包的詳細資訊:
[ STARTING] INFO com.baeldung.bitcoinj.Kit - Wallet created and loaded successfully. [ STARTING] INFO com.baeldung.bitcoinj.Kit - Receive address: moqVLcdRFjyXehgRAK5bJBK6rDN2vq14Wc [ STARTING] INFO com.baeldung.bitcoinj.Kit - Seed Phrase: DeterministicSeed{unencrypted} [ STARTING] INFO com.baeldung.bitcoinj.Kit - Balance: 0
|
該錢包目前有零比特幣。新增事件監聽器
我們可以向錢包新增事件監聽器來響應各種事件,例如傳入的交易:
kit.wallet() .addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> { logger.info(<font>"Received tx for " + tx.getValueSentToMe(wallet)); logger.info("New balance: " + newBalance.toFriendlyString()); });
|
上述事件監聽器記錄傳入的交易以及交易 ID 和收到的金額。此外,當我們將硬幣傳送到另一個錢包時,讓我們新增一個事件監聽器來記錄當前錢包餘額:
kit.wallet() .addCoinsSentEventListener((wallet, tx, prevBalance, newBalance) -> logger.info(<font>"new balance: " + newBalance.toFriendlyString()));
|
上面的程式碼監聽一個事件以將硬幣從錢包中傳送出來並記錄新的餘額。傳送比特幣
我們可以透過建立Coin例項並指定要傳送的金額,輕鬆地將比特幣傳送到另一個地址:
String receiveAddress = <font>"n1vb1YZXyMQxvEjkc53VULi5KTiRtcAA9G"; Coin value = Coin.valueOf(200); final Coin amountToSend = value.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); final Wallet.SendResult sendResult = kit.wallet() .sendCoins(kit.peerGroup(), Address.fromString(params, receiveAddress), amountToSend);
|
在上面的程式碼中,我們指定了要傳送200 satoshi 的地址。此外,我們減去礦工的交易費。最後,我們呼叫sendCoins(),啟動轉移硬幣的過程。