126 Commits

Author SHA1 Message Date
crowetic
8ec5a9cfaa Merge pull request #3 from IceBurst/master
Update & Corrections
2025-04-24 13:41:38 -07:00
Ice
f5d65c8703 Update PaymentSession.java
Correct @link
2025-04-21 13:04:05 -04:00
Ice
7ef0f18848 - JavaDoc Correction
- Invalid @Link removed
- Updated Gradle version
2025-04-21 12:26:12 -04:00
Ice
9940b0e10b Update build.gradle 2025-04-21 07:38:05 -04:00
CalDescent
7dc8c6f25d Added (incomplete) Pirate Chain mainnet params 2022-05-10 07:56:22 +01:00
CalDescent
e15d559802 Added comment with reminder to fix the genesis block data. 2022-04-24 15:12:34 +01:00
CalDescent
6628cfdd66 Temporarily disable genesis checkState(), to allow testing of other areas 2022-04-24 14:52:26 +01:00
CalDescent
37b66e199e Removed ravencoinj comments since it seems that it was never adapted for Ravencoin and is still using Bitcoin values. 2022-04-24 11:40:49 +01:00
CalDescent
2d1b7e4385 Use correct coinbase transaction for Ravencoin 2022-04-24 11:23:17 +01:00
CalDescent
85728d12c7 Revert "Put back to BLOCK_VERSION_GENESIS (1)"
This reverts commit 6ffdc03950.
2022-04-24 10:33:32 +01:00
CalDescent
714779ee1d Revert "Copied genesis transaction output from ravencoinj"
This reverts commit a5755908f0.
2022-04-23 17:22:09 +01:00
CalDescent
a5755908f0 Copied genesis transaction output from ravencoinj 2022-04-23 17:17:21 +01:00
CalDescent
6ffdc03950 Put back to BLOCK_VERSION_GENESIS (1) 2022-04-23 17:12:20 +01:00
CalDescent
4957559878 Fixed incorrect genesis timestamp in last commit 2022-04-23 16:45:27 +01:00
CalDescent
0786a0ec37 Updated Ravencoin genesis block values. 2022-04-23 16:31:29 +01:00
CalDescent
6fec8631ea Merge pull request #1 from QuickMythril/ravencoin
Added Ravencoin mainnet params
2022-04-23 14:07:06 +01:00
QuickMythril
98e5348113 Added Ravencoin mainnet params 2022-04-23 08:24:39 -04:00
CalDescent
5ce2206410 Fixed incorrect comment 2022-04-22 16:28:45 +01:00
CalDescent
dd1ed81f51 Added Digibyte mainnet unit test 2022-04-22 16:23:45 +01:00
CalDescent
02e0d3dc53 Construct the AltcoinBlock differently, because setMerkleRoot() is private. 2022-04-22 16:15:33 +01:00
CalDescent
99249bfdb7 Revert "Fixed incorrect genesis block script."
This reverts commit 790b449c41.
2022-04-22 15:01:16 +01:00
CalDescent
790b449c41 Fixed incorrect genesis block script. 2022-04-22 14:50:43 +01:00
CalDescent
6cf02a0d89 Copied Digibyte genesis block info from digibytej 2022-04-22 14:23:51 +01:00
CalDescent
247eaabc22 Added Digibyte mainnet params, based on Litecoin classes, but using constants from https://github.com/DigiByte-Core/digibytej
This implementation is incomplete and may need modifications before it is fully usable.
2022-04-22 14:03:11 +01:00
jjos2372
dcbc42885e Revert gradle version. 2021-01-29 12:19:14 -03:00
jjos2372
3d47666fb4 Updated gradle. 2021-01-29 12:07:56 -03:00
jjos2372
0f18ff1c3c Another seed node. 2021-01-29 12:07:48 -03:00
jjos2372
bf9fb8063c Segwit hrp 2020-06-02 19:45:49 -03:00
jjos2372
cc179d72c7 Delete travis 2020-02-26 10:04:14 -03:00
jjos2372
806b3926c2 Update README 2020-02-26 10:03:25 -03:00
jjos2372
ef6b5035d4 Update README 2020-02-26 09:57:59 -03:00
jjos2372
4abb955131 Update README 2020-02-26 09:45:21 -03:00
jjos2372
f26e20bb13 Removing maven build 2020-02-26 09:24:26 -03:00
jjos2372
e5da0b24df Fixing compilation, upated to bitcoinj 0.15, removed Namecoin 2020-02-26 09:13:43 -03:00
jjos2372
9afa0dd01f gradle build 2020-02-26 09:11:12 -03:00
jjos2372
657ebf57de Adding gradle build 2020-02-26 09:04:49 -03:00
jjos2372
9159a629a2 Removed namecoin stuff 2020-02-26 09:04:01 -03:00
langerhans
889ff26ebf Update fasterxml dependency 2019-05-04 16:40:20 +02:00
JeremyRand
31fb8985ba Namecoin LevelDBTransactionCache: Only store name scriptPubKey in the record, not entire transaction. (#32)
This breaks backward compatibility with older name databases.  You'll need to delete the blockchain and resync.
2018-03-18 08:59:42 +00:00
Max K
6ce57fdb04 Remove non-working seed (#30) 2017-12-29 22:09:00 +01:00
JeremyRand
9d20db9a84 Namecoin: add LevelDBTransactionCache algorithm. (#27)
Added Namecoin latest-name lookup algorithm using a local LevelDB transaction cache.
2017-11-06 10:36:12 +00:00
MikeR
70ce836956 Add Regtest mode for Litecoin (#20) 2017-06-19 09:58:47 +01:00
Ross Nicoll
1419b81241 Merge pull request #19 from JeremyRand/namecoin-fix-hash-verification
Fix verification bug in Namecoin.
2017-03-22 10:13:59 +00:00
JeremyRand
0237a504c4 Fix verification bug in Namecoin.
P2P full-block by-hash retrieval wasn't verifying that the received block had a header whose hash matched the requested hash.

This probably made it trivially easy to falsify name records, since any internally valid block supplied by a malicious P2P peer (or a MITM attacker) would be accepted, and the name transactions in it trusted as valid, even if the block had (for example) minimum difficulty.

The REST Merkle API is unaffected.

There's a reason I haven't deployed libdohj-namecoin to end users yet; this is that reason.  Review takes time.
2016-07-21 19:59:20 +00:00
Ross Nicoll
faadcca7ad Merge pull request #18 from JeremyRand/namecoin-initial-pull-request
Initial Namecoin support
2016-07-05 20:15:00 +01:00
JeremyRand
ca28f2a0ba Add classes for name lookups with SPV verification. 2016-07-04 04:04:39 +00:00
JeremyRand
80faef7303 Added tests for name transaction utils. 2016-07-04 04:04:39 +00:00
JeremyRand
7f873b69a6 Added util class for processing name transactions. 2016-07-04 04:04:39 +00:00
JeremyRand
a9fa671988 Added tests for parsing name scripts. 2016-07-04 04:04:39 +00:00
JeremyRand
f8186d9aee Added (incomplete) support for parsing name scripts. 2016-07-04 04:04:39 +00:00
JeremyRand
0cb659ca21 Added network parameters for Namecoin (abstract and mainnet). 2016-07-04 04:04:39 +00:00
Ross Nicoll
bacc348541 Restructure libdohj around Maven modules 2016-06-27 21:06:44 +01:00
Ross Nicoll
6f92dc64bd Update to bitcoin 0.14.2 2016-06-05 11:31:20 +01:00
Ross Nicoll
89cf3c6b17 Handle legacy AuxPoW blocks
Adds handling of legacy AuxPoW blocks before there was a merged mining
header.
2016-02-28 11:48:40 +00:00
Ross Nicoll
9afda0e8e9 Add build status image 2016-01-08 20:37:00 +00:00
Ross Nicoll
75fa1f4677 Add Travis configuration 2016-01-08 20:31:16 +00:00
Ross Nicoll
24f1ffe459 Clean up network parameters
Correct block subsidy calculations for Dogecoin and Litecoin and add test
coverage for both networks.
Change Litecoin block version check parameters to match Litecoin Core.
Add checkpoints for Dogecoin main and test, and Litecoin main network.
2015-12-28 21:17:47 +00:00
Ross Nicoll
9261271b3d Add Litecoin testnet difficulty rules
Add special rules for Litecoin testnet difficulty transitions when there's
a long break between blocks
2015-12-28 10:19:31 +00:00
Ross Nicoll
0f4a659fa8 Add Dogecoin testnet difficulty calculation rules
Add missing special case rules for Dogecoin testnet which allow blocks to
be mined against the maximum target, if the interval since the last block
is twice the target interval.
2015-12-25 18:24:20 +00:00
Ross Nicoll
3c371a543f Change from testing arrays to BitSet objects directly 2015-12-20 23:11:00 +00:00
Ross Nicoll
c15a742ffa Remove dependency on Java 7 in AltcoinBlock 2015-12-20 22:01:45 +00:00
Ross Nicoll
bf9539076f Add Bitcoin max money to Dogecoin parameters
Add Bitcoin max money to Dogecoin parameters as workaround until bitcoinj
hooks for network-specific maximums are complete.
2015-11-08 09:37:13 +00:00
Ross Nicoll
a3910134f8 Add Litecoin support 2015-11-08 09:35:31 +00:00
Ross Nicoll
de30a8e0c9 Update comments on network parameter classes. 2015-11-07 18:15:47 +00:00
langerhans
2d7ea57916 Enable parsing of merkleblock messages
Needs to construct the parts of the FilteredBlock manually at this time, but has potential for optimzations
2015-11-07 17:50:59 +00:00
langerhans
2c3466866c Advance the cursor the full header length
Otherweise parsing the nonexistant transactions would reset the size of the message to 80
2015-11-07 17:50:58 +00:00
Ross Nicoll
1dcdff9f6e Correct AuxPoW index calculation to match unsigned integer maths used by reference client.
Add unit tests for AuxPoW index calculation.
2015-11-07 17:50:58 +00:00
Ross Nicoll
95060faa20 Update subclasses to match bitcoinj API changes
Update AltcoinBlock and AltcoinSerializer to handle offset as a parameter
when parsing blocks.
2015-10-23 20:55:35 +01:00
Ross Nicoll
29d11d357b Merge pull request #9 from schildbach/patch-1
Fix typo in build.md.
2015-10-18 20:06:20 +01:00
Andreas Schildbach
98fa48ae2c Fix typo in build.md. 2015-10-18 21:04:53 +02:00
Ross Nicoll
18c6df1244 Merge pull request #8 from langerhans/array-match
Fix arrayMatch.
2015-10-18 18:17:04 +01:00
langerhans
5ad1659660 Fix arrayMatch.
It would incorrectly return true if just part of the subArray was at the end of the script.
2015-10-18 19:14:32 +02:00
Ross Nicoll
c36d605404 Merge pull request #6 from langerhans/sha256
Use Sha256Hash for checkpoints
2015-10-16 22:46:18 +01:00
Ross Nicoll
355ea2d50e Modified Dogecoin difficulty calculations to use next expected target to determine precision. 2015-10-16 22:44:47 +01:00
langerhans
5e6e821d1a Use Sha256Hash for checkpoints
They are compared with downloaded hashes and the two classes are not equal in terms of the equals method.
2015-10-16 23:10:29 +02:00
Ross Nicoll
95db3b960e Remove old experiments 2015-10-16 21:17:17 +01:00
Ross Nicoll
4951fb7241 Add unit tests for the retarget at block 720. 2015-10-16 21:04:38 +01:00
Ross Nicoll
4cf2dec918 Add majority window figures for BIP 44/BIP 66 enablement. 2015-10-16 20:31:22 +01:00
Ross Nicoll
5d36a644ea Add unit tests to verify how current and previous block time and difficulty are extracted from blocks 2015-10-16 19:49:49 +01:00
Ross Nicoll
a2499cb31a Correct difficulty target passsed to getNewDifficultyTarget - was received rather than previous value 2015-10-16 19:31:30 +01:00
Ross Nicoll
805b78f060 Added check of parsed difficulty bits.
Corrected difficult retarget interval.
2015-10-16 19:18:15 +01:00
Ross Nicoll
0fe4ac43ba Skip parsing AuxPoW block header where the header is too short (i.e. checkpoint blocks) 2015-10-16 18:59:54 +01:00
Ross Nicoll
8a96492c80 Modify parsing of nonce value from AuxPoW coinbase transaction script to
use long values rather than int, to support Java correctly.
Add unit tests for parsing of nonce values and calculating expected slot
index for AuxPoW headers.
2015-09-29 01:26:59 +01:00
Ross Nicoll
1a5184ab4b Correct cast of network parameters to AuxPoW parameters
Also adds unit test coverage
2015-08-26 21:29:43 +01:00
Ross Nicoll
a2ba8da774 Modify version handling to match Dogecoin 1.10 style API
Calling getVersion() on an AuxPoW block now returns the lowest 8 bits
only, and a new getRawVersion() method is introduced to support fetching
full version.
Added unit tests to check unpacking of AuxPoW version numbers.
2015-08-23 13:10:09 +01:00
Ross Nicoll
98ae05b0a1 Update README.md to match libdohj not dogecoinj 2015-08-23 12:31:46 +01:00
Ross Nicoll
562ea4f56c Complete rename to libdohj 2015-08-09 15:19:31 +01:00
Ross Nicoll
39fe02389b Add Dogecoin payment protocol support
Add Dogecoin payment protocol support, and remove unused proto definition
files.
2015-08-08 23:16:18 +01:00
Ross Nicoll
049fa77002 Add Dogecoin payment protocol support
Add Dogecoin payment protocol support, and remove unused proto definition
files.
2015-08-08 23:15:16 +01:00
Ross Nicoll
922243e503 Merge pull request #3 from patricklodder/dogecoin_dnsseeds
add the right dns seeds for mainnet
2015-08-06 13:57:27 +01:00
Patrick Lodder
fd0ccb902d add the right dns seeds for mainnet 2015-08-06 14:49:06 +02:00
Ross Nicoll
0f9910c6d8 Updated bitcoinj API calls to bitcoinj 0.14 2015-08-01 11:36:58 +01:00
Ross Nicoll
38e9c4ae1d Update bitcoinj library to 0.14 2015-07-11 20:40:25 +01:00
Ross Nicoll
403696f5e3 Update BIP32 wallet headers 2015-07-11 20:05:35 +01:00
Ross Nicoll
258792c803 Add unit tests for AuxPoW header validation. 2015-06-05 21:40:48 +01:00
Ross Nicoll
36753e5112 Moved classes to altcoinj.core package where they do not specifically require to be part of the bitcoinj package. 2015-06-01 22:58:08 +01:00
Ross Nicoll
573d6f6edf Add AuxPoW chain ID checks. 2015-06-01 22:54:54 +01:00
Ross Nicoll
c6659bad12 Completed AuxPoW header validation code. 2015-05-31 22:54:46 +01:00
Ross Nicoll
453819ccb2 Cleaned up unneeded files after rebase. 2015-05-30 21:22:59 +01:00
Ross Nicoll
5c973f6149 Remove existing build pom.xml
Added genesis block construction for Dogecoin network.
Added difficulty calculations for Dogecoin network.
Completed difficulty calculation code for Dogecoin.
Added code for parsing Dogecoin blocks, and unit tests for same.
2015-05-30 21:22:58 +01:00
Ross Nicoll
245505e984 Started connecting altcoinj to bitcoinj.
Merged in files from bitcoinj which were rejected for altcoin support.
2015-05-30 21:22:57 +01:00
Ross Nicoll
c129d3fc89 Added dependency on bitcoinj and removed code elements which should taken directly from bitcoinj.
Removed classes with no differences to bitcoinj.
Fixed packages.
2015-05-30 21:22:37 +01:00
waglik
09c80d44ff fix package 2015-04-03 19:21:33 +03:00
langerhans
be353f8556 Merge remote-tracking branch 'upstream/master'
Conflicts:
	core/src/main/java/com/dogecoin/dogecoinj/core/PeerGroup.java
	core/src/main/java/com/dogecoin/dogecoinj/core/TransactionBroadcast.java
	core/src/main/java/com/dogecoin/dogecoinj/core/Wallet.java
	core/src/main/java/com/dogecoin/dogecoinj/kits/WalletAppKit.java
	core/src/main/java/com/dogecoin/dogecoinj/net/discovery/DnsDiscovery.java
	core/src/main/java/com/dogecoin/dogecoinj/store/SPVBlockStore.java
	core/src/main/java/org/bitcoinj/net/discovery/HttpDiscovery.java
	wallettemplate/src/main/java/wallettemplate/Main.java
2015-02-12 23:15:09 +01:00
langerhans
e58dfe1049 Update README 2015-01-06 20:55:26 +01:00
langerhans
b3b8c0eb8d Merge remote-tracking branch 'upstream/master' into rebase 2015-01-06 20:52:03 +01:00
langerhans
e6fc3deb50 Merge remote-tracking branch 'upstream/master' into rebase
Conflicts:
	core/src/main/java/com/dogecoin/dogecoinj/wallet/DefaultRiskAnalysis.java
	core/src/test/java/com/dogecoin/dogecoinj/core/ECKeyTest.java
	core/src/test/java/com/dogecoin/dogecoinj/wallet/DefaultRiskAnalysisTest.java
	tools/src/main/java/com/dogecoin/dogecoinj/tools/WatchMempool.java
2015-01-04 20:33:24 +01:00
langerhans
f6d3c1b305 Fix the params 2015-01-04 19:09:19 +01:00
langerhans
ac12628289 Higher precision for Fiat values in DOGE land 2014-12-31 19:23:51 +01:00
langerhans
e00a5b2776 Comment out unittest params for now. 2014-12-30 19:19:28 +01:00
langerhans
905629a78f Merge branch 'master' of https://github.com/bitcoinj/bitcoinj into rebase
Conflicts:
	README.md
	core/pom.xml
	core/src/main/java/com/dogecoin/dogecoinj/core/DownloadListener.java
	core/src/main/java/com/dogecoin/dogecoinj/core/MemoryPool.java
	core/src/main/java/com/dogecoin/dogecoinj/core/NetworkParameters.java
	core/src/main/java/com/dogecoin/dogecoinj/core/PeerFilterProvider.java
	core/src/main/java/com/dogecoin/dogecoinj/core/PeerGroup.java
	core/src/main/java/com/dogecoin/dogecoinj/core/StoredTransactionOutput.java
	core/src/main/java/com/dogecoin/dogecoinj/core/Wallet.java
	core/src/main/java/com/dogecoin/dogecoinj/crypto/EncryptedPrivateKey.java
	core/src/main/java/com/dogecoin/dogecoinj/crypto/KeyCrypterScrypt.java
	core/src/main/java/com/dogecoin/dogecoinj/jni/NativeTransactionConfidenceListener.java
	core/src/main/java/com/dogecoin/dogecoinj/kits/WalletAppKit.java
	core/src/main/java/com/dogecoin/dogecoinj/net/FilterMerger.java
	core/src/main/java/com/dogecoin/dogecoinj/protocols/channels/IPaymentChannelClient.java
	core/src/main/java/com/dogecoin/dogecoinj/protocols/channels/PaymentChannelClient.java
	core/src/main/java/com/dogecoin/dogecoinj/protocols/channels/PaymentChannelClientConnection.java
	core/src/main/java/com/dogecoin/dogecoinj/protocols/channels/PaymentChannelClientState.java
	core/src/main/java/com/dogecoin/dogecoinj/store/BlockStore.java
	core/src/main/java/com/dogecoin/dogecoinj/store/FullPrunedBlockStore.java
	core/src/main/java/com/dogecoin/dogecoinj/store/H2FullPrunedBlockStore.java
	core/src/main/java/com/dogecoin/dogecoinj/store/PostgresFullPrunedBlockStore.java
	core/src/main/java/com/dogecoin/dogecoinj/testing/FakeTxBuilder.java
	core/src/main/java/com/dogecoin/dogecoinj/testing/TestWithPeerGroup.java
	core/src/main/java/com/dogecoin/dogecoinj/wallet/KeyChainGroup.java
	core/src/main/java/org/bitcoinj/core/DownloadListener.java
	core/src/main/java/org/bitcoinj/core/DownloadProgressTracker.java
	core/src/main/java/org/bitcoinj/core/MemoryPool.java
	core/src/main/java/org/bitcoinj/core/StoredTransactionOutput.java
	core/src/main/java/org/bitcoinj/core/TxConfidenceTable.java
	core/src/main/java/org/bitcoinj/core/UTXO.java
	core/src/main/java/org/bitcoinj/params/MainNetParams.java
	core/src/test/java/com/dogecoin/dogecoinj/core/AbstractFullPrunedBlockChainTest.java
	core/src/test/java/com/dogecoin/dogecoinj/core/BitcoindComparisonTool.java
	core/src/test/java/com/dogecoin/dogecoinj/core/FilteredBlockAndPartialMerkleTreeTests.java
	core/src/test/java/com/dogecoin/dogecoinj/core/FullBlockTestGenerator.java
	core/src/test/java/com/dogecoin/dogecoinj/core/PostgresFullPrunedBlockChainTest.java
	core/src/test/java/com/dogecoin/dogecoinj/core/WalletTest.java
	core/src/test/java/com/dogecoin/dogecoinj/crypto/ChildKeyDerivationTest.java
	core/src/test/java/com/dogecoin/dogecoinj/store/WalletProtobufSerializerTest.java
	core/src/test/java/com/dogecoin/dogecoinj/wallet/DefaultRiskAnalysisTest.java
	core/src/test/java/com/dogecoin/dogecoinj/wallet/DeterministicKeyChainTest.java
	tools/src/main/java/com/dogecoin/dogecoinj/tools/WalletTool.java
	wallettemplate/pom.xml
	wallettemplate/src/main/java/wallettemplate/Main.java
	wallettemplate/src/main/java/wallettemplate/MainController.java
	wallettemplate/src/main/java/wallettemplate/SendMoneyController.java
2014-12-23 18:09:55 +01:00
langerhans
e5a1eb8571 Merge remote-tracking branch 'upstream/master' into rebase
Conflicts:
	core/src/main/java/com/dogecoin/dogecoinj/core/Transaction.java
	core/src/main/java/com/dogecoin/dogecoinj/core/Wallet.java
	core/src/main/java/com/dogecoin/dogecoinj/wallet/DeterministicSeed.java
2014-10-30 22:32:59 +01:00
langerhans
5f1703a97f Fix monetary format tests 2014-10-20 20:46:11 +02:00
langerhans
5e75c2a746 Fix coin tests 2014-10-20 20:08:25 +02:00
langerhans
0a5c51429c Fix address tests 2014-10-20 19:42:13 +02:00
langerhans
bcbd9e0bab Update the README 2014-10-19 22:32:39 +02:00
langerhans
01c6d6f8a9 Fix the tools 2014-10-19 22:23:08 +02:00
langerhans
5f16d915ea fix peer monitor 2014-10-18 22:47:19 +02:00
langerhans
7219e746ac Additional small scale core changes 2014-10-18 21:56:49 +02:00
langerhans
3070012f4e Step 4: Core changes, including difficulty, auxpow and fee calculation 2014-10-18 21:52:53 +02:00
langerhans
dc689369f8 Step 3: Update the network params 2014-10-18 20:39:05 +02:00
langerhans
ac896faac9 Remove Bitcoin peers 2014-10-18 20:05:21 +02:00
langerhans
cda772d8ec Step 2: Move and refactor packages 2014-10-18 20:02:01 +02:00
langerhans
38b89b1e3d Update pom once more 2014-10-18 20:01:33 +02:00
langerhans
1243a4fb6a Update orchid hash 2014-10-18 19:57:58 +02:00
langerhans
e73ff6b53c Step 1: Update pom descriptors 2014-10-18 19:16:39 +02:00
742 changed files with 7043 additions and 151015 deletions

7
.gitignore vendored
View File

@@ -1,4 +1,5 @@
target
core/target
namecoin/target
.project
.classpath
.settings
@@ -7,3 +8,7 @@ target
*.chain
*.spvchain
*.wallet
/nbproject/private/
/build/
/.gradle/
/bin/

View File

@@ -1,20 +0,0 @@
# configuration for https://travis-ci.org/bitcoinj/bitcoinj
language: java
jdk: oraclejdk8
install: true # remove default
script:
- mvn -q clean install
- jdk_switcher use openjdk6
- cd orchid
- mvn -q clean package
- cd ../core
- mvn -q clean package
after_success:
- cd ../core
- mvn jacoco:report coveralls:report
notifications:
irc:
channels: "irc.freenode.net#bitcoinj"
skip_join: true

View File

@@ -1,57 +1,48 @@
Build status: [![Build Status](https://travis-ci.org/bitcoinj/bitcoinj.png?branch=master)](https://travis-ci.org/bitcoinj/bitcoinj)
Coverage status: [![Coverage Status](https://coveralls.io/repos/bitcoinj/bitcoinj/badge.png?branch=master)](https://coveralls.io/r/bitcoinj/bitcoinj?branch=master)
[![Apache-2](https://img.shields.io/badge/license-Apache-2.svg)](COPYING)
[![](https://jitpack.io/v/jjos2372/altcoinj.svg)](https://jitpack.io/#jjos2372/altcoinj)
### Welcome to bitcoinj
The bitcoinj library is a Java implementation of the Bitcoin protocol, which allows it to maintain a wallet and send/receive transactions without needing a local copy of Bitcoin Core. It comes with full documentation and some example apps showing how to use it.
### Welcome to altcoinj
### Technologies
The altcoinj library (forked from [libdohj](https://github.com/dogecoin/libdohj)) is a lightweight
Java library around [bitcoinj](https://bitcoinj.github.io/),
with updated support for Litecoin and Dogecoin.
* Java 6 for the core modules, Java 8 for everything else
* [Maven 3+](http://maven.apache.org) - for building the project
* [Orchid](https://github.com/subgraph/Orchid) - for secure communications over [TOR](https://www.torproject.org)
* [Google Protocol Buffers](https://code.google.com/p/protobuf/) - for use with serialization and hardware communications
Pull requests for support for other altcoins would be welcomed.
### Getting started
To get started, it is best to have the latest JDK and Maven installed. The HEAD of the `master` branch contains the latest development code and various production releases are provided on feature branches.
You should be familiar with [bitcoinj](https://bitcoinj.github.io/) first, as this library simply adds minor
changes to extend bitcoinj. Generally using altcoinj is equivalent to using
bitcoinj, except with different network parameters (reflecting altcoin consensus
in place of Bitcoin).
Be aware however that altcoin blocks have their own class, AltcoinBlock, which
adds support for features such as AuxPoW.
To use altcoinj in your own project, just add the following to your gradle.build file:
```
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
compile 'com.github.jjos2372:altcoinj:f26e20bb13'
compile 'org.bitcoinj:bitcoinj-core:0.15.6'
}
```
For maven, sbt, and leiningen check [jitpack](https://jitpack.io/#jjos2372/altcoinj).
#### Building from the command line
To perform a full build use
Simply run on the command line
```
mvn clean package
./gradlew jar
```
You can also run
```
mvn site:site
```
to generate a website with useful information like JavaDocs.
The outputs are under the `target` directory.
The outputs are under the `build` directory.
#### Building from an IDE
Alternatively, just import the project using your IDE. [IntelliJ](http://www.jetbrains.com/idea/download/) has Maven integration built-in and has a free Community Edition. Simply use `File | Import Project` and locate the `pom.xml` in the root of the cloned project source tree.
Alternatively, just import the project on your preferred IDE as a *gradle* project.
### Example applications
These are found in the `examples` module.
#### Forwarding service
This will download the block chain and eventually print a Bitcoin address that it has generated.
If you send coins to that address, it will forward them on to the address you specified.
```
cd examples
mvn exec:java -Dexec.mainClass=org.bitcoinj.examples.ForwardingService -Dexec.args="<insert a bitcoin address here>"
```
Note that this example app *does not use checkpointing*, so the initial chain sync will be pretty slow. You can make an app that starts up and does the initial sync much faster by including a checkpoints file; see the documentation for
more info on this technique.
### Where next?
Now you are ready to [follow the tutorial](https://bitcoinj.github.io/getting-started).

38
build.gradle Normal file
View File

@@ -0,0 +1,38 @@
apply plugin: 'java'
apply plugin: 'maven'
// Publishing stuff
group = 'com.github.jjos2372'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
}
dependencies {
compile 'org.bitcoinj:bitcoinj-core:0.15.10'
}
sourceSets {
main.java.srcDirs = ['core/src/main/java']
main.resources.srcDirs = ['core/src/main/resources']
}
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives sourcesJar
archives javadocJar
}

View File

@@ -1,48 +0,0 @@
<!--
~ Copyright 2012 Google Inc.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FindBugsFilter>
<Match>
<!-- Protos and inner classes are generated by the proto compiler -->
<Package name="org.bitcoinj.protos"/>
<Package name="org.bitcoin.protocols.payments"/>
</Match>
<!-- bitcoinj is not designed to run in an environment with malicious code loaded into the VM -->
<Match>
<Bug category="MALICIOUS_CODE"/>
</Match>
<!-- Ignore serialization bugs for now, it's not a high priority anymore -->
<Match>
<Bug code="Se"/>
</Match>
<!-- This is flagging a valid issue but the real bug is in the JDK. See issue 173. -->
<Match>
<Bug pattern="LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE"/>
</Match>
<!-- The code is correct but findbugs can't analyze it properly -->
<Match>
<Bug code="SF"/>
<Class name="org.bitcoinj.core.BloomFilter"/>
</Match>
<!-- fb doesn't like the odd API this class has -->
<Match>
<Class name="~.*SendRequest.*"/>
</Match>
</FindBugsFilter>

View File

@@ -1,475 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2012 Google Inc.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-parent</artifactId>
<version>0.13-SNAPSHOT</version>
</parent>
<artifactId>bitcoinj-core</artifactId>
<name>bitcoinj</name>
<description>A Java Bitcoin library</description>
<packaging>jar</packaging>
<url>https://bitcoinj.github.io</url>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<!-- Dummy block to make Maven Central happy: authors list is in AUTHORS -->
<developers>
<developer>
<name>The bitcoinj team</name>
<email>bitcoinj@googlegroups.com</email>
</developer>
</developers>
<profiles>
<profile>
<id>update-protobuf</id>
<activation>
<property>
<name>updateProtobuf</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>compile-protoc</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<path id="proto.path">
<fileset dir="src">
<include name="**/*.proto"/>
</fileset>
</path>
<pathconvert pathsep=" " property="proto.files" refid="proto.path"/>
<exec executable="protoc" failonerror="true">
<arg value="--java_out=${project.basedir}/src/main/java"/>
<arg value="-I${project.basedir}/src"/>
<arg line="${proto.files}"/>
</exec>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build>
<plugins>
<!-- Ensure compilation is done under Java 6 for backwards compatibility -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<!-- Generate source and javadoc jars: Maven Central requires this -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<detectLinks/>
<links>
<link>http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/</link>
</links>
<detectJavaApiLink/>
</configuration>
</plugin>
<!-- Verify the dependency chain: see https://github.com/gary-rowe/BitcoinjEnforcerRules for
more information on this.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>enforce</id>
<phase>verify</phase>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<DependencyConvergence/>
<digestRule implementation="uk.co.froot.maven.enforcer.DigestRule">
<!-- Create a snapshot to build the list of URNs below -->
<buildSnapshot>true</buildSnapshot>
<!-- List of required hashes -->
<!-- Format is URN of groupId:artifactId:version:type:classifier:scope:hash -->
<!-- classifier is "null" if not present -->
<urns>
<urn>org.bitcoinj:orchid:1.1:jar:null:compile:cc54aa849a4c3f5b3bfda90dd4286205b2a60e87</urn>
<urn>cglib:cglib-nodep:2.2:jar:null:test:59afed7ab65e7ec6585d5bc60556c3cbd203532b</urn>
<urn>com.google.code.findbugs:jsr305:2.0.1:jar:null:compile:516c03b21d50a644d538de0f0369c620989cd8f0</urn>
<urn>com.google.guava:guava:16.0.1:jar:null:compile:5fa98cd1a63c99a44dd8d3b77e4762b066a5d0c5</urn>
<urn>com.google.protobuf:protobuf-java:2.5.0:jar:null:compile:a10732c76bfacdbd633a7eb0f7968b1059a65dfa</urn>
<urn>com.h2database:h2:1.3.167:jar:null:compile:d3867d586f087e53eb12fc65e5693d8ee9a5da17</urn>
<urn>com.lambdaworks:scrypt:1.4.0:jar:null:compile:906506b74f30c8c20bccd9ed4a11112d8941fe87</urn>
<urn>com.madgag.spongycastle:core:1.51.0.0:jar:null:compile:0f642963312ea0e615ad65f28adc5a5b3a2a0862</urn>
<urn>junit:junit:4.11:jar:null:test:4e031bb61df09069aeb2bffb4019e7a5034a4ee0</urn>
<urn>net.jcip:jcip-annotations:1.0:jar:null:compile:afba4942caaeaf46aab0b976afd57cc7c181467e</urn>
<urn>org.apache.maven.plugins:maven-clean-plugin:2.5:maven-plugin:null:runtime:75653decaefa85ca8114ff3a4f869bb2ee6d605d</urn>
<urn>org.apache.maven.plugins:maven-compiler-plugin:3.1:maven-plugin:null:runtime:9977a8d04e75609cf01badc4eb6a9c7198c4c5ea</urn>
<urn>org.apache.maven.plugins:maven-dependency-plugin:2.8:maven-plugin:null:runtime:04c8dedf3d9b2a3f45f3daa93e11ca547d2063ca</urn>
<urn>org.apache.maven.plugins:maven-deploy-plugin:2.7:maven-plugin:null:runtime:6dadfb75679ca010b41286794f737088ebfe12fd</urn>
<urn>org.apache.maven.plugins:maven-enforcer-plugin:1.2:maven-plugin:null:runtime:6b755a9a0d618f8f57c0b5c4a0737a012e710a46</urn>
<urn>org.apache.maven.plugins:maven-install-plugin:2.5.1:maven-plugin:null:runtime:b6f5a4b621b9c26699c8deadb20fdc35ce568e35</urn>
<urn>org.apache.maven.plugins:maven-jar-plugin:2.5:maven-plugin:null:runtime:344d667f5ec8b90d03d698d096a1147672fc522f</urn>
<urn>org.apache.maven.plugins:maven-javadoc-plugin:2.9.1:maven-plugin:null:runtime:95ea7abf00e37e08bd927bf7e448c1e7fe4c6cb9</urn>
<urn>org.apache.maven.plugins:maven-resources-plugin:2.6:maven-plugin:null:runtime:dd093ff6a4b680eae7ae83b5ab04310249fc6590</urn>
<urn>org.apache.maven.plugins:maven-shade-plugin:2.3:maven-plugin:null:runtime:d136adc7abccc9c12adcad6ae7a9bc51b2b7184b</urn>
<urn>org.apache.maven.plugins:maven-site-plugin:3.3:maven-plugin:null:runtime:77ba1752b1ac4c4339d6f11554800960a56a4ae1</urn>
<urn>org.apache.maven.plugins:maven-source-plugin:2.1.2:maven-plugin:null:runtime:35154aa8e6e0e84c2b5c10c3d5220d65670ba984</urn>
<urn>org.apache.maven.plugins:maven-surefire-plugin:2.12.4:maven-plugin:null:runtime:2b435f7f77777d2e62354fdc690da3f1dc47a26b</urn>
<urn>org.codehaus.mojo:cobertura-maven-plugin:2.6:maven-plugin:null:runtime:5204735a0642b42f5647d8ec876d4301e328c0d5</urn>
<urn>org.easymock:easymock:3.0:jar:null:test:f28a4c31c330f95c9acbf1108cea19952b5c496f</urn>
<urn>org.hamcrest:hamcrest-core:1.3:jar:null:test:42a25dc3219429f0e5d060061f71acb49bf010a0</urn>
<urn>org.objenesis:objenesis:1.2:jar:null:test:bfcb0539a071a4c5a30690388903ac48c0667f2a</urn>
<urn>org.slf4j:slf4j-api:1.7.6:jar:null:compile:562424e36df3d2327e8e9301a76027fca17d54ea</urn>
<urn>org.slf4j:slf4j-jdk14:1.7.6:jar:null:test:1a3301a32ea7d90c3d33e9d60edbfdc9589fc748</urn>
<url>com.fasterxml.jackson.core:jackson-databind:2.4.2:jar:null:test:8e31266a272ad25ac4c089734d93e8d811652c1f</url>
<url>com.fasterxml.jackson.core:jackson-core:2.4.2:jar:null:test:ceb72830d95c512b4b300a38f29febc85bdf6e4b</url>
<url>com.fasterxml.jackson.core:jackson-annotations:2.4.2:jar:null:test:6bb52af09372d5064206d47d7887d41671f00f7d</url>
<urn>org.jacoco:jacoco-maven-plugin:0.7.2.201409121644:maven-plugin:null:runtime:b2cb310459d082db505fdfa66dbadd4d8bac8e34</urn>
<urn>org.eluder.coveralls:coveralls-maven-plugin:3.0.1:maven-plugin:null:runtime:3907ee5cf1e5c85af7bb90e486ce4c7b1408a552</urn>
<!-- A check for the rules themselves -->
<urn>uk.co.froot.maven.enforcer:digest-enforcer-rules:0.0.1:jar:null:runtime:16a9e04f3fe4bb143c42782d07d5faf65b32106f</urn>
</urns>
</digestRule>
</rules>
</configuration>
</execution>
</executions>
<!-- Ensure we download the enforcer rules -->
<dependencies>
<dependency>
<groupId>uk.co.froot.maven.enforcer</groupId>
<artifactId>digest-enforcer-rules</artifactId>
<version>0.0.1</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<!-- Create the bundled JAR, it's easier for some people -->
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>false</minimizeJar>
<filters>
<filter>
<!-- exclude signatures, the bundling process breaks them for some reason -->
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>bundled</shadedClassifierName>
</configuration>
</execution>
</executions>
</plugin>
<!-- Code coverage plugin, generates coverage report to target/site/jacoco/
To skip coverage generation add -Djacoco.skip=true
-->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.2.201409121644</version>
<configuration>
<excludes>
<exclude>**/Protos*.class</exclude> <!-- Exclude generated protobuf classes -->
<exclude>org/bitcoinj/jni/*</exclude> <!-- Exclude JNI classes -->
<exclude>org/bitcoin/*</exclude> <!-- Exclude native classes -->
</excludes>
</configuration>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/coverage-reports/jacoco.exec</destFile>
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage-reports/jacoco.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco</outputDirectory>
</configuration>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Unit tests plugin, to skip runing test add -Dmaven.test.skip -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<argLine>${surefireArgLine}</argLine> <!-- This is required for code coverage to work. -->
</configuration>
</plugin>
<!-- Coveralls is a online code coverage tool, you can track code coverage here: https://coveralls.io/r/bitcoinj/bitcoinj -->
<plugin>
<groupId>org.eluder.coveralls</groupId>
<artifactId>coveralls-maven-plugin</artifactId>
<version>3.0.1</version>
</plugin>
<!-- Create a bundled executable test jar that runs the regtester/pulltester.
The comparison tool is kind of messy and badly needs a seriously refactoring.
It depends on classes which are only in the test tree so we must do some
Maven kung fu here to create a bundle of it, as I couldn't make Maven Shade
do bundling on the test jar for some reason. Maven kind of sucks ...
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unzip-lib</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<artifactItems>
<artifactItem>
<outputDirectory>target/test-classes/</outputDirectory>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>${project.version}</version>
</artifactItem>
</artifactItems>
</configuration>
</execution>
<execution>
<id>unzip-deps</id>
<phase>package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<outputDirectory>target/test-classes/</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>org.bitcoinj.core.BitcoindComparisonTool</mainClass>
<addClasspath>false</addClasspath>
</manifest>
</archive>
<finalName>pull</finalName> <!-- becomes pull-tests.jar on disk (hacky) -->
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.0</version>
<scope>test</scope>
</dependency>
<!-- bitcoinj consumers are expected to provide their own SLF4J adapters
such as logback, slf4j-log4j12, slf4j-jcl and so on
see http://www.slf4j.org/faq.html -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.167</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.madgag.spongycastle</groupId>
<artifactId>core</artifactId>
<version>1.51.0.0</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>2.5.0</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>16.0.1</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.lambdaworks</groupId>
<artifactId>scrypt</artifactId>
<version>1.4.0</version>
</dependency>
<!-- Note this is an optional dependency: Postgres blockstore -->
<!-- To Test remove optional -->
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-901.jdbc4</version>
<optional>true</optional>
</dependency>
<!-- Note this is an optional dependency: MySQL blockstore -->
<!-- To Test remove optional -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.33</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>orchid</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
</project>

View File

@@ -15,25 +15,49 @@
* limitations under the License.
*/
package org.bitcoinj.protocols.payments;
package com.dogecoin.dogecoinj.protocols.payments;
import org.bitcoinj.core.*;
import java.io.Serializable;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidator;
import java.security.cert.CertPathValidatorException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException;
import java.security.cert.PKIXCertPathValidatorResult;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import org.bitcoin.protocols.payments.Protos;
import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Utils;
import org.bitcoinj.crypto.X509Utils;
import org.bitcoinj.script.ScriptBuilder;
import com.google.common.base.Objects;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import org.bitcoin.protocols.payments.Protos;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Utility methods and constants for working with <a href="https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki">
@@ -46,10 +70,10 @@ import java.util.List;
*/
public class PaymentProtocol {
// MIME types as defined in BIP71.
public static final String MIMETYPE_PAYMENTREQUEST = "application/bitcoin-paymentrequest";
public static final String MIMETYPE_PAYMENT = "application/bitcoin-payment";
public static final String MIMETYPE_PAYMENTACK = "application/bitcoin-paymentack";
// MIME types as defined in DIP71.
public static final String MIMETYPE_PAYMENTREQUEST = "application/vnd.doge.payment.request";
public static final String MIMETYPE_PAYMENT = "application/vnd.doge.payment.payment";
public static final String MIMETYPE_PAYMENTACK = "application/vnd.doge.payment.ack";
/**
* Create a payment request with one standard pay to address output. You may want to sign the request using
@@ -270,7 +294,7 @@ public class PaymentProtocol {
@Override
public String toString() {
return Objects.toStringHelper(this)
return MoreObjects.toStringHelper(this)
.add("displayName", displayName)
.add("rootAuthorityName", rootAuthorityName)
.add("merchantSigningKey", merchantSigningKey)

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.bitcoinj.protocols.payments;
package com.dogecoin.dogecoinj.protocols.payments;
import java.security.cert.X509Certificate;
import java.util.List;

View File

@@ -12,12 +12,13 @@
* limitations under the License.
*/
package org.bitcoinj.protocols.payments;
package com.dogecoin.dogecoinj.protocols.payments;
import com.dogecoin.dogecoinj.protocols.payments.PaymentProtocol.PkiVerificationData;
import org.bitcoinj.core.*;
import org.bitcoinj.wallet.SendRequest;
import org.bitcoinj.crypto.TrustStoreLoader;
import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.protocols.payments.PaymentProtocol.PkiVerificationData;
import org.bitcoinj.uri.BitcoinURI;
import org.bitcoinj.utils.Threading;
import com.google.common.annotations.VisibleForTesting;
@@ -291,13 +292,13 @@ public class PaymentSession {
}
/**
* Returns a {@link Wallet.SendRequest} suitable for broadcasting to the network.
Returns a {@link SendRequest} suitable for broadcasting to the network.
*/
public Wallet.SendRequest getSendRequest() {
public SendRequest getSendRequest() {
Transaction tx = new Transaction(params);
for (Protos.Output output : paymentDetails.getOutputsList())
tx.addOutput(new TransactionOutput(params, tx, Coin.valueOf(output.getAmount()), output.getScript().toByteArray()));
return Wallet.SendRequest.forTx(tx).fromPaymentDetails(paymentDetails);
return SendRequest.forTx(tx).fromPaymentDetails(paymentDetails);
}
/**

View File

@@ -2,4 +2,4 @@
* The BIP70 payment protocol wraps Bitcoin transactions and adds various useful features like memos, refund addresses
* and authentication.
*/
package org.bitcoinj.protocols.payments;
package com.dogecoin.dogecoinj.protocols.payments;

View File

@@ -1,78 +0,0 @@
/**
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoin;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.google.common.base.Preconditions;
/**
* <p>This class holds native methods to handle ECDSA verification.</p>
*
* <p>You can find an example library that can be used for this at https://github.com/sipa/secp256k1</p>
*
* <p>To build secp256k1 for use with bitcoinj, run `./configure` and `make libjavasecp256k1.so` then copy
* libjavasecp256k1.so to your system library path or point the JVM to the folder containing it with -Djava.library.path
* </p>
*/
public class NativeSecp256k1 {
public static boolean enabled = false;
static {
try {
System.loadLibrary("javasecp256k1");
} catch (UnsatisfiedLinkError e) {
enabled = false;
}
}
private static ThreadLocal<ByteBuffer> nativeECDSABuffer = new ThreadLocal<ByteBuffer>();
/**
* Verifies the given secp256k1 signature in native code.
* Calling when enabled == false is undefined (probably library not loaded)
*
* @param data The data which was signed, must be exactly 32 bytes
* @param signature The signature
* @param pub The public key which did the signing
*/
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520);
ByteBuffer byteBuff = nativeECDSABuffer.get();
if (byteBuff == null) {
byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520);
byteBuff.order(ByteOrder.nativeOrder());
nativeECDSABuffer.set(byteBuff);
}
byteBuff.rewind();
byteBuff.put(data);
byteBuff.putInt(signature.length);
byteBuff.putInt(pub.length);
byteBuff.put(signature);
byteBuff.put(pub);
return secp256k1_ecdsa_verify(byteBuff) == 1;
}
/**
* @param byteBuff signature format is byte[32] data,
* native-endian int signatureLength, native-endian int pubkeyLength,
* byte[signatureLength] signature, byte[pubkeyLength] pub
* @returns 1 for valid signature, anything else for invalid
*/
private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,48 +0,0 @@
/**
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.util.List;
/**
* Default no-op implementation of {@link BlockChainListener}.
*/
public class AbstractBlockChainListener implements BlockChainListener {
@Override
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
}
@Override
public void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks, List<StoredBlock> newBlocks) throws VerificationException {
}
@Override
public boolean isTransactionRelevant(Transaction tx) throws ScriptException {
return false;
}
@Override
public void receiveFromBlock(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException {
}
@Override
public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block, BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException {
return false;
}
}

View File

@@ -1,60 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.util.List;
import java.util.Set;
/**
* Convenience implementation of {@link PeerEventListener}.
*/
public class AbstractPeerEventListener implements PeerEventListener {
@Override
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
}
@Override
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) {
}
@Override
public void onChainDownloadStarted(Peer peer, int blocksLeft) {
}
@Override
public void onPeerConnected(Peer peer, int peerCount) {
}
@Override
public void onPeerDisconnected(Peer peer, int peerCount) {
}
@Override
public Message onPreMessageReceived(Peer peer, Message m) {
// Just pass the message right through for further processing.
return m;
}
@Override
public void onTransaction(Peer peer, Transaction t) {
}
@Override
public List<Message> getData(Peer peer, GetDataMessage m) {
return null;
}
}

View File

@@ -1,65 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.wallet.AbstractKeyChainEventListener;
import java.util.List;
/**
* Convenience implementation of {@link WalletEventListener}.
*/
public abstract class AbstractWalletEventListener extends AbstractKeyChainEventListener implements WalletEventListener {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
onChange();
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
onChange();
}
@Override
public void onReorganize(Wallet wallet) {
onChange();
}
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
onChange();
}
@Override
public void onKeysAdded(List<ECKey> keys) {
onChange();
}
@Override
public void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts) {
onChange();
}
@Override
public void onWalletChanged(Wallet wallet) {
onChange();
}
public void onChange() {
}
}

View File

@@ -1,179 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Giannis Dzegoutanis
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.params.Networks;
import org.bitcoinj.script.Script;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* <p>A Bitcoin address looks like 1MsScoe2fTJoq4ZPdQgqyhgWeoNamYPevy and is derived from an elliptic curve public key
* plus a set of network parameters. Not to be confused with a {@link PeerAddress} or {@link AddressMessage}
* which are about network (TCP) addresses.</p>
*
* <p>A standard address is built by taking the RIPE-MD160 hash of the public key bytes, with a version prefix and a
* checksum suffix, then encoding it textually as base58. The version prefix is used to both denote the network for
* which the address is valid (see {@link NetworkParameters}, and also to indicate how the bytes inside the address
* should be interpreted. Whilst almost all addresses today are hashes of public keys, another (currently unsupported
* type) can contain a hash of a script instead.</p>
*/
public class Address extends VersionedChecksummedBytes {
/**
* An address is a RIPEMD160 hash of a public key, therefore is always 160 bits or 20 bytes.
*/
public static final int LENGTH = 20;
transient final NetworkParameters params;
/**
* Construct an address from parameters, the address version, and the hash160 form. Example:<p>
*
* <pre>new Address(MainNetParams.get(), NetworkParameters.getAddressHeader(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre>
*/
public Address(NetworkParameters params, int version, byte[] hash160) throws WrongNetworkException {
super(version, hash160);
checkNotNull(params);
checkArgument(hash160.length == 20, "Addresses are 160-bit hashes, so you must provide 20 bytes");
if (!isAcceptableVersion(params, version))
throw new WrongNetworkException(version, params.getAcceptableAddressCodes());
this.params = params;
}
/** Returns an Address that represents the given P2SH script hash. */
public static Address fromP2SHHash(NetworkParameters params, byte[] hash160) {
try {
return new Address(params, params.getP2SHHeader(), hash160);
} catch (WrongNetworkException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/** Returns an Address that represents the script hash extracted from the given scriptPubKey */
public static Address fromP2SHScript(NetworkParameters params, Script scriptPubKey) {
checkArgument(scriptPubKey.isPayToScriptHash(), "Not a P2SH script");
return fromP2SHHash(params, scriptPubKey.getPubKeyHash());
}
/**
* Construct an address from parameters and the hash160 form. Example:<p>
*
* <pre>new Address(MainNetParams.get(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre>
*/
public Address(NetworkParameters params, byte[] hash160) {
super(params.getAddressHeader(), hash160);
checkArgument(hash160.length == 20, "Addresses are 160-bit hashes, so you must provide 20 bytes");
this.params = params;
}
/**
* Construct an address from parameters and the standard "human readable" form. Example:<p>
*
* <pre>new Address(MainNetParams.get(), "17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL");</pre><p>
*
* @param params The expected NetworkParameters or null if you don't want validation.
* @param address The textual form of the address, such as "17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL"
* @throws AddressFormatException if the given address doesn't parse or the checksum is invalid
* @throws WrongNetworkException if the given address is valid but for a different chain (eg testnet vs mainnet)
*/
public Address(@Nullable NetworkParameters params, String address) throws AddressFormatException {
super(address);
if (params != null) {
if (!isAcceptableVersion(params, version)) {
throw new WrongNetworkException(version, params.getAcceptableAddressCodes());
}
this.params = params;
} else {
NetworkParameters paramsFound = null;
for (NetworkParameters p : Networks.get()) {
if (isAcceptableVersion(p, version)) {
paramsFound = p;
break;
}
}
if (paramsFound == null)
throw new AddressFormatException("No network found for " + address);
this.params = paramsFound;
}
}
/** The (big endian) 20 byte hash that is the core of a Bitcoin address. */
public byte[] getHash160() {
return bytes;
}
/*
* Returns true if this address is a Pay-To-Script-Hash (P2SH) address.
* See also https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki: Address Format for pay-to-script-hash
*/
public boolean isP2SHAddress() {
final NetworkParameters parameters = getParameters();
return parameters != null && this.version == parameters.p2shHeader;
}
/**
* Examines the version byte of the address and attempts to find a matching NetworkParameters. If you aren't sure
* which network the address is intended for (eg, it was provided by a user), you can use this to decide if it is
* compatible with the current wallet. You should be able to handle a null response from this method. Note that the
* parameters returned is not necessarily the same as the one the Address was created with.
*
* @return a NetworkParameters representing the network the address is intended for.
*/
public NetworkParameters getParameters() {
return params;
}
/**
* Given an address, examines the version byte and attempts to find a matching NetworkParameters. If you aren't sure
* which network the address is intended for (eg, it was provided by a user), you can use this to decide if it is
* compatible with the current wallet.
* @return a NetworkParameters of the address
* @throws AddressFormatException if the string wasn't of a known version
*/
public static NetworkParameters getParametersFromAddress(String address) throws AddressFormatException {
try {
return new Address(null, address).getParameters();
} catch (WrongNetworkException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/**
* Check if a given address version is valid given the NetworkParameters.
*/
private static boolean isAcceptableVersion(NetworkParameters params, int version) {
for (int v : params.getAcceptableAddressCodes()) {
if (version == v) {
return true;
}
}
return false;
}
/**
* This implementation narrows the return type to <code>Address</code>.
*/
@Override
public Address clone() throws CloneNotSupportedException {
return (Address) super.clone();
}
}

View File

@@ -1,28 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
@SuppressWarnings("serial")
public class AddressFormatException extends Exception {
public AddressFormatException() {
super();
}
public AddressFormatException(String message) {
super(message);
}
}

View File

@@ -1,154 +0,0 @@
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Represents an "addr" message on the P2P network, which contains broadcast IP addresses of other peers. This is
* one of the ways peers can find each other without using the DNS or IRC discovery mechanisms. However storing and
* using addr messages is not presently implemented.
*/
public class AddressMessage extends Message {
private static final long serialVersionUID = 8058283864924679460L;
private static final long MAX_ADDRESSES = 1024;
private List<PeerAddress> addresses;
private transient long numAddresses = -1;
/**
* Contruct a new 'addr' message.
* @param params NetworkParameters object.
* @param offset The location of the first payload byte within the array.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
AddressMessage(NetworkParameters params, byte[] payload, int offset, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
super(params, payload, offset, parseLazy, parseRetain, length);
}
/**
* Contruct a new 'addr' message.
* @param params NetworkParameters object.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
AddressMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
super(params, payload, 0, parseLazy, parseRetain, length);
}
AddressMessage(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset, false, false, UNKNOWN_LENGTH);
}
AddressMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0, false, false, UNKNOWN_LENGTH);
}
@Override
protected void parseLite() throws ProtocolException {
}
@Override
void parse() throws ProtocolException {
numAddresses = readVarInt();
// Guard against ultra large messages that will crash us.
if (numAddresses > MAX_ADDRESSES)
throw new ProtocolException("Address message too large.");
addresses = new ArrayList<PeerAddress>((int) numAddresses);
for (int i = 0; i < numAddresses; i++) {
PeerAddress addr = new PeerAddress(params, payload, cursor, protocolVersion, this, parseLazy, parseRetain);
addresses.add(addr);
cursor += addr.getMessageSize();
}
length = cursor - offset;
}
/* (non-Javadoc)
* @see Message#bitcoinSerializeToStream(java.io.OutputStream)
*/
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (addresses == null)
return;
stream.write(new VarInt(addresses.size()).encode());
for (PeerAddress addr : addresses) {
addr.bitcoinSerialize(stream);
}
}
@Override
public int getMessageSize() {
if (length != UNKNOWN_LENGTH)
return length;
if (addresses != null) {
length = new VarInt(addresses.size()).getSizeInBytes();
// The 4 byte difference is the uint32 timestamp that was introduced in version 31402
length += addresses.size() * (protocolVersion > 31402 ? PeerAddress.MESSAGE_SIZE : PeerAddress.MESSAGE_SIZE - 4);
}
return length;
}
/**
* AddressMessage cannot cache checksum in non-retain mode due to dynamic time being used.
*/
@Override
void setChecksum(byte[] checksum) {
if (parseRetain)
super.setChecksum(checksum);
else
this.checksum = null;
}
/**
* @return An unmodifiableList view of the backing List of addresses. Addresses contained within the list may be safely modified.
*/
public List<PeerAddress> getAddresses() {
maybeParse();
return Collections.unmodifiableList(addresses);
}
public void addAddress(PeerAddress address) {
unCache();
maybeParse();
address.setParent(this);
addresses.add(address);
if (length == UNKNOWN_LENGTH)
getMessageSize();
else
length += address.getMessageSize();
}
public void removeAddress(int index) {
unCache();
PeerAddress address = addresses.remove(index);
address.setParent(null);
if (length == UNKNOWN_LENGTH)
getMessageSize();
else
length -= address.getMessageSize();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("addr: ");
for (PeerAddress a : addresses) {
builder.append(a.toString());
builder.append(" ");
}
return builder.toString();
}
}

View File

@@ -1,255 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
/**
* Alerts are signed messages that are broadcast on the peer-to-peer network if they match a hard-coded signing key.
* The private keys are held by a small group of core Bitcoin developers, and alerts may be broadcast in the event of
* an available upgrade or a serious network problem. Alerts have an expiration time, data that specifies what
* set of software versions it matches and the ability to cancel them by broadcasting another type of alert.<p>
*
* The right course of action on receiving an alert is usually to either ensure a human will see it (display on screen,
* log, email), or if you decide to use alerts for notifications that are specific to your app in some way, to parse it.
* For example, you could treat it as an upgrade notification specific to your app. Satoshi designed alerts to ensure
* that software upgrades could be distributed independently of a hard-coded website, in order to allow everything to
* be purely peer-to-peer. You don't have to use this of course, and indeed it often makes more sense not to.<p>
*
* Before doing anything with an alert, you should check {@link AlertMessage#isSignatureValid()}.
*/
public class AlertMessage extends Message {
private byte[] content;
private byte[] signature;
// See the getters for documentation of what each field means.
private long version = 1;
private Date relayUntil;
private Date expiration;
private long id;
private long cancel;
private Set<Long> cancelSet;
private long minVer, maxVer;
private Set<String> matchingSubVers;
private long priority;
private String comment, statusBar, reserved;
// Chosen arbitrarily to avoid memory blowups.
private static final long MAX_SET_SIZE = 100;
public AlertMessage(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
@Override
public String toString() {
return "ALERT: " + getStatusBar();
}
@Override
void parse() throws ProtocolException {
// Alerts are formatted in two levels. The top level contains two byte arrays: a signature, and a serialized
// data structure containing the actual alert data.
int startPos = cursor;
content = readByteArray();
signature = readByteArray();
// Now we need to parse out the contents of the embedded structure. Rewind back to the start of the message.
cursor = startPos;
readVarInt(); // Skip the length field on the content array.
// We're inside the embedded structure.
version = readUint32();
// Read the timestamps. Bitcoin uses seconds since the epoch.
relayUntil = new Date(readUint64().longValue() * 1000);
expiration = new Date(readUint64().longValue() * 1000);
id = readUint32();
cancel = readUint32();
// Sets are serialized as <len><item><item><item>....
long cancelSetSize = readVarInt();
if (cancelSetSize < 0 || cancelSetSize > MAX_SET_SIZE) {
throw new ProtocolException("Bad cancel set size: " + cancelSetSize);
}
// Using a hashset here is very inefficient given that this will normally be only one item. But Java doesn't
// make it easy to do better. What we really want is just an array-backed set.
cancelSet = new HashSet<Long>((int)cancelSetSize);
for (long i = 0; i < cancelSetSize; i++) {
cancelSet.add(readUint32());
}
minVer = readUint32();
maxVer = readUint32();
// Read the subver matching set.
long subverSetSize = readVarInt();
if (subverSetSize < 0 || subverSetSize > MAX_SET_SIZE) {
throw new ProtocolException("Bad subver set size: " + subverSetSize);
}
matchingSubVers = new HashSet<String>((int)subverSetSize);
for (long i = 0; i < subverSetSize; i++) {
matchingSubVers.add(readStr());
}
priority = readUint32();
comment = readStr();
statusBar = readStr();
reserved = readStr();
length = cursor - offset;
}
/**
* Returns true if the digital signature attached to the message verifies. Don't do anything with the alert if it
* doesn't verify, because that would allow arbitrary attackers to spam your users.
*/
public boolean isSignatureValid() {
return ECKey.verify(Utils.doubleDigest(content), signature, params.getAlertSigningKey());
}
@Override
protected void parseLite() throws ProtocolException {
// Do nothing, lazy parsing isn't useful for alerts.
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Field accessors.
/**
* The time at which the alert should stop being broadcast across the network. Note that you can still receive
* the alert after this time from other nodes if the alert still applies to them or to you.
*/
public Date getRelayUntil() {
return relayUntil;
}
public void setRelayUntil(Date relayUntil) {
this.relayUntil = relayUntil;
}
/**
* The time at which the alert ceases to be relevant. It should not be presented to the user or app administrator
* after this time.
*/
public Date getExpiration() {
return expiration;
}
public void setExpiration(Date expiration) {
this.expiration = expiration;
}
/**
* The numeric identifier of this alert. Each alert should have a unique ID, but the signer can choose any number.
* If an alert is broadcast with a cancel field higher than this ID, this alert is considered cancelled.
* @return uint32
*/
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
/**
* A marker that results in any alerts with an ID lower than this value to be considered cancelled.
* @return uint32
*/
public long getCancel() {
return cancel;
}
public void setCancel(long cancel) {
this.cancel = cancel;
}
/**
* The inclusive lower bound on software versions that are considered for the purposes of this alert. The Satoshi
* client compares this against a protocol version field, but as long as the subVer field is used to restrict it your
* alerts could use any version numbers.
* @return uint32
*/
public long getMinVer() {
return minVer;
}
public void setMinVer(long minVer) {
this.minVer = minVer;
}
/**
* The inclusive upper bound on software versions considered for the purposes of this alert. The Satoshi
* client compares this against a protocol version field, but as long as the subVer field is used to restrict it your
* alerts could use any version numbers.
* @return
*/
public long getMaxVer() {
return maxVer;
}
public void setMaxVer(long maxVer) {
this.maxVer = maxVer;
}
/**
* Provides an integer ordering amongst simultaneously active alerts.
* @return uint32
*/
public long getPriority() {
return priority;
}
public void setPriority(long priority) {
this.priority = priority;
}
/**
* This field is unused. It is presumably intended for the author of the alert to provide a justification for it
* visible to protocol developers but not users.
*/
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
/**
* A string that is intended to display in the status bar of the official GUI client. It contains the user-visible
* message. English only.
*/
public String getStatusBar() {
return statusBar;
}
public void setStatusBar(String statusBar) {
this.statusBar = statusBar;
}
/**
* This field is never used.
*/
public String getReserved() {
return reserved;
}
public void setReserved(String reserved) {
this.reserved = reserved;
}
public long getVersion() {
return version;
}
}

View File

@@ -0,0 +1,306 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import static org.bitcoinj.core.Utils.reverseBytes;
import static org.libdohj.core.Utils.scryptDigest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.util.BitSet;
import java.util.List;
import javax.annotation.Nullable;
import org.libdohj.core.AltcoinNetworkParameters;
import org.libdohj.core.AuxPoWNetworkParameters;
import org.libdohj.params.AbstractLitecoinParams;
/**
* <p>A block is a group of transactions, and is one of the fundamental data structures of the Bitcoin system.
* It records a set of {@link Transaction}s together with some data that links it into a place in the global block
* chain, and proves that a difficult calculation was done over its contents. See
* <a href="http://www.bitcoin.org/bitcoin.pdf">the Bitcoin technical paper</a> for
* more detail on blocks.
* </p>
*
* To get a block, you can either build one from the raw bytes you can get from another implementation, or request one
* specifically using {@link Peer#getBlock(Sha256Hash)}, or grab one from a downloaded {@link BlockChain}.
*/
public class AltcoinBlock extends org.bitcoinj.core.Block {
private static final int BYTE_BITS = 8;
private boolean auxpowParsed = false;
private boolean auxpowBytesValid = false;
/** AuxPoW header element, if applicable. */
@Nullable private AuxPoW auxpow;
/**
* Whether the chain this block belongs to support AuxPoW, used to avoid
* repeated instanceof checks. Initialised in parseTransactions()
*/
private boolean auxpowChain = false;
private Sha256Hash scryptHash;
/** Special case constructor, used for the genesis node, cloneAsHeader and unit tests.
* @param params NetworkParameters object.
*/
public AltcoinBlock(final NetworkParameters params, final long version) {
super(params, version);
}
/** Special case constructor, used for the genesis node, cloneAsHeader and unit tests.
* @param params NetworkParameters object.
*/
public AltcoinBlock(final NetworkParameters params, final byte[] payloadBytes) {
this(params, payloadBytes, 0, params.getDefaultSerializer(), payloadBytes.length);
}
/**
* Construct a block object from the Bitcoin wire format.
* @param params NetworkParameters object.
* @param serializer the serializer to use for this message.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
public AltcoinBlock(final NetworkParameters params, final byte[] payloadBytes,
final int offset, final MessageSerializer serializer, final int length)
throws ProtocolException {
super(params, payloadBytes, offset, serializer, length);
}
public AltcoinBlock(NetworkParameters params, byte[] payloadBytes, int offset,
Message parent, MessageSerializer serializer, int length)
throws ProtocolException {
super(params, payloadBytes, serializer, length);
}
/**
* Construct a block initialized with all the given fields.
* @param params Which network the block is for.
* @param version This should usually be set to 1 or 2, depending on if the height is in the coinbase input.
* @param prevBlockHash Reference to previous block in the chain or {@link Sha256Hash#ZERO_HASH} if genesis.
* @param merkleRoot The root of the merkle tree formed by the transactions.
* @param time UNIX time when the block was mined.
* @param difficultyTarget Number which this block hashes lower than.
* @param nonce Arbitrary number to make the block hash lower than the target.
* @param transactions List of transactions including the coinbase.
*/
public AltcoinBlock(NetworkParameters params, long version, Sha256Hash prevBlockHash, Sha256Hash merkleRoot, long time,
long difficultyTarget, long nonce, List<Transaction> transactions) {
super(params, version, prevBlockHash, merkleRoot, time, difficultyTarget, nonce, transactions);
}
private Sha256Hash calculateScryptHash() {
try {
ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(HEADER_SIZE);
writeHeader(bos);
return Sha256Hash.wrap(reverseBytes(scryptDigest(bos.toByteArray())));
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen.
} catch (GeneralSecurityException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
public AuxPoW getAuxPoW() {
return this.auxpow;
}
public void setAuxPoW(AuxPoW auxpow) {
this.auxpow = auxpow;
}
/**
* Returns the Scrypt hash of the block (which for a valid, solved block should be
* below the target). Big endian.
*/
public Sha256Hash getScryptHash() {
if (scryptHash == null)
scryptHash = calculateScryptHash();
return scryptHash;
}
/**
* Returns the Scrypt hash of the block.
*/
public String getScryptHashAsString() {
return getScryptHash().toString();
}
@Override
public Coin getBlockInflation(int height) {
final AltcoinNetworkParameters altParams = (AltcoinNetworkParameters) params;
return altParams.getBlockSubsidy(height);
}
/**
* Get the chain ID (upper 16 bits) from an AuxPoW version number.
*/
public static long getChainID(final long rawVersion) {
return rawVersion >> 16;
}
/**
* Return chain ID from block version of an AuxPoW-enabled chain.
*/
public long getChainID() {
return getChainID(this.getRawVersion());
}
/**
* Return flags from block version of an AuxPoW-enabled chain.
*
* @return flags as a bitset.
*/
public BitSet getVersionFlags() {
final BitSet bitset = new BitSet(BYTE_BITS);
final int bits = (int) (this.getRawVersion() & 0xff00) >> 8;
for (int bit = 0; bit < BYTE_BITS; bit++) {
if ((bits & (1 << bit)) > 0) {
bitset.set(bit);
}
}
return bitset;
}
/**
* Return block version without applying any filtering (i.e. for AuxPoW blocks
* which structure version differently to pack in additional data).
*/
public final long getRawVersion() {
return super.getVersion();
}
/**
* Get the base version (i.e. Bitcoin-like version number) out of a packed
* AuxPoW version number (i.e. one that contains chain ID and feature flags).
*/
public static long getBaseVersion(final long rawVersion) {
return rawVersion & 0xff;
}
@Override
public long getVersion() {
// TODO: Can we cache the individual parts on parse?
if(this.params instanceof AbstractLitecoinParams) {
return super.getVersion();
} else if (this.params instanceof AltcoinNetworkParameters) {
// AuxPoW networks use the higher block version bits for flags and
// chain ID.
return getBaseVersion(super.getVersion());
} else {
return super.getVersion();
}
}
protected void parseAuxPoW() throws ProtocolException {
if (this.auxpowParsed)
return;
this.auxpow = null;
if (this.auxpowChain) {
final AuxPoWNetworkParameters auxpowParams = (AuxPoWNetworkParameters)this.params;
if (auxpowParams.isAuxPoWBlockVersion(this.getRawVersion())
&& payload.length >= 160) { // We have at least 2 headers in an Aux block. Workaround for StoredBlocks
this.auxpow = new AuxPoW(params, payload, cursor, this, serializer);
}
}
this.auxpowParsed = true;
this.auxpowBytesValid = serializer.isParseRetainMode();
}
@Override
protected void parseTransactions(final int offset) {
this.auxpowChain = params instanceof AuxPoWNetworkParameters;
parseAuxPoW();
if (null != this.auxpow) {
super.parseTransactions(offset + auxpow.getMessageSize());
optimalEncodingMessageSize += auxpow.getMessageSize();
} else {
super.parseTransactions(offset);
}
}
@Override
void writeHeader(OutputStream stream) throws IOException {
super.writeHeader(stream);
if (null != this.auxpow) {
this.auxpow.bitcoinSerialize(stream);
}
}
/** Returns a copy of the block, but without any transactions. */
@Override
public Block cloneAsHeader() {
AltcoinBlock block = new AltcoinBlock(params, getRawVersion());
super.copyBitcoinHeaderTo(block);
block.auxpow = auxpow;
return block;
}
/** Returns true if the hash of the block is OK (lower than difficulty target). */
protected boolean checkProofOfWork(boolean throwException) throws VerificationException {
if (params instanceof AltcoinNetworkParameters) {
BigInteger target = getDifficultyTargetAsInteger();
if (params instanceof AuxPoWNetworkParameters) {
final AuxPoWNetworkParameters auxParams = (AuxPoWNetworkParameters)this.params;
if (auxParams.isAuxPoWBlockVersion(getRawVersion()) && null != auxpow) {
return auxpow.checkProofOfWork(this.getHash(), target, throwException);
}
}
final AltcoinNetworkParameters altParams = (AltcoinNetworkParameters)this.params;
BigInteger h = altParams.getBlockDifficultyHash(this).toBigInteger();
if (h.compareTo(target) > 0) {
// Proof of work check failed!
if (throwException)
throw new VerificationException("Hash is higher than target: " + getHashAsString() + " vs "
+ target.toString(16));
else
return false;
}
return true;
} else {
return super.checkProofOfWork(throwException);
}
}
/**
* Checks the block data to ensure it follows the rules laid out in the network parameters. Specifically,
* throws an exception if the proof of work is invalid, or if the timestamp is too far from what it should be.
* This is <b>not</b> everything that is required for a block to be valid, only what is checkable independent
* of the chain and without a transaction index.
*
* @throws VerificationException
*/
@Override
public void verifyHeader() throws VerificationException {
super.verifyHeader();
}
}

View File

@@ -0,0 +1,469 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
* Copyright 2015 J. Ross Nicoll
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.libdohj.core.AuxPoWNetworkParameters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.*;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.util.*;
/**
* <p>An AuxPoW header wraps a block header from another coin, enabling the foreign
* chain's proof of work to be used for this chain as well. <b>Note: </b>
* NetworkParameters for AuxPoW networks <b>must</b> implement AltcoinNetworkParameters
* in order for AuxPoW to work.</p>
*/
public class AuxPoW extends ChildMessage {
public static final byte[] MERGED_MINING_HEADER = new byte[] {
(byte) 0xfa, (byte) 0xbe, "m".getBytes()[0], "m".getBytes()[0]
};
/**
* Maximum index of the merkle root hash in the coinbase transaction script,
* where no merged mining header is present.
*/
protected static final int MAX_INDEX_PC_BACKWARDS_COMPATIBILITY = 20;
private static final Logger log = LoggerFactory.getLogger(AuxPoW.class);
private static final long serialVersionUID = -8567546957352643140L;
private Transaction transaction;
private Sha256Hash hashBlock;
private MerkleBranch coinbaseBranch;
private MerkleBranch chainMerkleBranch;
private AltcoinBlock parentBlockHeader;
// Transactions can be encoded in a way that will use more bytes than is optimal
// (due to VarInts having multiple encodings)
// MAX_BLOCK_SIZE must be compared to the optimal encoding, not the actual encoding, so when parsing, we keep track
// of the size of the ideal encoding in addition to the actual message size (which Message needs) so that Blocks
// can properly keep track of optimal encoded size
private transient int optimalEncodingMessageSize;
public AuxPoW(NetworkParameters params, @Nullable Message parent) {
super(params);
transaction = new Transaction(params);
hashBlock = Sha256Hash.ZERO_HASH;
coinbaseBranch = new MerkleBranch(params, this);
chainMerkleBranch = new MerkleBranch(params, this);
parentBlockHeader = null;
}
/**
* Creates an AuxPoW header by reading payload starting from offset bytes in. Length of header is fixed.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param parent The message element which contains this header.
* @param serializer the serializer to use for this message.
* @throws ProtocolException
*/
public AuxPoW(NetworkParameters params, byte[] payload, int offset, Message parent, MessageSerializer serializer)
throws ProtocolException {
super(params, payload, offset, parent, serializer, Message.UNKNOWN_LENGTH);
}
/**
* Creates an AuxPoW header by reading payload starting from offset bytes in. Length of header is fixed.
*
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param parent The message element which contains this header.
* @param serializer the serializer to use for this message.
*/
public AuxPoW(NetworkParameters params, byte[] payload, @Nullable Message parent, MessageSerializer serializer)
throws ProtocolException {
super(params, payload, 0, parent, serializer, Message.UNKNOWN_LENGTH);
}
protected static int calcLength(byte[] buf, int offset) {
VarInt varint;
// jump past transaction
int cursor = offset + Transaction.calcLength(buf, offset);
// jump past header hash
cursor += 4;
// Coin base branch
cursor += MerkleBranch.calcLength(buf, offset);
// Block chain branch
cursor += MerkleBranch.calcLength(buf, offset);
// Block header
cursor += Block.HEADER_SIZE;
return cursor - offset + 4;
}
@Override
protected void parse() throws ProtocolException {
cursor = offset;
transaction = new Transaction(params, payload, cursor, this, serializer, Message.UNKNOWN_LENGTH, null);
cursor += transaction.getOptimalEncodingMessageSize();
optimalEncodingMessageSize = transaction.getOptimalEncodingMessageSize();
hashBlock = readHash();
optimalEncodingMessageSize += 32; // Add the hash size to the optimal encoding
coinbaseBranch = new MerkleBranch(params, this, payload, cursor, serializer);
cursor += coinbaseBranch.getOptimalEncodingMessageSize();
optimalEncodingMessageSize += coinbaseBranch.getOptimalEncodingMessageSize();
chainMerkleBranch = new MerkleBranch(params, this, payload, cursor, serializer);
cursor += chainMerkleBranch.getOptimalEncodingMessageSize();
optimalEncodingMessageSize += chainMerkleBranch.getOptimalEncodingMessageSize();
// Make a copy of JUST the contained block header, so the block parser doesn't try reading
// transactions past the end
byte[] blockBytes = Arrays.copyOfRange(payload, cursor, cursor + Block.HEADER_SIZE);
cursor += Block.HEADER_SIZE;
parentBlockHeader = new AltcoinBlock(params, blockBytes, 0, this, serializer, Block.HEADER_SIZE);
length = cursor - offset;
}
public int getOptimalEncodingMessageSize() {
if (optimalEncodingMessageSize != 0)
return optimalEncodingMessageSize;
optimalEncodingMessageSize = getMessageSize();
return optimalEncodingMessageSize;
}
@Override
public String toString() {
return toString(null);
}
/**
* A human readable version of the transaction useful for debugging. The format is not guaranteed to be stable.
* @param chain If provided, will be used to estimate lock times (if set). Can be null.
*/
public String toString(@Nullable AbstractBlockChain chain) {
return transaction.toString(chain, null);
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
transaction.bitcoinSerialize(stream);
stream.write(Utils.reverseBytes(hashBlock.getBytes()));
coinbaseBranch.bitcoinSerialize(stream);
chainMerkleBranch.bitcoinSerialize(stream);
parentBlockHeader.bitcoinSerializeToStream(stream);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AuxPoW input = (AuxPoW) o;
if (!transaction.equals(input.transaction)) return false;
if (!hashBlock.equals(input.hashBlock)) return false;
if (!coinbaseBranch.equals(input.coinbaseBranch)) return false;
if (!chainMerkleBranch.equals(input.chainMerkleBranch)) return false;
if (!parentBlockHeader.equals(input.parentBlockHeader)) return false;
return getHash().equals(input.getHash());
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + transaction.hashCode();
result = 31 * result + hashBlock.hashCode();
result = 31 * result + coinbaseBranch.hashCode();
result = 31 * result + chainMerkleBranch.hashCode();
result = 31 * result + parentBlockHeader.hashCode();
return result;
}
/**
* Get the block header from the parent blockchain. The hash of the header
* is the value which should match the difficulty target. Note that blocks are
* not necessarily part of the parent blockchain, they simply must be valid
* blocks at the difficulty of the child blockchain.
*/
public AltcoinBlock getParentBlockHeader() {
return parentBlockHeader;
}
/**
* Get the coinbase transaction from the AuxPoW header. This should contain a
* reference back to the block hash in its input scripts, to prove that the
* transaction was created after the block.
*/
public Transaction getCoinbase() {
return transaction;
}
/**
* Get the Merkle branch used to connect the AuXPow header with this blockchain.
*/
public MerkleBranch getChainMerkleBranch() {
return chainMerkleBranch;
}
/**
* Get the Merkle branch used to connect the coinbase transaction with this blockchain.
*/
public MerkleBranch getCoinbaseBranch() {
return coinbaseBranch;
}
/**
* Check the proof of work for this AuxPoW header meets the target
* difficulty.
*
* @param hashAuxBlock hash of the block the AuxPoW header is attached to.
* @param target the difficulty target after decoding from compact bits.
*/
protected boolean checkProofOfWork(Sha256Hash hashAuxBlock,
BigInteger target, boolean throwException) throws VerificationException {
if (!(params instanceof AuxPoWNetworkParameters)) {
if (throwException) {
// Should be impossible
throw new VerificationException("Network parameters are not an instance of AuxPoWNetworkParameters, AuxPoW support is not available.");
}
return false;
}
final AuxPoWNetworkParameters altcoinParams = (AuxPoWNetworkParameters) params;
if (0 != this.getCoinbaseBranch().getIndex()) {
if (throwException) {
// I don't like the message, but it correlates with what's in the reference client.
throw new VerificationException("AuxPow is not a generate");
}
return false;
}
if (!altcoinParams.isTestNet()
&& parentBlockHeader.getChainID() == altcoinParams.getChainID()) {
if (throwException) {
throw new VerificationException("Aux POW parent has our chain ID");
}
return false;
}
if (this.getChainMerkleBranch().size() > 30) {
if (throwException) {
throw new VerificationException("Aux POW chain merkle branch too long");
}
return false;
}
Sha256Hash nRootHash = getChainMerkleBranch().calculateMerkleRoot(hashAuxBlock);
final byte[] vchRootHash = nRootHash.getBytes();
// Check that the coinbase transaction is in the merkle tree of the
// parent block header
if (!getCoinbaseBranch().calculateMerkleRoot(getCoinbase().getHash()).equals(parentBlockHeader.getMerkleRoot())) {
if (throwException) {
throw new VerificationException("Aux POW merkle root incorrect");
}
return false;
}
if (this.getCoinbase().getInputs().isEmpty()) {
throw new VerificationException("Coinbase transaction has no inputs");
}
// Check that the chain merkle root is in the coinbase
final byte[] script = this.getCoinbase().getInput(0).getScriptBytes();
// Check that the same work is not submitted twice to our chain, by
// confirming that the child block hash is in the coinbase merkle tree
int pcHead = -1;
int pc = -1;
for (int scriptIdx = 0; scriptIdx < script.length; scriptIdx++) {
if (arrayMatch(script, scriptIdx, MERGED_MINING_HEADER)) {
// Enforce only one chain merkle root by checking that a single instance of the merged
// mining header exists just before.
if (pcHead >= 0) {
if (throwException) {
throw new VerificationException("Multiple merged mining headers in coinbase");
}
return false;
}
pcHead = scriptIdx;
} else if (arrayMatch(script, scriptIdx, vchRootHash)) {
pc = scriptIdx;
}
}
if (pc == -1) {
if (throwException) {
throw new VerificationException("Aux POW missing chain merkle root in parent coinbase");
}
return false;
}
if (pcHead != -1) {
if (pcHead + MERGED_MINING_HEADER.length != pc) {
if (throwException) {
throw new VerificationException("Merged mining header is not just before chain merkle root");
}
return false;
}
} else {
// For backward compatibility.
// Enforce only one chain merkle root by checking that it starts early in the coinbase.
// 8-12 bytes are enough to encode extraNonce and nBits.
if (pc > MAX_INDEX_PC_BACKWARDS_COMPATIBILITY) {
if (throwException) {
throw new VerificationException("Aux POW chain merkle root must start in the first 20 bytes of the parent coinbase");
}
return false;
}
}
// Ensure we are at a deterministic point in the merkle leaves by hashing
// a nonce and our chain ID and comparing to the index.
pc += vchRootHash.length;
if ((script.length - pc) < 8) {
if (throwException) {
throw new VerificationException("Aux POW missing chain merkle tree size and nonce in parent coinbase");
}
return false;
}
byte[] sizeBytes = Utils.reverseBytes(Arrays.copyOfRange(script, pc, pc + 4));
int branchSize = ByteBuffer.wrap(sizeBytes).getInt();
if (branchSize != (1 << getChainMerkleBranch().size())) {
if (throwException) {
throw new VerificationException("Aux POW merkle branch size does not match parent coinbase");
}
return false;
}
long nonce = getNonceFromScript(script, pc);
if (getChainMerkleBranch().getIndex() != getExpectedIndex(nonce, ((AuxPoWNetworkParameters) params).getChainID(), getChainMerkleBranch().size())) {
if (throwException) {
throw new VerificationException("Aux POW wrong index in chain merkle branch for chain ID "
+ ((AuxPoWNetworkParameters) params).getChainID() + ". Was "
+ getChainMerkleBranch().getIndex() + ", expected "
+ getExpectedIndex(nonce, ((AuxPoWNetworkParameters) params).getChainID(), getChainMerkleBranch().size()));
}
return false;
}
Sha256Hash hash = altcoinParams.getBlockDifficultyHash(getParentBlockHeader());
BigInteger hashVal = hash.toBigInteger();
if (hashVal.compareTo(target) > 0) {
// Proof of work check failed!
if (throwException) {
throw new VerificationException("Hash is higher than target: " + hash.toString() + " vs "
+ target.toString(16));
}
return false;
}
return true;
}
/**
* Get the nonce value from the coinbase transaction script.
*
* @param script the transaction script to extract the nonce from.
* @param pc offset of the merkle branch size within the script (this is 4
* bytes before the start of the nonce value). Range checks should be
* performed before calling this method.
* @return the nonce value.
*/
protected static long getNonceFromScript(final byte[] script, int pc) {
// Note that the nonce value is packed as platform order (typically
// little-endian) so we have to convert to big-endian for Java
final byte[] nonceBytes = Utils.reverseBytes(Arrays.copyOfRange(script, pc + 4, pc + 8));
return ByteBuffer.wrap(nonceBytes).getInt() & 0xffffffffl;
}
/**
* Get the expected index of the slot within the chain merkle tree.
*
* This prevents the same work from being used twice for the
* same chain while reducing the chance that two chains clash
* for the same slot.
*/
protected static int getExpectedIndex(final long nonce, final int chainId, final int merkleHeight) {
// Choose a pseudo-random slot in the chain merkle tree
// but have it be fixed for a size/nonce/chain combination.
// We do most of the maths with a signed 32 bit integer, as the operation is
// the same as the 32 unsigned integer that the reference version uses
int rand = (int) nonce;
rand = rand * 1103515245 + 12345;
rand += chainId;
rand = rand * 1103515245 + 12345;
// At this point, we need to flip the value to its positive version,
// so we switch to a 64 bit signed integer for the last calculations
long longRand = rand & 0xffffffffl;
longRand %= (1 << merkleHeight);
return (int) longRand;
}
public Transaction getTransaction() {
return transaction;
}
/**
* Test whether one array is at a specific offset within the other.
*
* @param script the longer array to test for containing another array.
* @param offset the offset to start at within the larger array.
* @param subArray the shorter array to test for presence in the longer array.
* @return true if the shorter array is present at the offset, false otherwise.
*/
static boolean arrayMatch(byte[] script, int offset, byte[] subArray) {
int matchIdx;
for (matchIdx = 0; matchIdx + offset < script.length && matchIdx < subArray.length; matchIdx++) {
if (script[offset + matchIdx] != subArray[matchIdx]) {
return false;
}
}
return matchIdx == subArray.length;
}
/**
* Set the merkle branch used to connect the coinbase transaction to the
* parent block header.
*/
public void setCoinbaseBranch(final MerkleBranch merkleBranch) {
this.coinbaseBranch = merkleBranch;
}
/**
* Set the parent chain block header.
*/
public void setParentBlockHeader(final AltcoinBlock header) {
this.parentBlockHeader = header;
}
}

View File

@@ -1,204 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.Arrays;
/**
* <p>Base58 is a way to encode Bitcoin addresses as numbers and letters. Note that this is not the same base58 as used by
* Flickr, which you may see reference to around the internet.</p>
*
* <p>You may instead wish to work with {@link VersionedChecksummedBytes}, which adds support for testing the prefix
* and suffix bytes commonly found in addresses.</p>
*
* <p>Satoshi says: why base-58 instead of standard base-64 encoding?<p>
*
* <ul>
* <li>Don't want 0OIl characters that look the same in some fonts and
* could be used to create visually identical looking account numbers.</li>
* <li>A string with non-alphanumeric characters is not as easily accepted as an account number.</li>
* <li>E-mail usually won't line-break if there's no punctuation to break at.</li>
* <li>Doubleclicking selects the whole number as one word if it's all alphanumeric.</li>
* </ul>
*/
public class Base58 {
public static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
private static final int[] INDEXES = new int[128];
static {
for (int i = 0; i < INDEXES.length; i++) {
INDEXES[i] = -1;
}
for (int i = 0; i < ALPHABET.length; i++) {
INDEXES[ALPHABET[i]] = i;
}
}
/** Encodes the given bytes in base58. No checksum is appended. */
public static String encode(byte[] input) {
if (input.length == 0) {
return "";
}
input = copyOfRange(input, 0, input.length);
// Count leading zeroes.
int zeroCount = 0;
while (zeroCount < input.length && input[zeroCount] == 0) {
++zeroCount;
}
// The actual encoding.
byte[] temp = new byte[input.length * 2];
int j = temp.length;
int startAt = zeroCount;
while (startAt < input.length) {
byte mod = divmod58(input, startAt);
if (input[startAt] == 0) {
++startAt;
}
temp[--j] = (byte) ALPHABET[mod];
}
// Strip extra '1' if there are some after decoding.
while (j < temp.length && temp[j] == ALPHABET[0]) {
++j;
}
// Add as many leading '1' as there were leading zeros.
while (--zeroCount >= 0) {
temp[--j] = (byte) ALPHABET[0];
}
byte[] output = copyOfRange(temp, j, temp.length);
try {
return new String(output, "US-ASCII");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
public static byte[] decode(String input) throws AddressFormatException {
if (input.length() == 0) {
return new byte[0];
}
byte[] input58 = new byte[input.length()];
// Transform the String to a base58 byte sequence
for (int i = 0; i < input.length(); ++i) {
char c = input.charAt(i);
int digit58 = -1;
if (c >= 0 && c < 128) {
digit58 = INDEXES[c];
}
if (digit58 < 0) {
throw new AddressFormatException("Illegal character " + c + " at " + i);
}
input58[i] = (byte) digit58;
}
// Count leading zeroes
int zeroCount = 0;
while (zeroCount < input58.length && input58[zeroCount] == 0) {
++zeroCount;
}
// The encoding
byte[] temp = new byte[input.length()];
int j = temp.length;
int startAt = zeroCount;
while (startAt < input58.length) {
byte mod = divmod256(input58, startAt);
if (input58[startAt] == 0) {
++startAt;
}
temp[--j] = mod;
}
// Do no add extra leading zeroes, move j to first non null byte.
while (j < temp.length && temp[j] == 0) {
++j;
}
return copyOfRange(temp, j - zeroCount, temp.length);
}
public static BigInteger decodeToBigInteger(String input) throws AddressFormatException {
return new BigInteger(1, decode(input));
}
/**
* Uses the checksum in the last 4 bytes of the decoded data to verify the rest are correct. The checksum is
* removed from the returned data.
*
* @throws AddressFormatException if the input is not base 58 or the checksum does not validate.
*/
public static byte[] decodeChecked(String input) throws AddressFormatException {
byte tmp [] = decode(input);
if (tmp.length < 4)
throw new AddressFormatException("Input too short");
byte[] bytes = copyOfRange(tmp, 0, tmp.length - 4);
byte[] checksum = copyOfRange(tmp, tmp.length - 4, tmp.length);
tmp = Utils.doubleDigest(bytes);
byte[] hash = copyOfRange(tmp, 0, 4);
if (!Arrays.equals(checksum, hash))
throw new AddressFormatException("Checksum does not validate");
return bytes;
}
//
// number -> number / 58, returns number % 58
//
private static byte divmod58(byte[] number, int startAt) {
int remainder = 0;
for (int i = startAt; i < number.length; i++) {
int digit256 = (int) number[i] & 0xFF;
int temp = remainder * 256 + digit256;
number[i] = (byte) (temp / 58);
remainder = temp % 58;
}
return (byte) remainder;
}
//
// number -> number / 256, returns number % 256
//
private static byte divmod256(byte[] number58, int startAt) {
int remainder = 0;
for (int i = startAt; i < number58.length; i++) {
int digit58 = (int) number58[i] & 0xFF;
int temp = remainder * 58 + digit58;
number58[i] = (byte) (temp / 256);
remainder = temp % 256;
}
return (byte) remainder;
}
private static byte[] copyOfRange(byte[] source, int from, int to) {
byte[] range = new byte[to - from];
System.arraycopy(source, from, range, 0, range.length);
return range;
}
}

View File

@@ -1,328 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import static org.bitcoinj.core.Utils.*;
/**
* <p>Methods to serialize and de-serialize messages to the Bitcoin network format as defined in
* <a href="https://en.bitcoin.it/wiki/Protocol_specification">the protocol specification</a>.</p>
*
* <p>To be able to serialize and deserialize new Message subclasses the following criteria needs to be met.</p>
*
* <ul>
* <li>The proper Class instance needs to be mapped to its message name in the names variable below</li>
* <li>There needs to be a constructor matching: NetworkParameters params, byte[] payload</li>
* <li>Message.bitcoinSerializeToStream() needs to be properly subclassed</li>
* </ul>
*/
public class BitcoinSerializer {
private static final Logger log = LoggerFactory.getLogger(BitcoinSerializer.class);
private static final int COMMAND_LEN = 12;
private NetworkParameters params;
private boolean parseLazy = false;
private boolean parseRetain = false;
private static Map<Class<? extends Message>, String> names = new HashMap<Class<? extends Message>, String>();
static {
names.put(VersionMessage.class, "version");
names.put(InventoryMessage.class, "inv");
names.put(Block.class, "block");
names.put(GetDataMessage.class, "getdata");
names.put(Transaction.class, "tx");
names.put(AddressMessage.class, "addr");
names.put(Ping.class, "ping");
names.put(Pong.class, "pong");
names.put(VersionAck.class, "verack");
names.put(GetBlocksMessage.class, "getblocks");
names.put(GetHeadersMessage.class, "getheaders");
names.put(GetAddrMessage.class, "getaddr");
names.put(HeadersMessage.class, "headers");
names.put(BloomFilter.class, "filterload");
names.put(FilteredBlock.class, "merkleblock");
names.put(NotFoundMessage.class, "notfound");
names.put(MemoryPoolMessage.class, "mempool");
names.put(RejectMessage.class, "reject");
names.put(GetUTXOsMessage.class, "getutxos");
names.put(UTXOsMessage.class, "utxos");
}
/**
* Constructs a BitcoinSerializer with the given behavior.
*
* @param params networkParams used to create Messages instances and termining packetMagic
*/
public BitcoinSerializer(NetworkParameters params) {
this(params, false, false);
}
/**
* Constructs a BitcoinSerializer with the given behavior.
*
* @param params networkParams used to create Messages instances and termining packetMagic
* @param parseLazy deserialize messages in lazy mode.
* @param parseRetain retain the backing byte array of a message for fast reserialization.
*/
public BitcoinSerializer(NetworkParameters params, boolean parseLazy, boolean parseRetain) {
this.params = params;
this.parseLazy = parseLazy;
this.parseRetain = parseRetain;
}
/**
* Writes message to to the output stream.
*/
public void serialize(String name, byte[] message, OutputStream out) throws IOException {
byte[] header = new byte[4 + COMMAND_LEN + 4 + 4 /* checksum */];
uint32ToByteArrayBE(params.getPacketMagic(), header, 0);
// The header array is initialized to zero by Java so we don't have to worry about
// NULL terminating the string here.
for (int i = 0; i < name.length() && i < COMMAND_LEN; i++) {
header[4 + i] = (byte) (name.codePointAt(i) & 0xFF);
}
Utils.uint32ToByteArrayLE(message.length, header, 4 + COMMAND_LEN);
byte[] hash = doubleDigest(message);
System.arraycopy(hash, 0, header, 4 + COMMAND_LEN + 4, 4);
out.write(header);
out.write(message);
if (log.isDebugEnabled())
log.debug("Sending {} message: {}", name, HEX.encode(header) + HEX.encode(message));
}
/**
* Writes message to to the output stream.
*/
public void serialize(Message message, OutputStream out) throws IOException {
String name = names.get(message.getClass());
if (name == null) {
throw new Error("BitcoinSerializer doesn't currently know how to serialize " + message.getClass());
}
serialize(name, message.bitcoinSerialize(), out);
}
/**
* Reads a message from the given ByteBuffer and returns it.
*/
public Message deserialize(ByteBuffer in) throws ProtocolException, IOException {
// A Bitcoin protocol message has the following format.
//
// - 4 byte magic number: 0xfabfb5da for the testnet or
// 0xf9beb4d9 for production
// - 12 byte command in ASCII
// - 4 byte payload size
// - 4 byte checksum
// - Payload data
//
// The checksum is the first 4 bytes of a SHA256 hash of the message payload. It isn't
// present for all messages, notably, the first one on a connection.
//
// Satoshi's implementation ignores garbage before the magic header bytes. We have to do the same because
// sometimes it sends us stuff that isn't part of any message.
seekPastMagicBytes(in);
BitcoinPacketHeader header = new BitcoinPacketHeader(in);
// Now try to read the whole message.
return deserializePayload(header, in);
}
/**
* Deserializes only the header in case packet meta data is needed before decoding
* the payload. This method assumes you have already called seekPastMagicBytes()
*/
public BitcoinPacketHeader deserializeHeader(ByteBuffer in) throws ProtocolException, IOException {
return new BitcoinPacketHeader(in);
}
/**
* Deserialize payload only. You must provide a header, typically obtained by calling
* {@link BitcoinSerializer#deserializeHeader}.
*/
public Message deserializePayload(BitcoinPacketHeader header, ByteBuffer in) throws ProtocolException, BufferUnderflowException {
byte[] payloadBytes = new byte[header.size];
in.get(payloadBytes, 0, header.size);
// Verify the checksum.
byte[] hash;
hash = doubleDigest(payloadBytes);
if (header.checksum[0] != hash[0] || header.checksum[1] != hash[1] ||
header.checksum[2] != hash[2] || header.checksum[3] != hash[3]) {
throw new ProtocolException("Checksum failed to verify, actual " +
HEX.encode(hash) +
" vs " + HEX.encode(header.checksum));
}
if (log.isDebugEnabled()) {
log.debug("Received {} byte '{}' message: {}", header.size, header.command,
HEX.encode(payloadBytes));
}
try {
return makeMessage(header.command, header.size, payloadBytes, hash, header.checksum);
} catch (Exception e) {
throw new ProtocolException("Error deserializing message " + HEX.encode(payloadBytes) + "\n", e);
}
}
private Message makeMessage(String command, int length, byte[] payloadBytes, byte[] hash, byte[] checksum) throws ProtocolException {
// We use an if ladder rather than reflection because reflection is very slow on Android.
Message message;
if (command.equals("version")) {
return new VersionMessage(params, payloadBytes);
} else if (command.equals("inv")) {
message = new InventoryMessage(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("block")) {
message = new Block(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("merkleblock")) {
message = new FilteredBlock(params, payloadBytes);
} else if (command.equals("getdata")) {
message = new GetDataMessage(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("getblocks")) {
message = new GetBlocksMessage(params, payloadBytes);
} else if (command.equals("getheaders")) {
message = new GetHeadersMessage(params, payloadBytes);
} else if (command.equals("tx")) {
Transaction tx = new Transaction(params, payloadBytes, null, parseLazy, parseRetain, length);
if (hash != null)
tx.setHash(new Sha256Hash(Utils.reverseBytes(hash)));
message = tx;
} else if (command.equals("addr")) {
message = new AddressMessage(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("ping")) {
message = new Ping(params, payloadBytes);
} else if (command.equals("pong")) {
message = new Pong(params, payloadBytes);
} else if (command.equals("verack")) {
return new VersionAck(params, payloadBytes);
} else if (command.equals("headers")) {
return new HeadersMessage(params, payloadBytes);
} else if (command.equals("alert")) {
return new AlertMessage(params, payloadBytes);
} else if (command.equals("filterload")) {
return new BloomFilter(params, payloadBytes);
} else if (command.equals("notfound")) {
return new NotFoundMessage(params, payloadBytes);
} else if (command.equals("mempool")) {
return new MemoryPoolMessage();
} else if (command.equals("reject")) {
return new RejectMessage(params, payloadBytes);
} else if (command.equals("utxos")) {
return new UTXOsMessage(params, payloadBytes);
} else if (command.equals("getutxos")) {
return new GetUTXOsMessage(params, payloadBytes);
} else {
log.warn("No support for deserializing message with name {}", command);
return new UnknownMessage(params, command, payloadBytes);
}
if (checksum != null)
message.setChecksum(checksum);
return message;
}
public void seekPastMagicBytes(ByteBuffer in) throws BufferUnderflowException {
int magicCursor = 3; // Which byte of the magic we're looking for currently.
while (true) {
byte b = in.get();
// We're looking for a run of bytes that is the same as the packet magic but we want to ignore partial
// magics that aren't complete. So we keep track of where we're up to with magicCursor.
byte expectedByte = (byte)(0xFF & params.getPacketMagic() >>> (magicCursor * 8));
if (b == expectedByte) {
magicCursor--;
if (magicCursor < 0) {
// We found the magic sequence.
return;
} else {
// We still have further to go to find the next message.
}
} else {
magicCursor = 3;
}
}
}
/**
* Whether the serializer will produce lazy parse mode Messages
*/
public boolean isParseLazyMode() {
return parseLazy;
}
/**
* Whether the serializer will produce cached mode Messages
*/
public boolean isParseRetainMode() {
return parseRetain;
}
public static class BitcoinPacketHeader {
/** The largest number of bytes that a header can represent */
public static final int HEADER_LENGTH = COMMAND_LEN + 4 + 4;
public final byte[] header;
public final String command;
public final int size;
public final byte[] checksum;
public BitcoinPacketHeader(ByteBuffer in) throws ProtocolException, BufferUnderflowException {
header = new byte[HEADER_LENGTH];
in.get(header, 0, header.length);
int cursor = 0;
// The command is a NULL terminated string, unless the command fills all twelve bytes
// in which case the termination is implicit.
for (; header[cursor] != 0 && cursor < COMMAND_LEN; cursor++) ;
byte[] commandBytes = new byte[cursor];
System.arraycopy(header, 0, commandBytes, 0, cursor);
try {
command = new String(commandBytes, "US-ASCII");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); // Cannot happen.
}
cursor = COMMAND_LEN;
size = (int) readUint32(header, cursor);
cursor += 4;
if (size > Message.MAX_SIZE)
throw new ProtocolException("Message size too large: " + size);
// Old clients don't send the checksum.
checksum = new byte[4];
// Note that the size read above includes the checksum bytes.
System.arraycopy(header, cursor, checksum, 0, 4);
cursor += 4;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,157 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import static com.google.common.base.Preconditions.checkArgument;
import org.bitcoinj.store.BlockStore;
import org.bitcoinj.store.BlockStoreException;
import java.util.ArrayList;
import java.util.List;
/**
* <p>A BlockChain implements the <i>simplified payment verification</i> mode of the Bitcoin protocol. It is the right
* choice to use for programs that have limited resources as it won't verify transactions signatures or attempt to store
* all of the block chain. Really, this class should be called SPVBlockChain but for backwards compatibility it is not.
* </p>
*/
public class BlockChain extends AbstractBlockChain {
/** Keeps a map of block hashes to StoredBlocks. */
protected final BlockStore blockStore;
/**
* <p>Constructs a BlockChain connected to the given wallet and store. To obtain a {@link Wallet} you can construct
* one from scratch, or you can deserialize a saved wallet from disk using {@link Wallet#loadFromFile(java.io.File)}
* </p>
*
* <p>For the store, you should use {@link org.bitcoinj.store.SPVBlockStore} or you could also try a
* {@link org.bitcoinj.store.MemoryBlockStore} if you want to hold all headers in RAM and don't care about
* disk serialization (this is rare).</p>
*/
public BlockChain(NetworkParameters params, Wallet wallet, BlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<BlockChainListener>(), blockStore);
if (wallet != null)
addWallet(wallet);
}
/**
* Constructs a BlockChain that has no wallet at all. This is helpful when you don't actually care about sending
* and receiving coins but rather, just want to explore the network data structures.
*/
public BlockChain(NetworkParameters params, BlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<BlockChainListener>(), blockStore);
}
/**
* Constructs a BlockChain connected to the given list of listeners and a store.
*/
public BlockChain(NetworkParameters params, List<BlockChainListener> wallets,
BlockStore blockStore) throws BlockStoreException {
super(params, wallets, blockStore);
this.blockStore = blockStore;
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block blockHeader, TransactionOutputChanges txOutChanges)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(blockHeader);
blockStore.put(newBlock);
return newBlock;
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block blockHeader)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(blockHeader);
blockStore.put(newBlock);
return newBlock;
}
@Override
protected void rollbackBlockStore(int height) throws BlockStoreException {
lock.lock();
try {
int currentHeight = getBestChainHeight();
checkArgument(height >= 0 && height <= currentHeight, "Bad height: %s", height);
if (height == currentHeight)
return; // nothing to do
// Look for the block we want to be the new chain head
StoredBlock newChainHead = blockStore.getChainHead();
while (newChainHead.getHeight() > height) {
newChainHead = newChainHead.getPrev(blockStore);
if (newChainHead == null)
throw new BlockStoreException("Unreachable height");
}
// Modify store directly
blockStore.put(newChainHead);
this.setChainHead(newChainHead);
} finally {
lock.unlock();
}
}
@Override
protected boolean shouldVerifyTransactions() {
return false;
}
@Override
protected TransactionOutputChanges connectTransactions(int height, Block block) {
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
throw new UnsupportedOperationException();
}
@Override
protected TransactionOutputChanges connectTransactions(StoredBlock newBlock) {
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
throw new UnsupportedOperationException();
}
@Override
protected void disconnectTransactions(StoredBlock block) {
// Don't have to do anything as this is only called if(shouldVerifyTransactions())
throw new UnsupportedOperationException();
}
@Override
protected void doSetChainHead(StoredBlock chainHead) throws BlockStoreException {
blockStore.setChainHead(chainHead);
}
@Override
protected void notSettingChainHead() throws BlockStoreException {
// We don't use DB transactions here, so we don't need to do anything
}
@Override
protected StoredBlock getStoredBlockInCurrentScope(Sha256Hash hash) throws BlockStoreException {
return blockStore.get(hash);
}
@Override
public boolean add(FilteredBlock block) throws VerificationException, PrunedException {
boolean success = super.add(block);
if (success) {
trackFilteredTransactions(block.getTransactionCount());
}
return success;
}
}

View File

@@ -1,95 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.util.List;
/**
* Implementors can be connected to a {@link BlockChain} and have its methods called when various things
* happen that modify the state of the chain, for example: new blocks being received, a re-org occurring, or the
* best chain head changing.
*/
public interface BlockChainListener {
/**
* Called when a new block on the best chain is seen, after relevant transactions are extracted and sent to
* us via either {@link #receiveFromBlock(Transaction, StoredBlock, org.bitcoinj.core.BlockChain.NewBlockType, int)}
* or {@link #notifyTransactionIsInBlock(Sha256Hash, StoredBlock, org.bitcoinj.core.BlockChain.NewBlockType, int)}.
* If this block is causing a re-organise to a new chain, this method is NOT called even though the block may be
* the new best block: your reorganize implementation is expected to do whatever would normally be done do for a new
* best block in this case.
*/
void notifyNewBestBlock(StoredBlock block) throws VerificationException;
/**
* Called by the {@link BlockChain} when the best chain (representing total work done) has changed. In this case,
* we need to go through our transactions and find out if any have become invalid. It's possible for our balance
* to go down in this case: money we thought we had can suddenly vanish if the rest of the network agrees it
* should be so.<p>
*
* The oldBlocks/newBlocks lists are ordered height-wise from top first to bottom last (i.e. newest blocks first).
*/
void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks,
List<StoredBlock> newBlocks) throws VerificationException;
/**
* Returns true if the given transaction is interesting to the listener. If yes, then the transaction will
* be provided via the receiveFromBlock method. This method is essentially an optimization that lets BlockChain
* bypass verification of a blocks merkle tree if no listeners are interested, which can save time when processing
* full blocks on mobile phones. It's likely the method will be removed in future and replaced with an alternative
* mechanism that involves listeners providing all keys that are interesting.
*/
boolean isTransactionRelevant(Transaction tx) throws ScriptException;
/**
* <p>Called by the {@link BlockChain} when we receive a new block that contains a relevant transaction.</p>
*
* <p>A transaction may be received multiple times if is included into blocks in parallel chains. The blockType
* parameter describes whether the containing block is on the main/best chain or whether it's on a presently
* inactive side chain.</p>
*
* <p>The relativityOffset parameter is an arbitrary number used to establish an ordering between transactions
* within the same block. In the case where full blocks are being downloaded, it is simply the index of the
* transaction within that block. When Bloom filtering is in use, we don't find out the exact offset into a block
* that a transaction occurred at, so the relativity count is not reflective of anything in an absolute sense but
* rather exists only to order the transaction relative to the others.</p>
*/
void receiveFromBlock(Transaction tx, StoredBlock block,
BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException;
/**
* <p>Called by the {@link BlockChain} when we receive a new {@link FilteredBlock} that contains the given
* transaction hash in its merkle tree.</p>
*
* <p>A transaction may be received multiple times if is included into blocks in parallel chains. The blockType
* parameter describes whether the containing block is on the main/best chain or whether it's on a presently
* inactive side chain.</p>
*
* <p>The relativityOffset parameter in this case is an arbitrary (meaningless) number, that is useful only when
* compared to the relativity count of another transaction received inside the same block. It is used to establish
* an ordering of transactions relative to one another.</p>
*
* <p>This method should return false if the given tx hash isn't known about, e.g. because the the transaction was
* a Bloom false positive. If it was known about and stored, it should return true. The caller may need to know
* this to calculate the effective FP rate.</p>
*
* @return whether the transaction is known about i.e. was considered relevant previously.
*/
boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block,
BlockChain.NewBlockType blockType,
int relativityOffset) throws VerificationException;
}

View File

@@ -1,369 +0,0 @@
/*
* Copyright 2012 Matt Corallo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptChunk;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Math.*;
/**
* <p>A Bloom filter is a probabilistic data structure which can be sent to another client so that it can avoid
* sending us transactions that aren't relevant to our set of keys. This allows for significantly more efficient
* use of available network bandwidth and CPU time.</p>
*
* <p>Because a Bloom filter is probabilistic, it has a configurable false positive rate. So the filter will sometimes
* match transactions that weren't inserted into it, but it will never fail to match transactions that were. This is
* a useful privacy feature - if you have spare bandwidth the false positive rate can be increased so the remote peer
* gets a noisy picture of what transactions are relevant to your wallet.</p>
*/
public class BloomFilter extends Message {
/** The BLOOM_UPDATE_* constants control when the bloom filter is auto-updated by the peer using
it as a filter, either never, for all outputs or only for pay-2-pubkey outputs (default) */
public enum BloomUpdate {
UPDATE_NONE, // 0
UPDATE_ALL, // 1
/** Only adds outpoints to the filter if the output is a pay-to-pubkey/pay-to-multisig script */
UPDATE_P2PUBKEY_ONLY //2
}
private byte[] data;
private long hashFuncs;
private long nTweak;
private byte nFlags;
// Same value as the reference client
// A filter of 20,000 items and a false positive rate of 0.1% or one of 10,000 items and 0.0001% is just under 36,000 bytes
private static final long MAX_FILTER_SIZE = 36000;
// There is little reason to ever have more hash functions than 50 given a limit of 36,000 bytes
private static final int MAX_HASH_FUNCS = 50;
/**
* Construct a BloomFilter by deserializing payloadBytes
*/
public BloomFilter(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
/**
* Constructs a filter with the given parameters which is updated on pay2pubkey outputs only.
*/
public BloomFilter(int elements, double falsePositiveRate, long randomNonce) {
this(elements, falsePositiveRate, randomNonce, BloomUpdate.UPDATE_P2PUBKEY_ONLY);
}
/**
* <p>Constructs a new Bloom Filter which will provide approximately the given false positive rate when the given
* number of elements have been inserted. If the filter would otherwise be larger than the maximum allowed size,
* it will be automatically downsized to the maximum size.</p>
*
* <p>To check the theoretical false positive rate of a given filter, use
* {@link BloomFilter#getFalsePositiveRate(int)}.</p>
*
* <p>The anonymity of which coins are yours to any peer which you send a BloomFilter to is controlled by the
* false positive rate. For reference, as of block 187,000, the total number of addresses used in the chain was
* roughly 4.5 million. Thus, if you use a false positive rate of 0.001 (0.1%), there will be, on average, 4,500
* distinct public keys/addresses which will be thought to be yours by nodes which have your bloom filter, but
* which are not actually yours. Keep in mind that a remote node can do a pretty good job estimating the order of
* magnitude of the false positive rate of a given filter you provide it when considering the anonymity of a given
* filter.</p>
*
* <p>In order for filtered block download to function efficiently, the number of matched transactions in any given
* block should be less than (with some headroom) the maximum size of the MemoryPool used by the Peer
* doing the downloading (default is {@link TxConfidenceTable#MAX_SIZE}). See the comment in processBlock(FilteredBlock)
* for more information on this restriction.</p>
*
* <p>randomNonce is a tweak for the hash function used to prevent some theoretical DoS attacks.
* It should be a random value, however secureness of the random value is of no great consequence.</p>
*
* <p>updateFlag is used to control filter behaviour on the server (remote node) side when it encounters a hit.
* See {@link org.bitcoinj.core.BloomFilter.BloomUpdate} for a brief description of each mode. The purpose
* of this flag is to reduce network round-tripping and avoid over-dirtying the filter for the most common
* wallet configurations.</p>
*/
public BloomFilter(int elements, double falsePositiveRate, long randomNonce, BloomUpdate updateFlag) {
// The following formulas were stolen from Wikipedia's page on Bloom Filters (with the addition of min(..., MAX_...))
// Size required for a given number of elements and false-positive rate
int size = (int)(-1 / (pow(log(2), 2)) * elements * log(falsePositiveRate));
size = max(1, min(size, (int) MAX_FILTER_SIZE * 8) / 8);
data = new byte[size];
// Optimal number of hash functions for a given filter size and element count.
hashFuncs = (int)(data.length * 8 / (double)elements * log(2));
hashFuncs = max(1, min(hashFuncs, MAX_HASH_FUNCS));
this.nTweak = randomNonce;
this.nFlags = (byte)(0xff & updateFlag.ordinal());
}
/**
* Returns the theoretical false positive rate of this filter if were to contain the given number of elements.
*/
public double getFalsePositiveRate(int elements) {
return pow(1 - pow(E, -1.0 * (hashFuncs * elements) / (data.length * 8)), hashFuncs);
}
@Override
public String toString() {
return "Bloom Filter of size " + data.length + " with " + hashFuncs + " hash functions.";
}
@Override
void parse() throws ProtocolException {
data = readByteArray();
if (data.length > MAX_FILTER_SIZE)
throw new ProtocolException ("Bloom filter out of size range.");
hashFuncs = readUint32();
if (hashFuncs > MAX_HASH_FUNCS)
throw new ProtocolException("Bloom filter hash function count out of range");
nTweak = readUint32();
nFlags = readBytes(1)[0];
length = cursor - offset;
}
/**
* Serializes this message to the provided stream. If you just want the raw bytes use bitcoinSerialize().
*/
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new VarInt(data.length).encode());
stream.write(data);
Utils.uint32ToByteStreamLE(hashFuncs, stream);
Utils.uint32ToByteStreamLE(nTweak, stream);
stream.write(nFlags);
}
@Override
protected void parseLite() throws ProtocolException {
// Do nothing, lazy parsing isn't useful for bloom filters.
}
private static int rotateLeft32(int x, int r) {
return (x << r) | (x >>> (32 - r));
}
/**
* Applies the MurmurHash3 (x86_32) algorithm to the given data.
* See this <a href="http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp">C++ code for the original.</a>
*/
public static int murmurHash3(byte[] data, long nTweak, int hashNum, byte[] object) {
int h1 = (int)(hashNum * 0xFBA4C795L + nTweak);
final int c1 = 0xcc9e2d51;
final int c2 = 0x1b873593;
int numBlocks = (object.length / 4) * 4;
// body
for(int i = 0; i < numBlocks; i += 4) {
int k1 = (object[i] & 0xFF) |
((object[i+1] & 0xFF) << 8) |
((object[i+2] & 0xFF) << 16) |
((object[i+3] & 0xFF) << 24);
k1 *= c1;
k1 = rotateLeft32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = rotateLeft32(h1, 13);
h1 = h1*5+0xe6546b64;
}
int k1 = 0;
switch(object.length & 3)
{
case 3:
k1 ^= (object[numBlocks + 2] & 0xff) << 16;
// Fall through.
case 2:
k1 ^= (object[numBlocks + 1] & 0xff) << 8;
// Fall through.
case 1:
k1 ^= (object[numBlocks] & 0xff);
k1 *= c1; k1 = rotateLeft32(k1, 15); k1 *= c2; h1 ^= k1;
// Fall through.
default:
// Do nothing.
break;
}
// finalization
h1 ^= object.length;
h1 ^= h1 >>> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >>> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >>> 16;
return (int)((h1&0xFFFFFFFFL) % (data.length * 8));
}
/**
* Returns true if the given object matches the filter either because it was inserted, or because we have a
* false-positive.
*/
public synchronized boolean contains(byte[] object) {
for (int i = 0; i < hashFuncs; i++) {
if (!Utils.checkBitLE(data, murmurHash3(data, nTweak, i, object)))
return false;
}
return true;
}
/** Insert the given arbitrary data into the filter */
public synchronized void insert(byte[] object) {
for (int i = 0; i < hashFuncs; i++)
Utils.setBitLE(data, murmurHash3(data, nTweak, i, object));
}
/** Inserts the given key and equivalent hashed form (for the address). */
public synchronized void insert(ECKey key) {
insert(key.getPubKey());
insert(key.getPubKeyHash());
}
/**
* Sets this filter to match all objects. A Bloom filter which matches everything may seem pointless, however,
* it is useful in order to reduce steady state bandwidth usage when you want full blocks. Instead of receiving
* all transaction data twice, you will receive the vast majority of all transactions just once, at broadcast time.
* Solved blocks will then be send just as Merkle trees of tx hashes, meaning a constant 32 bytes of data for each
* transaction instead of 100-300 bytes as per usual.
*/
public synchronized void setMatchAll() {
data = new byte[] {(byte) 0xff};
}
/**
* Copies filter into this. Filter must have the same size, hash function count and nTweak or an
* IllegalArgumentException will be thrown.
*/
public synchronized void merge(BloomFilter filter) {
if (!this.matchesAll() && !filter.matchesAll()) {
checkArgument(filter.data.length == this.data.length &&
filter.hashFuncs == this.hashFuncs &&
filter.nTweak == this.nTweak);
for (int i = 0; i < data.length; i++)
this.data[i] |= filter.data[i];
} else {
this.data = new byte[] {(byte) 0xff};
}
}
/**
* Returns true if this filter will match anything. See {@link org.bitcoinj.core.BloomFilter#setMatchAll()}
* for when this can be a useful thing to do.
*/
public synchronized boolean matchesAll() {
for (byte b : data)
if (b != (byte) 0xff)
return false;
return true;
}
/**
* The update flag controls how application of the filter to a block modifies the filter. See the enum javadocs
* for information on what occurs and when.
*/
public synchronized BloomUpdate getUpdateFlag() {
if (nFlags == 0)
return BloomUpdate.UPDATE_NONE;
else if (nFlags == 1)
return BloomUpdate.UPDATE_ALL;
else if (nFlags == 2)
return BloomUpdate.UPDATE_P2PUBKEY_ONLY;
else
throw new IllegalStateException("Unknown flag combination");
}
/**
* Creates a new FilteredBlock from the given Block, using this filter to select transactions. Matches can cause the
* filter to be updated with the matched element, this ensures that when a filter is applied to a block, spends of
* matched transactions are also matched. However it means this filter can be mutated by the operation. The returned
* filtered block already has the matched transactions associated with it.
*/
public synchronized FilteredBlock applyAndUpdate(Block block) {
List<Transaction> txns = block.getTransactions();
List<Sha256Hash> txHashes = new ArrayList<Sha256Hash>(txns.size());
List<Transaction> matched = Lists.newArrayList();
byte[] bits = new byte[(int) Math.ceil(txns.size() / 8.0)];
for (int i = 0; i < txns.size(); i++) {
Transaction tx = txns.get(i);
txHashes.add(tx.getHash());
if (applyAndUpdate(tx)) {
Utils.setBitLE(bits, i);
matched.add(tx);
}
}
PartialMerkleTree pmt = PartialMerkleTree.buildFromLeaves(block.getParams(), bits, txHashes);
FilteredBlock filteredBlock = new FilteredBlock(block.getParams(), block.cloneAsHeader(), pmt);
for (Transaction transaction : matched)
filteredBlock.provideTransaction(transaction);
return filteredBlock;
}
public synchronized boolean applyAndUpdate(Transaction tx) {
if (contains(tx.getHash().getBytes()))
return true;
boolean found = false;
BloomUpdate flag = getUpdateFlag();
for (TransactionOutput output : tx.getOutputs()) {
Script script = output.getScriptPubKey();
for (ScriptChunk chunk : script.getChunks()) {
if (!chunk.isPushData())
continue;
if (contains(chunk.data)) {
boolean isSendingToPubKeys = script.isSentToRawPubKey() || script.isSentToMultiSig();
if (flag == BloomUpdate.UPDATE_ALL || (flag == BloomUpdate.UPDATE_P2PUBKEY_ONLY && isSendingToPubKeys))
insert(output.getOutPointFor().bitcoinSerialize());
found = true;
}
}
}
if (found) return true;
for (TransactionInput input : tx.getInputs()) {
if (contains(input.getOutpoint().bitcoinSerialize())) {
return true;
}
for (ScriptChunk chunk : input.getScriptSig().getChunks()) {
if (chunk.isPushData() && contains(chunk.data))
return true;
}
}
return false;
}
@Override
public synchronized boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BloomFilter other = (BloomFilter) o;
return hashFuncs == other.hashFuncs &&
nTweak == other.nTweak &&
Arrays.equals(data, other.data);
}
@Override
public synchronized int hashCode() {
return Objects.hashCode(hashFuncs, nTweak, Arrays.hashCode(data));
}
}

View File

@@ -1,225 +0,0 @@
/**
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.store.BlockStore;
import org.bitcoinj.store.BlockStoreException;
import org.bitcoinj.store.FullPrunedBlockStore;
import com.google.common.base.Charsets;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.google.common.io.BaseEncoding;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Map;
import java.util.TreeMap;
import static com.google.common.base.Preconditions.*;
/**
* <p>Vends hard-coded {@link StoredBlock}s for blocks throughout the chain. Checkpoints serve two purposes:</p>
* <ol>
* <li>They act as a safety mechanism against huge re-orgs that could rewrite large chunks of history, thus
* constraining the block chain to be a consensus mechanism only for recent parts of the timeline.</li>
* <li>They allow synchronization to the head of the chain for new wallets/users much faster than syncing all
* headers from the genesis block.</li>
* </ol>
*
* <p>Checkpoints are used by the SPV {@link BlockChain} to initialize fresh
* {@link org.bitcoinj.store.SPVBlockStore}s. They are not used by fully validating mode, which instead has a
* different concept of checkpoints that are used to hard-code the validity of blocks that violate BIP30 (duplicate
* coinbase transactions). Those "checkpoints" can be found in NetworkParameters.</p>
*
* <p>The file format consists of the string "CHECKPOINTS 1", followed by a uint32 containing the number of signatures
* to read. The value may not be larger than 256 (so it could have been a byte but isn't for historical reasons).
* If the number of signatures is larger than zero, each 65 byte ECDSA secp256k1 signature then follows. The signatures
* sign the hash of all bytes that follow the last signature.</p>
*
* <p>After the signatures come an int32 containing the number of checkpoints in the file. Then each checkpoint follows
* one after the other. A checkpoint is 12 bytes for the total work done field, 4 bytes for the height, 80 bytes
* for the block header and then 1 zero byte at the end (i.e. number of transactions in the block: always zero).</p>
*/
public class CheckpointManager {
private static final Logger log = LoggerFactory.getLogger(CheckpointManager.class);
private static final String BINARY_MAGIC = "CHECKPOINTS 1";
private static final String TEXTUAL_MAGIC = "TXT CHECKPOINTS 1";
private static final int MAX_SIGNATURES = 256;
// Map of block header time to data.
protected final TreeMap<Long, StoredBlock> checkpoints = new TreeMap<Long, StoredBlock>();
protected final NetworkParameters params;
protected final Sha256Hash dataHash;
public static final BaseEncoding BASE64 = BaseEncoding.base64().omitPadding();
public CheckpointManager(NetworkParameters params, InputStream inputStream) throws IOException {
this.params = checkNotNull(params);
checkNotNull(inputStream);
inputStream = new BufferedInputStream(inputStream);
inputStream.mark(1);
int first = inputStream.read();
inputStream.reset();
if (first == BINARY_MAGIC.charAt(0))
dataHash = readBinary(inputStream);
else if (first == TEXTUAL_MAGIC.charAt(0))
dataHash = readTextual(inputStream);
else
throw new IOException("Unsupported format.");
}
private Sha256Hash readBinary(InputStream inputStream) throws IOException {
DataInputStream dis = null;
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
DigestInputStream digestInputStream = new DigestInputStream(inputStream, digest);
dis = new DataInputStream(digestInputStream);
digestInputStream.on(false);
byte[] header = new byte[BINARY_MAGIC.length()];
dis.readFully(header);
if (!Arrays.equals(header, BINARY_MAGIC.getBytes("US-ASCII")))
throw new IOException("Header bytes did not match expected version");
int numSignatures = checkPositionIndex(dis.readInt(), MAX_SIGNATURES, "Num signatures out of range");
for (int i = 0; i < numSignatures; i++) {
byte[] sig = new byte[65];
dis.readFully(sig);
// TODO: Do something with the signature here.
}
digestInputStream.on(true);
int numCheckpoints = dis.readInt();
checkState(numCheckpoints > 0);
final int size = StoredBlock.COMPACT_SERIALIZED_SIZE;
ByteBuffer buffer = ByteBuffer.allocate(size);
for (int i = 0; i < numCheckpoints; i++) {
if (dis.read(buffer.array(), 0, size) < size)
throw new IOException("Incomplete read whilst loading checkpoints.");
StoredBlock block = StoredBlock.deserializeCompact(params, buffer);
buffer.position(0);
checkpoints.put(block.getHeader().getTimeSeconds(), block);
}
Sha256Hash dataHash = new Sha256Hash(digest.digest());
log.info("Read {} checkpoints, hash is {}", checkpoints.size(), dataHash);
return dataHash;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Cannot happen.
} catch (ProtocolException e) {
throw new IOException(e);
} finally {
if (dis != null) dis.close();
inputStream.close();
}
}
private Sha256Hash readTextual(InputStream inputStream) throws IOException {
Hasher hasher = Hashing.sha256().newHasher();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(inputStream, Charsets.US_ASCII));
String magic = reader.readLine();
if (!TEXTUAL_MAGIC.equals(magic))
throw new IOException("unexpected magic: " + magic);
int numSigs = Integer.parseInt(reader.readLine());
for (int i = 0; i < numSigs; i++)
reader.readLine(); // Skip sigs for now.
int numCheckpoints = Integer.parseInt(reader.readLine());
checkState(numCheckpoints > 0);
// Hash numCheckpoints in a way compatible to the binary format.
hasher.putBytes(ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(numCheckpoints).array());
final int size = StoredBlock.COMPACT_SERIALIZED_SIZE;
ByteBuffer buffer = ByteBuffer.allocate(size);
for (int i = 0; i < numCheckpoints; i++) {
byte[] bytes = BASE64.decode(reader.readLine());
hasher.putBytes(bytes);
buffer.position(0);
buffer.put(bytes);
buffer.position(0);
StoredBlock block = StoredBlock.deserializeCompact(params, buffer);
checkpoints.put(block.getHeader().getTimeSeconds(), block);
}
HashCode hash = hasher.hash();
log.info("Read {} checkpoints, hash is {}", checkpoints.size(), hash);
return new Sha256Hash(hash.asBytes());
} finally {
if (reader != null) reader.close();
}
}
/**
* Returns a {@link StoredBlock} representing the last checkpoint before the given time, for example, normally
* you would want to know the checkpoint before the earliest wallet birthday.
*/
public StoredBlock getCheckpointBefore(long time) {
try {
checkArgument(time > params.getGenesisBlock().getTimeSeconds());
// This is thread safe because the map never changes after creation.
Map.Entry<Long, StoredBlock> entry = checkpoints.floorEntry(time);
if (entry != null) return entry.getValue();
Block genesis = params.getGenesisBlock().cloneAsHeader();
return new StoredBlock(genesis, genesis.getWork(), 0);
} catch (VerificationException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/** Returns the number of checkpoints that were loaded. */
public int numCheckpoints() {
return checkpoints.size();
}
/** Returns a hash of the concatenated checkpoint data. */
public Sha256Hash getDataHash() {
return dataHash;
}
/**
* <p>Convenience method that creates a CheckpointManager, loads the given data, gets the checkpoint for the given
* time, then inserts it into the store and sets that to be the chain head. Useful when you have just created
* a new store from scratch and want to use configure it all in one go.</p>
*
* <p>Note that time is adjusted backwards by a week to account for possible clock drift in the block headers.</p>
*/
public static void checkpoint(NetworkParameters params, InputStream checkpoints, BlockStore store, long time)
throws IOException, BlockStoreException {
checkNotNull(params);
checkNotNull(store);
checkArgument(!(store instanceof FullPrunedBlockStore), "You cannot use checkpointing with a full store.");
time -= 86400 * 7;
BufferedInputStream stream = new BufferedInputStream(checkpoints);
CheckpointManager manager = new CheckpointManager(params, stream);
StoredBlock checkpoint = manager.getCheckpointBefore(time);
store.put(checkpoint);
store.setChainHead(checkpoint);
}
}

View File

@@ -1,87 +0,0 @@
/**
* Copyright 2011 Steve Coughlan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import javax.annotation.Nullable;
/**
* Represents a Message type that can be contained within another Message. ChildMessages that have a cached
* backing byte array need to invalidate their parent's caches as well as their own if they are modified.
*/
public abstract class ChildMessage extends Message {
private static final long serialVersionUID = -7657113383624517931L;
@Nullable protected Message parent;
protected ChildMessage() {
}
public ChildMessage(NetworkParameters params) {
super(params);
}
public ChildMessage(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException {
super(params, payload, offset, protocolVersion);
}
public ChildMessage(NetworkParameters params, byte[] payload, int offset, int protocolVersion, Message parent, boolean parseLazy,
boolean parseRetain, int length) throws ProtocolException {
super(params, payload, offset, protocolVersion, parseLazy, parseRetain, length);
this.parent = parent;
}
public ChildMessage(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
}
public ChildMessage(NetworkParameters params, byte[] payload, int offset, @Nullable Message parent, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, payload, offset, parseLazy, parseRetain, length);
this.parent = parent;
}
public void setParent(@Nullable Message parent) {
if (this.parent != null && this.parent != parent && parent != null) {
// After old parent is unlinked it won't be able to receive notice if this ChildMessage
// changes internally. To be safe we invalidate the parent cache to ensure it rebuilds
// manually on serialization.
this.parent.unCache();
}
this.parent = parent;
}
/* (non-Javadoc)
* @see Message#unCache()
*/
@Override
protected void unCache() {
super.unCache();
if (parent != null)
parent.unCache();
}
protected void adjustLength(int adjustment) {
adjustLength(0, adjustment);
}
@Override
protected void adjustLength(int newArraySize, int adjustment) {
super.adjustLength(newArraySize, adjustment);
if (parent != null)
parent.adjustLength(newArraySize, adjustment);
}
}

View File

@@ -1,281 +0,0 @@
/**
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.utils.MonetaryFormat;
import com.google.common.math.LongMath;
import java.io.Serializable;
import java.math.BigDecimal;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Represents a monetary Bitcoin value. This class is immutable.
*/
public final class Coin implements Monetary, Comparable<Coin>, Serializable {
/**
* Number of decimals for one Bitcoin. This constant is useful for quick adapting to other coins because a lot of
* constants derive from it.
*/
public static final int SMALLEST_UNIT_EXPONENT = 8;
/**
* The number of satoshis equal to one bitcoin.
*/
private static final long COIN_VALUE = LongMath.pow(10, SMALLEST_UNIT_EXPONENT);
/**
* Zero Bitcoins.
*/
public static final Coin ZERO = Coin.valueOf(0);
/**
* One Bitcoin.
*/
public static final Coin COIN = Coin.valueOf(COIN_VALUE);
/**
* 0.01 Bitcoins. This unit is not really used much.
*/
public static final Coin CENT = COIN.divide(100);
/**
* 0.001 Bitcoins, also known as 1 mBTC.
*/
public static final Coin MILLICOIN = COIN.divide(1000);
/**
* 0.000001 Bitcoins, also known as 1 µBTC or 1 uBTC.
*/
public static final Coin MICROCOIN = MILLICOIN.divide(1000);
/**
* A satoshi is the smallest unit that can be transferred. 100 million of them fit into a Bitcoin.
*/
public static final Coin SATOSHI = Coin.valueOf(1);
public static final Coin FIFTY_COINS = COIN.multiply(50);
/**
* Represents a monetary value of minus one satoshi.
*/
public static final Coin NEGATIVE_SATOSHI = Coin.valueOf(-1);
/**
* The number of satoshis of this monetary value.
*/
public final long value;
private final long MAX_SATOSHIS = COIN_VALUE * NetworkParameters.MAX_COINS;
private Coin(final long satoshis) {
checkArgument(-MAX_SATOSHIS <= satoshis && satoshis <= MAX_SATOSHIS,
"%s satoshis exceeds maximum possible quantity of Bitcoin.", satoshis);
this.value = satoshis;
}
public static Coin valueOf(final long satoshis) {
return new Coin(satoshis);
}
@Override
public int smallestUnitExponent() {
return SMALLEST_UNIT_EXPONENT;
}
/**
* Returns the number of satoshis of this monetary value.
*/
@Override
public long getValue() {
return value;
}
/**
* Convert an amount expressed in the way humans are used to into satoshis.
*/
public static Coin valueOf(final int coins, final int cents) {
checkArgument(cents < 100);
checkArgument(cents >= 0);
checkArgument(coins >= 0);
final Coin coin = COIN.multiply(coins).add(CENT.multiply(cents));
checkArgument(coin.compareTo(NetworkParameters.MAX_MONEY) <= 0);
return coin;
}
/**
* Parses an amount expressed in the way humans are used to.<p>
* <p/>
* This takes string in a format understood by {@link BigDecimal#BigDecimal(String)},
* for example "0", "1", "0.10", "1.23E3", "1234.5E-5".
*
* @throws IllegalArgumentException if you try to specify fractional satoshis, or a value out of range.
*/
public static Coin parseCoin(final String str) {
try {
long satoshis = new BigDecimal(str).movePointRight(SMALLEST_UNIT_EXPONENT).toBigIntegerExact().longValue();
return Coin.valueOf(satoshis);
} catch (ArithmeticException e) {
throw new IllegalArgumentException(e); // Repackage exception to honor method contract
}
}
public Coin add(final Coin value) {
return new Coin(LongMath.checkedAdd(this.value, value.value));
}
public Coin subtract(final Coin value) {
return new Coin(LongMath.checkedSubtract(this.value, value.value));
}
public Coin multiply(final long factor) {
return new Coin(LongMath.checkedMultiply(this.value, factor));
}
public Coin divide(final long divisor) {
return new Coin(this.value / divisor);
}
public Coin[] divideAndRemainder(final long divisor) {
return new Coin[] { new Coin(this.value / divisor), new Coin(this.value % divisor) };
}
public long divide(final Coin divisor) {
return this.value / divisor.value;
}
/**
* Returns true if and only if this instance represents a monetary value greater than zero,
* otherwise false.
*/
public boolean isPositive() {
return signum() == 1;
}
/**
* Returns true if and only if this instance represents a monetary value less than zero,
* otherwise false.
*/
public boolean isNegative() {
return signum() == -1;
}
/**
* Returns true if and only if this instance represents zero monetary value,
* otherwise false.
*/
public boolean isZero() {
return signum() == 0;
}
/**
* Returns true if the monetary value represented by this instance is greater than that
* of the given other Coin, otherwise false.
*/
public boolean isGreaterThan(Coin other) {
return compareTo(other) > 0;
}
/**
* Returns true if the monetary value represented by this instance is less than that
* of the given other Coin, otherwise false.
*/
public boolean isLessThan(Coin other) {
return compareTo(other) < 0;
}
public Coin shiftLeft(final int n) {
return new Coin(this.value << n);
}
public Coin shiftRight(final int n) {
return new Coin(this.value >> n);
}
@Override
public int signum() {
if (this.value == 0)
return 0;
return this.value < 0 ? -1 : 1;
}
public Coin negate() {
return new Coin(-this.value);
}
/**
* Returns the number of satoshis of this monetary value. It's deprecated in favour of accessing {@link #value}
* directly.
*/
public long longValue() {
return this.value;
}
private static final MonetaryFormat FRIENDLY_FORMAT = MonetaryFormat.BTC.minDecimals(2).repeatOptionalDecimals(1, 6).postfixCode();
/**
* Returns the value as a 0.12 type string. More digits after the decimal place will be used
* if necessary, but two will always be present.
*/
public String toFriendlyString() {
return FRIENDLY_FORMAT.format(this).toString();
}
private static final MonetaryFormat PLAIN_FORMAT = MonetaryFormat.BTC.minDecimals(0).repeatOptionalDecimals(1, 8).noCode();
/**
* <p>
* Returns the value as a plain string denominated in BTC.
* The result is unformatted with no trailing zeroes.
* For instance, a value of 150000 satoshis gives an output string of "0.0015" BTC
* </p>
*/
public String toPlainString() {
return PLAIN_FORMAT.format(this).toString();
}
@Override
public String toString() {
return Long.toString(value);
}
@Override
public boolean equals(final Object o) {
if (o == this)
return true;
if (o == null || o.getClass() != getClass())
return false;
final Coin other = (Coin) o;
if (this.value != other.value)
return false;
return true;
}
@Override
public int hashCode() {
return (int) this.value;
}
@Override
public int compareTo(final Coin other) {
if (this.value == other.value)
return 0;
return this.value > other.value ? 1 : -1;
}
}

View File

@@ -1,25 +0,0 @@
package org.bitcoinj.core;
/**
* The Context object holds various objects that are scoped to a specific instantiation of bitcoinj for a specific
* network. You can get an instance of this class through {@link AbstractBlockChain#getContext()}. At the momemnt it
* only contains a {@link org.bitcoinj.core.TxConfidenceTable} but in future it will likely contain file paths and
* other global configuration of use.
*/
public class Context {
protected TxConfidenceTable confidenceTable;
protected Context() {
confidenceTable = new TxConfidenceTable();
}
/**
* Returns the {@link TxConfidenceTable} created by this context. The pool tracks advertised
* and downloaded transactions so their confidence can be measured as a proportion of how many peers announced it.
* With an un-tampered with internet connection, the more peers announce a transaction the more confidence you can
* have that it's really valid.
*/
public TxConfidenceTable getConfidenceTable() {
return confidenceTable;
}
}

View File

@@ -1,122 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
import java.util.concurrent.ExecutionException;
/**
* <p>An implementation of {@link AbstractPeerEventListener} that listens to chain download events and tracks progress
* as a percentage. The default implementation prints progress to stdout, but you can subclass it and override the
* progress method to update a GUI instead.</p>
*/
public class DownloadProgressTracker extends AbstractPeerEventListener {
private static final Logger log = LoggerFactory.getLogger(DownloadProgressTracker.class);
private int originalBlocksLeft = -1;
private int lastPercent = 0;
private SettableFuture<Long> future = SettableFuture.create();
private boolean caughtUp = false;
@Override
public void onChainDownloadStarted(Peer peer, int blocksLeft) {
if (blocksLeft > 0 && originalBlocksLeft == -1)
startDownload(blocksLeft);
// Only mark this the first time, because this method can be called more than once during a chain download
// if we switch peers during it.
if (originalBlocksLeft == -1)
originalBlocksLeft = blocksLeft;
else
log.info("Chain download switched to {}", peer);
if (blocksLeft == 0) {
doneDownload();
future.set(peer.getBestHeight());
}
}
@Override
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) {
if (caughtUp)
return;
if (blocksLeft == 0) {
caughtUp = true;
doneDownload();
future.set(peer.getBestHeight());
}
if (blocksLeft < 0 || originalBlocksLeft <= 0)
return;
double pct = 100.0 - (100.0 * (blocksLeft / (double) originalBlocksLeft));
if ((int) pct != lastPercent) {
progress(pct, blocksLeft, new Date(block.getTimeSeconds() * 1000));
lastPercent = (int) pct;
}
}
/**
* Called when download progress is made.
*
* @param pct the percentage of chain downloaded, estimated
* @param date the date of the last block downloaded
*/
protected void progress(double pct, int blocksSoFar, Date date) {
log.info(String.format("Chain download %d%% done with %d blocks to go, block date %s", (int) pct, blocksSoFar,
Utils.dateTimeFormat(date)));
}
/**
* Called when download is initiated.
*
* @param blocks the number of blocks to download, estimated
*/
protected void startDownload(int blocks) {
log.info("Downloading block chain of size " + blocks + ". " +
(blocks > 1000 ? "This may take a while." : ""));
}
/**
* Called when we are done downloading the block chain.
*/
protected void doneDownload() {
}
/**
* Wait for the chain to be downloaded.
*/
public void await() throws InterruptedException {
try {
future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
/**
* Returns a listenable future that completes with the height of the best chain (as reported by the peer) once chain
* download seems to be finished.
*/
public ListenableFuture<Long> getFuture() {
return future;
}
}

View File

@@ -1,95 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import java.util.Arrays;
/**
* Parses and generates private keys in the form used by the Bitcoin "dumpprivkey" command. This is the private key
* bytes with a header byte and 4 checksum bytes at the end. If there are 33 private key bytes instead of 32, then
* the last byte is a discriminator value for the compressed pubkey.
*/
public class DumpedPrivateKey extends VersionedChecksummedBytes {
private boolean compressed;
// Used by ECKey.getPrivateKeyEncoded()
DumpedPrivateKey(NetworkParameters params, byte[] keyBytes, boolean compressed) {
super(params.getDumpedPrivateKeyHeader(), encode(keyBytes, compressed));
this.compressed = compressed;
}
private static byte[] encode(byte[] keyBytes, boolean compressed) {
Preconditions.checkArgument(keyBytes.length == 32, "Private keys must be 32 bytes");
if (!compressed) {
return keyBytes;
} else {
// Keys that have compressed public components have an extra 1 byte on the end in dumped form.
byte[] bytes = new byte[33];
System.arraycopy(keyBytes, 0, bytes, 0, 32);
bytes[32] = 1;
return bytes;
}
}
/**
* Parses the given private key as created by the "dumpprivkey" Bitcoin C++ RPC.
*
* @param params The expected network parameters of the key. If you don't care, provide null.
* @param encoded The base58 encoded string.
* @throws AddressFormatException If the string is invalid or the header byte doesn't match the network params.
*/
public DumpedPrivateKey(NetworkParameters params, String encoded) throws AddressFormatException {
super(encoded);
if (params != null && version != params.getDumpedPrivateKeyHeader())
throw new AddressFormatException("Mismatched version number, trying to cross networks? " + version +
" vs " + params.getDumpedPrivateKeyHeader());
if (bytes.length == 33 && bytes[32] == 1) {
compressed = true;
bytes = Arrays.copyOf(bytes, 32); // Chop off the additional marker byte.
} else if (bytes.length == 32) {
compressed = false;
} else {
throw new AddressFormatException("Wrong number of bytes for a private key, not 32 or 33");
}
}
/**
* Returns an ECKey created from this encoded private key.
*/
public ECKey getKey() {
final ECKey key = ECKey.fromPrivate(bytes);
return compressed ? key : key.decompress();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DumpedPrivateKey other = (DumpedPrivateKey) o;
return Arrays.equals(bytes, other.bytes) &&
version == other.version &&
compressed == other.compressed;
}
@Override
public int hashCode() {
return Objects.hashCode(bytes, version, compressed);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,83 +0,0 @@
/**
* Copyright 2011 Steve Coughlan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
/**
* Parent class for header only messages that don't have a payload.
* Currently this includes getaddr, verack and special bitcoinj class UnknownMessage.
*/
public abstract class EmptyMessage extends Message {
private static final long serialVersionUID = 8240801253854151802L;
public EmptyMessage() {
length = 0;
}
public EmptyMessage(NetworkParameters params) {
super(params);
length = 0;
}
public EmptyMessage(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
length = 0;
}
@Override
final protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
}
@Override
public int getMessageSize() {
return 0;
}
/* (non-Javadoc)
* @see Message#parse()
*/
@Override
void parse() throws ProtocolException {
}
/* (non-Javadoc)
* @see Message#parseLite()
*/
@Override
protected void parseLite() throws ProtocolException {
length = 0;
}
/* (non-Javadoc)
* @see Message#ensureParsed()
*/
@Override
public void ensureParsed() throws ProtocolException {
parsed = true;
}
/* (non-Javadoc)
* @see Message#bitcoinSerialize()
*/
@Override
public byte[] bitcoinSerialize() {
return new byte[0];
}
}

View File

@@ -1,155 +0,0 @@
/**
* Copyright 2012 Matt Corallo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
/**
* <p>A FilteredBlock is used to relay a block with its transactions filtered using a {@link BloomFilter}. It consists
* of the block header and a {@link PartialMerkleTree} which contains the transactions which matched the filter.</p>
*/
public class FilteredBlock extends Message {
/** The protocol version at which Bloom filtering started to be supported. */
public static final int MIN_PROTOCOL_VERSION = 70000;
private Block header;
private PartialMerkleTree merkleTree;
private List<Sha256Hash> cachedTransactionHashes = null;
// A set of transactions whose hashes are a subset of getTransactionHashes()
// These were relayed as a part of the filteredblock getdata, ie likely weren't previously received as loose transactions
private Map<Sha256Hash, Transaction> associatedTransactions = new HashMap<Sha256Hash, Transaction>();
public FilteredBlock(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
public FilteredBlock(NetworkParameters params, Block header, PartialMerkleTree pmt) {
super(params);
this.header = header;
this.merkleTree = pmt;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (header.transactions == null)
header.bitcoinSerializeToStream(stream);
else
header.cloneAsHeader().bitcoinSerializeToStream(stream);
merkleTree.bitcoinSerializeToStream(stream);
}
@Override
void parse() throws ProtocolException {
byte[] headerBytes = new byte[Block.HEADER_SIZE];
System.arraycopy(payload, 0, headerBytes, 0, Block.HEADER_SIZE);
header = new Block(params, headerBytes);
merkleTree = new PartialMerkleTree(params, payload, Block.HEADER_SIZE);
length = Block.HEADER_SIZE + merkleTree.getMessageSize();
}
@Override
protected void parseLite() throws ProtocolException {
}
/**
* Gets a list of leaf hashes which are contained in the partial merkle tree in this filtered block
*
* @throws ProtocolException If the partial merkle block is invalid or the merkle root of the partial merkle block doesnt match the block header
*/
public List<Sha256Hash> getTransactionHashes() throws VerificationException {
if (cachedTransactionHashes != null)
return Collections.unmodifiableList(cachedTransactionHashes);
List<Sha256Hash> hashesMatched = new LinkedList<Sha256Hash>();
if (header.getMerkleRoot().equals(merkleTree.getTxnHashAndMerkleRoot(hashesMatched))) {
cachedTransactionHashes = hashesMatched;
return Collections.unmodifiableList(cachedTransactionHashes);
} else
throw new VerificationException("Merkle root of block header does not match merkle root of partial merkle tree.");
}
/**
* Gets a copy of the block header
*/
public Block getBlockHeader() {
return header.cloneAsHeader();
}
/** Gets the hash of the block represented in this Filtered Block */
@Override
public Sha256Hash getHash() {
return header.getHash();
}
/**
* Provide this FilteredBlock with a transaction which is in its merkle tree
* @returns false if the tx is not relevant to this FilteredBlock
*/
public boolean provideTransaction(Transaction tx) throws VerificationException {
Sha256Hash hash = tx.getHash();
if (getTransactionHashes().contains(hash)) {
associatedTransactions.put(hash, tx);
return true;
} else
return false;
}
/** Gets the set of transactions which were provided using provideTransaction() which match in getTransactionHashes() */
public Map<Sha256Hash, Transaction> getAssociatedTransactions() {
return Collections.unmodifiableMap(associatedTransactions);
}
/** Number of transactions in this block, before it was filtered */
public int getTransactionCount() {
return merkleTree.getTransactionCount();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FilteredBlock block = (FilteredBlock) o;
if (!associatedTransactions.equals(block.associatedTransactions)) return false;
if (!header.equals(block.header)) return false;
if (!merkleTree.equals(block.merkleTree)) return false;
return true;
}
@Override
public int hashCode() {
int result = header.hashCode();
result = 31 * result + merkleTree.hashCode();
result = 31 * result + associatedTransactions.hashCode();
return result;
}
@Override
public String toString() {
return "FilteredBlock{" +
"merkleTree=" + merkleTree +
", header=" + header +
'}';
}
}

View File

@@ -1,517 +0,0 @@
/*
* Copyright 2012 Matt Corallo.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.Script.VerifyFlag;
import org.bitcoinj.store.BlockStoreException;
import org.bitcoinj.store.FullPrunedBlockStore;
import org.bitcoinj.utils.DaemonThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.*;
import static com.google.common.base.Preconditions.checkState;
/**
* <p>A FullPrunedBlockChain works in conjunction with a {@link FullPrunedBlockStore} to verify all the rules of the
* Bitcoin system, with the downside being a larg cost in system resources. Fully verifying means all unspent transaction
* outputs are stored. Once a transaction output is spent and that spend is buried deep enough, the data related to it
* is deleted to ensure disk space usage doesn't grow forever. For this reason a pruning node cannot serve the full
* block chain to other clients, but it nevertheless provides the same security guarantees as a regular Satoshi
* client does.</p>
*/
public class FullPrunedBlockChain extends AbstractBlockChain {
private static final Logger log = LoggerFactory.getLogger(FullPrunedBlockChain.class);
/** Keeps a map of block hashes to StoredBlocks. */
protected final FullPrunedBlockStore blockStore;
// Whether or not to execute scriptPubKeys before accepting a transaction (i.e. check signatures).
private boolean runScripts = true;
/**
* Constructs a BlockChain connected to the given wallet and store. To obtain a {@link Wallet} you can construct
* one from scratch, or you can deserialize a saved wallet from disk using {@link Wallet#loadFromFile(java.io.File)}
*/
public FullPrunedBlockChain(NetworkParameters params, Wallet wallet, FullPrunedBlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<BlockChainListener>(), blockStore);
if (wallet != null)
addWallet(wallet);
}
/**
* Constructs a BlockChain that has no wallet at all. This is helpful when you don't actually care about sending
* and receiving coins but rather, just want to explore the network data structures.
*/
public FullPrunedBlockChain(NetworkParameters params, FullPrunedBlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<BlockChainListener>(), blockStore);
}
/**
* Constructs a BlockChain connected to the given list of wallets and a store.
*/
public FullPrunedBlockChain(NetworkParameters params, List<BlockChainListener> listeners,
FullPrunedBlockStore blockStore) throws BlockStoreException {
super(params, listeners, blockStore);
this.blockStore = blockStore;
// Ignore upgrading for now
this.chainHead = blockStore.getVerifiedChainHead();
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block header, TransactionOutputChanges txOutChanges)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(header);
blockStore.put(newBlock, new StoredUndoableBlock(newBlock.getHeader().getHash(), txOutChanges));
return newBlock;
}
@Override
protected StoredBlock addToBlockStore(StoredBlock storedPrev, Block block)
throws BlockStoreException, VerificationException {
StoredBlock newBlock = storedPrev.build(block);
blockStore.put(newBlock, new StoredUndoableBlock(newBlock.getHeader().getHash(), block.transactions));
return newBlock;
}
@Override
protected void rollbackBlockStore(int height) throws BlockStoreException {
throw new BlockStoreException("Unsupported");
}
@Override
protected boolean shouldVerifyTransactions() {
return true;
}
/**
* Whether or not to run scripts whilst accepting blocks (i.e. checking signatures, for most transactions).
* If you're accepting data from an untrusted node, such as one found via the P2P network, this should be set
* to true (which is the default). If you're downloading a chain from a node you control, script execution
* is redundant because you know the connected node won't relay bad data to you. In that case it's safe to set
* this to false and obtain a significant speedup.
*/
public void setRunScripts(boolean value) {
this.runScripts = value;
}
//TODO: Remove lots of duplicated code in the two connectTransactions
// TODO: execute in order of largest transaction (by input count) first
ExecutorService scriptVerificationExecutor = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors(), new DaemonThreadFactory());
/** A job submitted to the executor which verifies signatures. */
private static class Verifier implements Callable<VerificationException> {
final Transaction tx;
final List<Script> prevOutScripts;
final Set<VerifyFlag> verifyFlags;
public Verifier(final Transaction tx, final List<Script> prevOutScripts, final Set<VerifyFlag> verifyFlags) {
this.tx = tx; this.prevOutScripts = prevOutScripts; this.verifyFlags = verifyFlags;
}
@Nullable
@Override
public VerificationException call() throws Exception {
try{
ListIterator<Script> prevOutIt = prevOutScripts.listIterator();
for (int index = 0; index < tx.getInputs().size(); index++) {
tx.getInputs().get(index).getScriptSig().correctlySpends(tx, index, prevOutIt.next(), verifyFlags);
}
} catch (VerificationException e) {
return e;
}
return null;
}
}
/** Get the {@link Script} from the script bytes or null if it doesn't parse. */
@Nullable
private Script getScript(byte[] scriptBytes) {
try {
return new Script(scriptBytes);
} catch (Exception e) {
return null;
}
}
/**
* Get the address from the {@link Script} if it exists otherwise return empty string "".
* @param script The script.
* @return The address.
*/
private String getScriptAddress(@Nullable Script script) {
String address = "";
try {
if (script != null) {
address = script.getToAddress(params, true).toString();
}
} catch (Exception e) {
}
return address;
}
/**
* Get the {@link Script.ScriptType} of this script.
* @param script The script.
* @return The script type.
*/
private Script.ScriptType getScriptType(@Nullable Script script) {
if (script != null) {
return script.getScriptType();
}
return Script.ScriptType.NO_TYPE;
}
@Override
protected TransactionOutputChanges connectTransactions(int height, Block block)
throws VerificationException, BlockStoreException {
checkState(lock.isHeldByCurrentThread());
if (block.transactions == null)
throw new RuntimeException("connectTransactions called with Block that didn't have transactions!");
if (!params.passesCheckpoint(height, block.getHash()))
throw new VerificationException("Block failed checkpoint lockin at " + height);
blockStore.beginDatabaseBatchWrite();
LinkedList<UTXO> txOutsSpent = new LinkedList<UTXO>();
LinkedList<UTXO> txOutsCreated = new LinkedList<UTXO>();
long sigOps = 0;
final Set<VerifyFlag> verifyFlags = EnumSet.noneOf(VerifyFlag.class);
if (block.getTimeSeconds() >= NetworkParameters.BIP16_ENFORCE_TIME)
verifyFlags.add(VerifyFlag.P2SH);
if (scriptVerificationExecutor.isShutdown())
scriptVerificationExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<Future<VerificationException>> listScriptVerificationResults = new ArrayList<Future<VerificationException>>(block.transactions.size());
try {
if (!params.isCheckpoint(height)) {
// BIP30 violator blocks are ones that contain a duplicated transaction. They are all in the
// checkpoints list and we therefore only check non-checkpoints for duplicated transactions here. See the
// BIP30 document for more details on this: https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki
for (Transaction tx : block.transactions) {
Sha256Hash hash = tx.getHash();
// If we already have unspent outputs for this hash, we saw the tx already. Either the block is
// being added twice (bug) or the block is a BIP30 violator.
if (blockStore.hasUnspentOutputs(hash, tx.getOutputs().size()))
throw new VerificationException("Block failed BIP30 test!");
if (verifyFlags.contains(VerifyFlag.P2SH)) // We already check non-BIP16 sigops in Block.verifyTransactions(true)
sigOps += tx.getSigOpCount();
}
}
Coin totalFees = Coin.ZERO;
Coin coinbaseValue = null;
for (final Transaction tx : block.transactions) {
boolean isCoinBase = tx.isCoinBase();
Coin valueIn = Coin.ZERO;
Coin valueOut = Coin.ZERO;
final List<Script> prevOutScripts = new LinkedList<Script>();
if (!isCoinBase) {
// For each input of the transaction remove the corresponding output from the set of unspent
// outputs.
for (int index = 0; index < tx.getInputs().size(); index++) {
TransactionInput in = tx.getInputs().get(index);
UTXO prevOut = blockStore.getTransactionOutput(in.getOutpoint().getHash(),
in.getOutpoint().getIndex());
if (prevOut == null)
throw new VerificationException("Attempted to spend a non-existent or already spent output!");
// Coinbases can't be spent until they mature, to avoid re-orgs destroying entire transaction
// chains. The assumption is there will ~never be re-orgs deeper than the spendable coinbase
// chain depth.
if (prevOut.isCoinbase()) {
if (height - prevOut.getHeight() < params.getSpendableCoinbaseDepth()) {
throw new VerificationException("Tried to spend coinbase at depth " + (height - prevOut.getHeight()));
}
}
// TODO: Check we're not spending the genesis transaction here. Satoshis code won't allow it.
valueIn = valueIn.add(prevOut.getValue());
if (verifyFlags.contains(VerifyFlag.P2SH)) {
if (new Script(prevOut.getScriptBytes()).isPayToScriptHash())
sigOps += Script.getP2SHSigOpCount(in.getScriptBytes());
if (sigOps > Block.MAX_BLOCK_SIGOPS)
throw new VerificationException("Too many P2SH SigOps in block");
}
prevOutScripts.add(new Script(prevOut.getScriptBytes()));
//in.getScriptSig().correctlySpends(tx, index, new Script(params, prevOut.getScriptBytes(), 0, prevOut.getScriptBytes().length));
blockStore.removeUnspentTransactionOutput(prevOut);
txOutsSpent.add(prevOut);
}
}
Sha256Hash hash = tx.getHash();
for (TransactionOutput out : tx.getOutputs()) {
valueOut = valueOut.add(out.getValue());
// For each output, add it to the set of unspent outputs so it can be consumed in future.
Script script = getScript(out.getScriptBytes());
UTXO newOut = new UTXO(hash,
out.getIndex(),
out.getValue(),
height, isCoinBase,
out.getScriptBytes(),
getScriptAddress(script),
getScriptType(script).ordinal());
blockStore.addUnspentTransactionOutput(newOut);
txOutsCreated.add(newOut);
}
// All values were already checked for being non-negative (as it is verified in Transaction.verify())
// but we check again here just for defence in depth. Transactions with zero output value are OK.
if (valueOut.signum() < 0 || valueOut.compareTo(NetworkParameters.MAX_MONEY) > 0)
throw new VerificationException("Transaction output value out of range");
if (isCoinBase) {
coinbaseValue = valueOut;
} else {
if (valueIn.compareTo(valueOut) < 0 || valueIn.compareTo(NetworkParameters.MAX_MONEY) > 0)
throw new VerificationException("Transaction input value out of range");
totalFees = totalFees.add(valueIn.subtract(valueOut));
}
if (!isCoinBase && runScripts) {
// Because correctlySpends modifies transactions, this must come after we are done with tx
FutureTask<VerificationException> future = new FutureTask<VerificationException>(new Verifier(tx, prevOutScripts, verifyFlags));
scriptVerificationExecutor.execute(future);
listScriptVerificationResults.add(future);
}
}
if (totalFees.compareTo(NetworkParameters.MAX_MONEY) > 0 || block.getBlockInflation(height).add(totalFees).compareTo(coinbaseValue) < 0)
throw new VerificationException("Transaction fees out of range");
for (Future<VerificationException> future : listScriptVerificationResults) {
VerificationException e;
try {
e = future.get();
} catch (InterruptedException thrownE) {
throw new RuntimeException(thrownE); // Shouldn't happen
} catch (ExecutionException thrownE) {
log.error("Script.correctlySpends threw a non-normal exception: " + thrownE.getCause());
throw new VerificationException("Bug in Script.correctlySpends, likely script malformed in some new and interesting way.", thrownE);
}
if (e != null)
throw e;
}
} catch (VerificationException e) {
scriptVerificationExecutor.shutdownNow();
blockStore.abortDatabaseBatchWrite();
throw e;
} catch (BlockStoreException e) {
scriptVerificationExecutor.shutdownNow();
blockStore.abortDatabaseBatchWrite();
throw e;
}
return new TransactionOutputChanges(txOutsCreated, txOutsSpent);
}
@Override
/**
* Used during reorgs to connect a block previously on a fork
*/
protected synchronized TransactionOutputChanges connectTransactions(StoredBlock newBlock)
throws VerificationException, BlockStoreException, PrunedException {
checkState(lock.isHeldByCurrentThread());
if (!params.passesCheckpoint(newBlock.getHeight(), newBlock.getHeader().getHash()))
throw new VerificationException("Block failed checkpoint lockin at " + newBlock.getHeight());
blockStore.beginDatabaseBatchWrite();
StoredUndoableBlock block = blockStore.getUndoBlock(newBlock.getHeader().getHash());
if (block == null) {
// We're trying to re-org too deep and the data needed has been deleted.
blockStore.abortDatabaseBatchWrite();
throw new PrunedException(newBlock.getHeader().getHash());
}
TransactionOutputChanges txOutChanges;
try {
List<Transaction> transactions = block.getTransactions();
if (transactions != null) {
LinkedList<UTXO> txOutsSpent = new LinkedList<UTXO>();
LinkedList<UTXO> txOutsCreated = new LinkedList<UTXO>();
long sigOps = 0;
final Set<VerifyFlag> verifyFlags = EnumSet.noneOf(VerifyFlag.class);
if (newBlock.getHeader().getTimeSeconds() >= NetworkParameters.BIP16_ENFORCE_TIME)
verifyFlags.add(VerifyFlag.P2SH);
if (!params.isCheckpoint(newBlock.getHeight())) {
for(Transaction tx : transactions) {
Sha256Hash hash = tx.getHash();
if (blockStore.hasUnspentOutputs(hash, tx.getOutputs().size()))
throw new VerificationException("Block failed BIP30 test!");
}
}
Coin totalFees = Coin.ZERO;
Coin coinbaseValue = null;
if (scriptVerificationExecutor.isShutdown())
scriptVerificationExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
List<Future<VerificationException>> listScriptVerificationResults = new ArrayList<Future<VerificationException>>(transactions.size());
for(final Transaction tx : transactions) {
boolean isCoinBase = tx.isCoinBase();
Coin valueIn = Coin.ZERO;
Coin valueOut = Coin.ZERO;
final List<Script> prevOutScripts = new LinkedList<Script>();
if (!isCoinBase) {
for (int index = 0; index < tx.getInputs().size(); index++) {
final TransactionInput in = tx.getInputs().get(index);
final UTXO prevOut = blockStore.getTransactionOutput(in.getOutpoint().getHash(),
in.getOutpoint().getIndex());
if (prevOut == null)
throw new VerificationException("Attempted spend of a non-existent or already spent output!");
if (prevOut.isCoinbase() && newBlock.getHeight() - prevOut.getHeight() < params.getSpendableCoinbaseDepth())
throw new VerificationException("Tried to spend coinbase at depth " + (newBlock.getHeight() - prevOut.getHeight()));
valueIn = valueIn.add(prevOut.getValue());
if (verifyFlags.contains(VerifyFlag.P2SH)) {
Script script = new Script(prevOut.getScriptBytes());
if (script.isPayToScriptHash())
sigOps += Script.getP2SHSigOpCount(in.getScriptBytes());
if (sigOps > Block.MAX_BLOCK_SIGOPS)
throw new VerificationException("Too many P2SH SigOps in block");
}
prevOutScripts.add(new Script(prevOut.getScriptBytes()));
blockStore.removeUnspentTransactionOutput(prevOut);
txOutsSpent.add(prevOut);
}
}
Sha256Hash hash = tx.getHash();
for (TransactionOutput out : tx.getOutputs()) {
valueOut = valueOut.add(out.getValue());
Script script = getScript(out.getScriptBytes());
UTXO newOut = new UTXO(hash,
out.getIndex(),
out.getValue(),
newBlock.getHeight(),
isCoinBase,
out.getScriptBytes(),
getScriptAddress(script),
getScriptType(script).ordinal());
blockStore.addUnspentTransactionOutput(newOut);
txOutsCreated.add(newOut);
}
// All values were already checked for being non-negative (as it is verified in Transaction.verify())
// but we check again here just for defence in depth. Transactions with zero output value are OK.
if (valueOut.signum() < 0 || valueOut.compareTo(NetworkParameters.MAX_MONEY) > 0)
throw new VerificationException("Transaction output value out of range");
if (isCoinBase) {
coinbaseValue = valueOut;
} else {
if (valueIn.compareTo(valueOut) < 0 || valueIn.compareTo(NetworkParameters.MAX_MONEY) > 0)
throw new VerificationException("Transaction input value out of range");
totalFees = totalFees.add(valueIn.subtract(valueOut));
}
if (!isCoinBase) {
// Because correctlySpends modifies transactions, this must come after we are done with tx
FutureTask<VerificationException> future = new FutureTask<VerificationException>(new Verifier(tx, prevOutScripts, verifyFlags));
scriptVerificationExecutor.execute(future);
listScriptVerificationResults.add(future);
}
}
if (totalFees.compareTo(NetworkParameters.MAX_MONEY) > 0 ||
newBlock.getHeader().getBlockInflation(newBlock.getHeight()).add(totalFees).compareTo(coinbaseValue) < 0)
throw new VerificationException("Transaction fees out of range");
txOutChanges = new TransactionOutputChanges(txOutsCreated, txOutsSpent);
for (Future<VerificationException> future : listScriptVerificationResults) {
VerificationException e;
try {
e = future.get();
} catch (InterruptedException thrownE) {
throw new RuntimeException(thrownE); // Shouldn't happen
} catch (ExecutionException thrownE) {
log.error("Script.correctlySpends threw a non-normal exception: " + thrownE.getCause());
throw new VerificationException("Bug in Script.correctlySpends, likely script malformed in some new and interesting way.", thrownE);
}
if (e != null)
throw e;
}
} else {
txOutChanges = block.getTxOutChanges();
if (!params.isCheckpoint(newBlock.getHeight()))
for(UTXO out : txOutChanges.txOutsCreated) {
Sha256Hash hash = out.getHash();
if (blockStore.getTransactionOutput(hash, out.getIndex()) != null)
throw new VerificationException("Block failed BIP30 test!");
}
for (UTXO out : txOutChanges.txOutsCreated)
blockStore.addUnspentTransactionOutput(out);
for (UTXO out : txOutChanges.txOutsSpent)
blockStore.removeUnspentTransactionOutput(out);
}
} catch (VerificationException e) {
scriptVerificationExecutor.shutdownNow();
blockStore.abortDatabaseBatchWrite();
throw e;
} catch (BlockStoreException e) {
scriptVerificationExecutor.shutdownNow();
blockStore.abortDatabaseBatchWrite();
throw e;
}
return txOutChanges;
}
/**
* This is broken for blocks that do not pass BIP30, so all BIP30-failing blocks which are allowed to fail BIP30
* must be checkpointed.
*/
@Override
protected void disconnectTransactions(StoredBlock oldBlock) throws PrunedException, BlockStoreException {
checkState(lock.isHeldByCurrentThread());
blockStore.beginDatabaseBatchWrite();
try {
StoredUndoableBlock undoBlock = blockStore.getUndoBlock(oldBlock.getHeader().getHash());
if (undoBlock == null) throw new PrunedException(oldBlock.getHeader().getHash());
TransactionOutputChanges txOutChanges = undoBlock.getTxOutChanges();
for(UTXO out : txOutChanges.txOutsSpent)
blockStore.addUnspentTransactionOutput(out);
for(UTXO out : txOutChanges.txOutsCreated)
blockStore.removeUnspentTransactionOutput(out);
} catch (PrunedException e) {
blockStore.abortDatabaseBatchWrite();
throw e;
} catch (BlockStoreException e) {
blockStore.abortDatabaseBatchWrite();
throw e;
}
}
@Override
protected void doSetChainHead(StoredBlock chainHead) throws BlockStoreException {
checkState(lock.isHeldByCurrentThread());
blockStore.setVerifiedChainHead(chainHead);
blockStore.commitDatabaseBatchWrite();
}
@Override
protected void notSettingChainHead() throws BlockStoreException {
blockStore.abortDatabaseBatchWrite();
}
@Override
protected StoredBlock getStoredBlockInCurrentScope(Sha256Hash hash) throws BlockStoreException {
checkState(lock.isHeldByCurrentThread());
return blockStore.getOnceUndoableStoredBlock(hash);
}
}

View File

@@ -1,30 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
/**
* Represents the "getaddr" P2P protocol message, which requests network {@link AddressMessage}s from a peer. Not to
* be confused with {@link Address} which is sort of like an account number.
*/
public class GetAddrMessage extends EmptyMessage {
private static final long serialVersionUID = 6204437624599661503L;
public GetAddrMessage(NetworkParameters params) {
super(params);
}
}

View File

@@ -1,122 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Represents the "getblocks" P2P network message, which requests the hashes of the parts of the block chain we're
* missing. Those blocks can then be downloaded with a {@link GetDataMessage}.
*/
public class GetBlocksMessage extends Message {
private static final long serialVersionUID = 3479412877853645644L;
protected long version;
protected List<Sha256Hash> locator;
protected Sha256Hash stopHash;
public GetBlocksMessage(NetworkParameters params, List<Sha256Hash> locator, Sha256Hash stopHash) {
super(params);
this.version = protocolVersion;
this.locator = locator;
this.stopHash = stopHash;
}
public GetBlocksMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0);
}
@Override
protected void parseLite() throws ProtocolException {
cursor = offset;
version = readUint32();
int startCount = (int) readVarInt();
if (startCount > 500)
throw new ProtocolException("Number of locators cannot be > 500, received: " + startCount);
length = (int) (cursor - offset + ((startCount + 1) * 32));
}
@Override
public void parse() throws ProtocolException {
cursor = offset;
version = readUint32();
int startCount = (int) readVarInt();
if (startCount > 500)
throw new ProtocolException("Number of locators cannot be > 500, received: " + startCount);
locator = new ArrayList<Sha256Hash>(startCount);
for (int i = 0; i < startCount; i++) {
locator.add(readHash());
}
stopHash = readHash();
}
public List<Sha256Hash> getLocator() {
return locator;
}
public Sha256Hash getStopHash() {
return stopHash;
}
@Override
public String toString() {
StringBuffer b = new StringBuffer();
b.append("getblocks: ");
for (Sha256Hash hash : locator) {
b.append(hash.toString());
b.append(" ");
}
return b.toString();
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
// Version, for some reason.
Utils.uint32ToByteStreamLE(NetworkParameters.PROTOCOL_VERSION, stream);
// Then a vector of block hashes. This is actually a "block locator", a set of block
// identifiers that spans the entire chain with exponentially increasing gaps between
// them, until we end up at the genesis block. See CBlockLocator::Set()
stream.write(new VarInt(locator.size()).encode());
for (Sha256Hash hash : locator) {
// Have to reverse as wire format is little endian.
stream.write(Utils.reverseBytes(hash.getBytes()));
}
// Next, a block ID to stop at.
stream.write(Utils.reverseBytes(stopHash.getBytes()));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetBlocksMessage other = (GetBlocksMessage) o;
return version == other.version &&
locator.size() == other.locator.size() &&
locator.containsAll(other.locator) &&
stopHash.equals(other.stopHash);
}
@Override
public int hashCode() {
int hashCode = (int) version ^ "getblocks".hashCode();
for (Sha256Hash aLocator : locator) hashCode ^= aLocator.hashCode();
hashCode ^= stopHash.hashCode();
return hashCode;
}
}

View File

@@ -1,66 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
/**
* Represents the "getdata" P2P network message, which requests the contents of blocks or transactions given their
* hashes.
*/
public class GetDataMessage extends ListMessage {
private static final long serialVersionUID = 2754681589501709887L;
public GetDataMessage(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes);
}
/**
* Deserializes a 'getdata' message.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
public GetDataMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, payload, parseLazy, parseRetain, length);
}
public GetDataMessage(NetworkParameters params) {
super(params);
}
public void addTransaction(Sha256Hash hash) {
addItem(new InventoryItem(InventoryItem.Type.Transaction, hash));
}
public void addBlock(Sha256Hash hash) {
addItem(new InventoryItem(InventoryItem.Type.Block, hash));
}
public void addFilteredBlock(Sha256Hash hash) {
addItem(new InventoryItem(InventoryItem.Type.FilteredBlock, hash));
}
public Sha256Hash getHashOf(int i) {
return getItems().get(i).hash;
}
}

View File

@@ -1,69 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.util.List;
/**
* The "getheaders" command is structurally identical to "getblocks", but has different meaning. On receiving this
* message a Bitcoin node returns matching blocks up to the limit, but without the bodies. It is useful as an
* optimization: when your wallet does not contain any keys created before a particular time, you don't have to download
* the bodies for those blocks because you know there are no relevant transactions.
*/
public class GetHeadersMessage extends GetBlocksMessage {
public GetHeadersMessage(NetworkParameters params, List<Sha256Hash> locator, Sha256Hash stopHash) {
super(params, locator, stopHash);
}
public GetHeadersMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload);
}
@Override
public String toString() {
StringBuffer b = new StringBuffer();
b.append("getheaders: ");
for (Sha256Hash hash : locator) {
b.append(hash.toString());
b.append(" ");
}
return b.toString();
}
/**
* Compares two getheaders messages. Note that even though they are structurally identical a GetHeadersMessage
* will not compare equal to a GetBlocksMessage containing the same data.
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetHeadersMessage other = (GetHeadersMessage) o;
return version == other.version &&
locator.size() == other.locator.size() &&
locator.containsAll(other.locator) &&
stopHash.equals(other.stopHash);
}
@Override
public int hashCode() {
int hashCode = (int) version ^ "getheaders".hashCode();
for (Sha256Hash aLocator : locator) hashCode ^= aLocator.hashCode();
hashCode ^= stopHash.hashCode();
return hashCode;
}
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright 2014 the bitcoinj authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
/**
* This command is supported only by <a href="http://github.com/bitcoinxt/bitcoinxt">Bitcoin XT</a> nodes, which
* advertise themselves using the second service bit flag. It requests a query of the UTXO set keyed by a set of
* outpoints (i.e. tx hash and output index). The result contains a bitmap of spentness flags, and the contents of
* the associated outputs if they were found. The results aren't authenticated by anything, so the peer could lie,
* or a man in the middle could swap out its answer for something else.
*/
public class GetUTXOsMessage extends Message {
public static final int MIN_PROTOCOL_VERSION = 70002;
/** Bitmask of service flags required for a node to support this command (0x3) */
public static final int SERVICE_FLAGS_REQUIRED = 3;
private boolean includeMempool;
private ImmutableList<TransactionOutPoint> outPoints;
public GetUTXOsMessage(NetworkParameters params, List<TransactionOutPoint> outPoints, boolean includeMempool) {
super(params);
this.outPoints = ImmutableList.copyOf(outPoints);
this.includeMempool = includeMempool;
}
public GetUTXOsMessage(NetworkParameters params, byte[] payloadBytes) {
super(params, payloadBytes, 0);
}
@Override
protected void parse() throws ProtocolException {
includeMempool = readBytes(1)[0] == 1;
long numOutpoints = readVarInt();
ImmutableList.Builder<TransactionOutPoint> list = ImmutableList.builder();
for (int i = 0; i < numOutpoints; i++) {
TransactionOutPoint outPoint = new TransactionOutPoint(params, payload, cursor);
list.add(outPoint);
cursor += outPoint.getMessageSize();
}
outPoints = list.build();
length = cursor;
}
public boolean getIncludeMempool() {
return includeMempool;
}
public ImmutableList<TransactionOutPoint> getOutPoints() {
return outPoints;
}
@Override
protected void parseLite() throws ProtocolException {
// Not needed.
}
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new byte[]{1}); // include mempool.
stream.write(new VarInt(outPoints.size()).encode());
for (TransactionOutPoint outPoint : outPoints) {
outPoint.bitcoinSerializeToStream(stream);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GetUTXOsMessage that = (GetUTXOsMessage) o;
if (includeMempool != that.includeMempool) return false;
if (!outPoints.equals(that.outPoints)) return false;
return true;
}
@Override
public int hashCode() {
int result = (includeMempool ? 1 : 0);
result = 31 * result + outPoints.hashCode();
return result;
}
}

View File

@@ -1,109 +0,0 @@
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A protocol message that contains a repeated series of block headers, sent in response to the "getheaders" command.
* This is useful when you want to traverse the chain but know you don't care about the block contents, for example,
* because you have a freshly created wallet with no keys.
*/
public class HeadersMessage extends Message {
private static final Logger log = LoggerFactory.getLogger(HeadersMessage.class);
// The main client will never send us more than this number of headers.
public static final int MAX_HEADERS = 2000;
private List<Block> blockHeaders;
public HeadersMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0);
}
public HeadersMessage(NetworkParameters params, Block... headers) throws ProtocolException {
super(params);
blockHeaders = Arrays.asList(headers);
}
public HeadersMessage(NetworkParameters params, List<Block> headers) throws ProtocolException {
super(params);
blockHeaders = headers;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new VarInt(blockHeaders.size()).encode());
for (Block header : blockHeaders) {
if (header.transactions == null)
header.bitcoinSerializeToStream(stream);
else
header.cloneAsHeader().bitcoinSerializeToStream(stream);
stream.write(0);
}
}
@Override
protected void parseLite() throws ProtocolException {
if (length == UNKNOWN_LENGTH) {
int saveCursor = cursor;
long numHeaders = readVarInt();
cursor = saveCursor;
// Each header has 80 bytes and one more byte for transactions number which is 00.
length = 81 * (int)numHeaders;
}
}
@Override
void parse() throws ProtocolException {
long numHeaders = readVarInt();
if (numHeaders > MAX_HEADERS)
throw new ProtocolException("Too many headers: got " + numHeaders + " which is larger than " +
MAX_HEADERS);
blockHeaders = new ArrayList<Block>();
for (int i = 0; i < numHeaders; ++i) {
// Read 80 bytes of the header and one more byte for the transaction list, which is always a 00 because the
// transaction list is empty.
byte[] blockHeader = readBytes(81);
if (blockHeader[80] != 0)
throw new ProtocolException("Block header does not end with a null byte");
Block newBlockHeader = new Block(this.params, blockHeader, true, true, 81);
blockHeaders.add(newBlockHeader);
}
if (log.isDebugEnabled()) {
for (int i = 0; i < numHeaders; ++i) {
log.debug(this.blockHeaders.get(i).toString());
}
}
}
public List<Block> getBlockHeaders() {
return blockHeaders;
}
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Thrown to indicate that you don't have enough money available to perform the requested operation.
*/
public class InsufficientMoneyException extends Exception {
/** Contains the number of satoshis that would have been required to complete the operation. */
@Nullable
public final Coin missing;
protected InsufficientMoneyException() {
this.missing = null;
}
public InsufficientMoneyException(Coin missing) {
this(missing, "Insufficient money, missing " + missing + " satoshis");
}
public InsufficientMoneyException(Coin missing, String message) {
super(message);
this.missing = checkNotNull(missing);
}
}

View File

@@ -1,60 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
public class InventoryItem {
/**
* 4 byte uint32 type field + 32 byte hash
*/
static final int MESSAGE_LENGTH = 36;
public enum Type {
Error,
Transaction,
Block,
FilteredBlock
}
public final Type type;
public final Sha256Hash hash;
public InventoryItem(Type type, Sha256Hash hash) {
this.type = type;
this.hash = hash;
}
@Override
public String toString() {
return type.toString() + ": " + hash;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InventoryItem other = (InventoryItem) o;
return type == other.type &&
hash.equals(other.hash);
}
@Override
public int hashCode() {
return hash.hashCode() + type.ordinal();
}
}

View File

@@ -1,74 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import static com.google.common.base.Preconditions.checkArgument;
/**
* <p>Represents the "inv" P2P network message. An inv contains a list of hashes of either blocks or transactions. It's
* a bandwidth optimization - on receiving some data, a (fully validating) peer sends every connected peer an inv
* containing the hash of what it saw. It'll only transmit the full thing if a peer asks for it with a
* {@link GetDataMessage}.</p>
*/
public class InventoryMessage extends ListMessage {
private static final long serialVersionUID = -7050246551646107066L;
/** A hard coded constant in the protocol. */
public static final int MAX_INV_SIZE = 50000;
public InventoryMessage(NetworkParameters params, byte[] bytes) throws ProtocolException {
super(params, bytes);
}
/**
* Deserializes an 'inv' message.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
public InventoryMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, payload, parseLazy, parseRetain, length);
}
public InventoryMessage(NetworkParameters params) {
super(params);
}
public void addBlock(Block block) {
addItem(new InventoryItem(InventoryItem.Type.Block, block.getHash()));
}
public void addTransaction(Transaction tx) {
addItem(new InventoryItem(InventoryItem.Type.Transaction, tx.getHash()));
}
/** Creates a new inv message for the given transactions. */
public static InventoryMessage with(Transaction... txns) {
checkArgument(txns.length > 0);
InventoryMessage result = new InventoryMessage(txns[0].getParams());
for (Transaction tx : txns)
result.addTransaction(tx);
return result;
}
}

View File

@@ -1,135 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Abstract superclass of classes with list based payload, ie InventoryMessage and GetDataMessage.
*/
public abstract class ListMessage extends Message {
private static final long serialVersionUID = -4275896329391143643L;
private long arrayLen;
// For some reason the compiler complains if this is inside InventoryItem
protected List<InventoryItem> items;
public static final long MAX_INVENTORY_ITEMS = 50000;
public ListMessage(NetworkParameters params, byte[] bytes) throws ProtocolException {
super(params, bytes, 0);
}
public ListMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, payload, 0, parseLazy, parseRetain, length);
}
public ListMessage(NetworkParameters params) {
super(params);
items = new ArrayList<InventoryItem>();
length = 1; //length of 0 varint;
}
public List<InventoryItem> getItems() {
maybeParse();
return Collections.unmodifiableList(items);
}
public void addItem(InventoryItem item) {
unCache();
length -= VarInt.sizeOf(items.size());
items.add(item);
length += VarInt.sizeOf(items.size()) + InventoryItem.MESSAGE_LENGTH;
}
public void removeItem(int index) {
unCache();
length -= VarInt.sizeOf(items.size());
items.remove(index);
length += VarInt.sizeOf(items.size()) - InventoryItem.MESSAGE_LENGTH;
}
@Override
protected void parseLite() throws ProtocolException {
arrayLen = readVarInt();
if (arrayLen > MAX_INVENTORY_ITEMS)
throw new ProtocolException("Too many items in INV message: " + arrayLen);
length = (int) (cursor - offset + (arrayLen * InventoryItem.MESSAGE_LENGTH));
}
@Override
public void parse() throws ProtocolException {
// An inv is vector<CInv> where CInv is int+hash. The int is either 1 or 2 for tx or block.
items = new ArrayList<InventoryItem>((int) arrayLen);
for (int i = 0; i < arrayLen; i++) {
if (cursor + InventoryItem.MESSAGE_LENGTH > payload.length) {
throw new ProtocolException("Ran off the end of the INV");
}
int typeCode = (int) readUint32();
InventoryItem.Type type;
// See ppszTypeName in net.h
switch (typeCode) {
case 0:
type = InventoryItem.Type.Error;
break;
case 1:
type = InventoryItem.Type.Transaction;
break;
case 2:
type = InventoryItem.Type.Block;
break;
case 3:
type = InventoryItem.Type.FilteredBlock;
break;
default:
throw new ProtocolException("Unknown CInv type: " + typeCode);
}
InventoryItem item = new InventoryItem(type, readHash());
items.add(item);
}
payload = null;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new VarInt(items.size()).encode());
for (InventoryItem i : items) {
// Write out the type code.
Utils.uint32ToByteStreamLE(i.type.ordinal(), stream);
// And now the hash.
stream.write(Utils.reverseBytes(i.hash.getBytes()));
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ListMessage other = (ListMessage) o;
return items.equals(other.items);
}
@Override
public int hashCode() {
return items.hashCode();
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
/**
* The "mempool" message asks a remote peer to announce all transactions in its memory pool, possibly restricted by
* any Bloom filter set on the connection. The list of transaction hashes comes back in an inv message. Note that
* this is different to the {@link TxConfidenceTable} object which doesn't try to keep track of all pending transactions,
* it's just a holding area for transactions that a part of the app may find interesting. The mempool message has
* no fields.
*/
public class MemoryPoolMessage extends Message {
@Override
void parse() throws ProtocolException {}
@Override
protected void parseLite() throws ProtocolException {}
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {}
}

View File

@@ -0,0 +1,222 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A Merkle branch contains the hashes from a leaf of a Merkle tree
* up to its root, plus a bitset used to define how the hashes are applied.
* Given the hash of the leaf, this can be used to calculate the tree
* root. This is useful for proving that a leaf belongs to a given tree.
*
* TODO: Has a lot of similarity to PartialMerkleTree, should attempt to merge
* the two.
*/
public class MerkleBranch extends ChildMessage {
private static final long serialVersionUID = 2;
// Merkle branches can be encoded in a way that will use more bytes than is optimal
// (due to VarInts having multiple encodings)
// MAX_BLOCK_SIZE must be compared to the optimal encoding, not the actual encoding, so when parsing, we keep track
// of the size of the ideal encoding in addition to the actual message size (which Message needs) so that Blocks
// can properly keep track of optimal encoded size
private transient int optimalEncodingMessageSize;
private List<Sha256Hash> hashes;
private long index;
public MerkleBranch(NetworkParameters params, @Nullable ChildMessage parent) {
super(params);
setParent(parent);
this.hashes = new ArrayList<Sha256Hash>();
this.index = 0;
}
/**
* Deserializes an input message. This is usually part of a merkle branch message.
*/
public MerkleBranch(NetworkParameters params, @Nullable ChildMessage parent, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
setParent(parent);
}
/**
* Deserializes an input message. This is usually part of a merkle branch message.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param serializer the serializer to use for this message.
* @throws ProtocolException
*/
public MerkleBranch(NetworkParameters params, ChildMessage parent, byte[] payload, int offset,
MessageSerializer serializer)
throws ProtocolException {
super(params, payload, offset, parent, serializer, UNKNOWN_LENGTH);
}
public MerkleBranch(NetworkParameters params, @Nullable ChildMessage parent,
final List<Sha256Hash> hashes, final long branchSideMask) {
super(params);
setParent(parent);
this.hashes = hashes;
this.index = branchSideMask;
}
public static int calcLength(byte[] buf, int offset) {
VarInt varint = new VarInt(buf, offset);
return ((int) varint.value) * 4 + 4;
}
@Override
protected void parse() throws ProtocolException {
cursor = offset;
final int hashCount = (int) readVarInt();
optimalEncodingMessageSize += VarInt.sizeOf(hashCount);
hashes = new ArrayList<Sha256Hash>(hashCount);
for (int hashIdx = 0; hashIdx < hashCount; hashIdx++) {
hashes.add(readHash());
}
optimalEncodingMessageSize += 32 * hashCount;
setIndex(readUint32());
optimalEncodingMessageSize += 4;
length = cursor - offset;
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(new VarInt(hashes.size()).encode());
for (Sha256Hash hash: hashes) {
stream.write(Utils.reverseBytes(hash.getBytes()));
}
Utils.uint32ToByteStreamLE(index, stream);
}
/**
* Calculate the merkle branch root based on the supplied hashes and the given leaf hash.
* Used to verify that the given leaf and root are part of the same tree.
*/
public Sha256Hash calculateMerkleRoot(final Sha256Hash leaf) {
byte[] target = leaf.getReversedBytes();
long mask = index;
MessageDigest digest = Sha256Hash.newDigest();
for (Sha256Hash hash: hashes) {
digest.reset();
if ((mask & 1) == 0) { // 0 means it goes on the right
digest.update(target);
digest.update(hash.getReversedBytes());
} else {
digest.update(hash.getReversedBytes());
digest.update(target);
}
// Double-digest the values
target = digest.digest();
digest.reset();
target = digest.digest(target);
mask >>= 1;
}
return Sha256Hash.wrapReversed(target);
}
/**
* Get the hashes which make up this branch.
*/
public List<Sha256Hash> getHashes() {
return Collections.unmodifiableList(this.hashes);
}
/**
* Return the mask used to determine which side the hashes are applied on.
* Each bit represents a hash. Zero means it goes on the right, one means
* on the left.
*/
public long getIndex() {
return index;
}
/**
* @param hashes the hashes to set
*/
public void setHashes(List<Sha256Hash> hashes) {
this.hashes = hashes;
}
/**
* Set the mask used to determine the sides in which hashes are applied.
*/
public void setIndex(final long newIndex) {
assert newIndex >= 0;
this.index = newIndex;
}
/**
* Get the number of hashes in this branch.
*/
public int size() {
return hashes.size();
}
public int getOptimalEncodingMessageSize() {
if (optimalEncodingMessageSize != 0)
return optimalEncodingMessageSize;
if (optimalEncodingMessageSize != 0)
return optimalEncodingMessageSize;
optimalEncodingMessageSize = getMessageSize();
return optimalEncodingMessageSize;
}
/**
* Returns a human readable debug string.
*/
@Override
public String toString() {
return "Merkle branch";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MerkleBranch input = (MerkleBranch) o;
if (!hashes.equals(input.hashes)) return false;
if (index != input.index) return false;
return true;
}
@Override
public int hashCode() {
int result = 1;
result = 31 * result + hashes.hashCode();
result = 31 * result + (int) index;
return result;
}
}

View File

@@ -1,527 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigInteger;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkState;
/**
* <p>A Message is a data structure that can be serialized/deserialized using both the Bitcoin proprietary serialization
* format and built-in Java object serialization. Specific types of messages that are used both in the block chain,
* and on the wire, are derived from this class.</p>
*/
public abstract class Message implements Serializable {
private static final Logger log = LoggerFactory.getLogger(Message.class);
private static final long serialVersionUID = -3561053461717079135L;
public static final int MAX_SIZE = 0x02000000; // 32MB
public static final int UNKNOWN_LENGTH = Integer.MIN_VALUE;
// Useful to ensure serialize/deserialize are consistent with each other.
private static final boolean SELF_CHECK = false;
// The offset is how many bytes into the provided byte array this message payload starts at.
protected transient int offset;
// The cursor keeps track of where we are in the byte array as we parse it.
// Note that it's relative to the start of the array NOT the start of the message payload.
protected transient int cursor;
protected transient int length = UNKNOWN_LENGTH;
// The raw message payload bytes themselves.
protected transient byte[] payload;
protected transient boolean parsed = false;
protected transient boolean recached = false;
protected transient final boolean parseLazy;
protected transient final boolean parseRetain;
protected transient int protocolVersion;
protected transient byte[] checksum;
// This will be saved by subclasses that implement Serializable.
protected NetworkParameters params;
/**
* This exists for the Java serialization framework to use only.
*/
protected Message() {
parsed = true;
parseLazy = false;
parseRetain = false;
}
Message(NetworkParameters params) {
this.params = params;
parsed = true;
parseLazy = false;
parseRetain = false;
}
Message(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException {
this(params, payload, offset, protocolVersion, false, false, UNKNOWN_LENGTH);
}
/**
*
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param protocolVersion Bitcoin protocol version.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @param length The length of message payload if known. Usually this is provided when deserializing of the wire
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
Message(NetworkParameters params, byte[] payload, int offset, int protocolVersion, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
this.parseLazy = parseLazy;
this.parseRetain = parseRetain;
this.protocolVersion = protocolVersion;
this.params = params;
this.payload = payload;
this.cursor = this.offset = offset;
this.length = length;
if (parseLazy) {
parseLite();
} else {
parseLite();
parse();
parsed = true;
}
if (this.length == UNKNOWN_LENGTH)
checkState(false, "Length field has not been set in constructor for %s after %s parse. " +
"Refer to Message.parseLite() for detail of required Length field contract.",
getClass().getSimpleName(), parseLazy ? "lite" : "full");
if (SELF_CHECK) {
selfCheck(payload, offset);
}
if (parseRetain || !parsed)
return;
this.payload = null;
}
private void selfCheck(byte[] payload, int offset) {
if (!(this instanceof VersionMessage)) {
maybeParse();
byte[] payloadBytes = new byte[cursor - offset];
System.arraycopy(payload, offset, payloadBytes, 0, cursor - offset);
byte[] reserialized = bitcoinSerialize();
if (!Arrays.equals(reserialized, payloadBytes))
throw new RuntimeException("Serialization is wrong: \n" +
Utils.HEX.encode(reserialized) + " vs \n" +
Utils.HEX.encode(payloadBytes));
}
}
Message(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
this(params, payload, offset, NetworkParameters.PROTOCOL_VERSION, false, false, UNKNOWN_LENGTH);
}
Message(NetworkParameters params, byte[] payload, int offset, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
this(params, payload, offset, NetworkParameters.PROTOCOL_VERSION, parseLazy, parseRetain, length);
}
// These methods handle the serialization/deserialization using the custom Bitcoin protocol.
// It's somewhat painful to work with in Java, so some of these objects support a second
// serialization mechanism - the standard Java serialization system. This is used when things
// are serialized to the wallet.
abstract void parse() throws ProtocolException;
/**
* Perform the most minimal parse possible to calculate the length of the message payload.
* This is only required for subclasses of ChildMessage as root level messages will have their length passed
* into the constructor.
* <p/>
* Implementations should adhere to the following contract: If parseLazy = true the 'length'
* field must be set before returning. If parseLazy = false the length field must be set either
* within the parseLite() method OR the parse() method. The overriding requirement is that length
* must be set to non UNKNOWN_MESSAGE value by the time the constructor exits.
*
* @return
* @throws ProtocolException
*/
protected abstract void parseLite() throws ProtocolException;
/**
* Ensure the object is parsed if needed. This should be called in every getter before returning a value.
* If the lazy parse flag is not set this is a method returns immediately.
*/
protected synchronized void maybeParse() {
if (parsed || payload == null)
return;
try {
parse();
parsed = true;
if (!parseRetain)
payload = null;
} catch (ProtocolException e) {
throw new LazyParseException("ProtocolException caught during lazy parse. For safe access to fields call ensureParsed before attempting read or write access", e);
}
}
/**
* In lazy parsing mode access to getters and setters may throw an unchecked LazyParseException. If guaranteed safe access is required
* this method will force parsing to occur immediately thus ensuring LazyParseExeption will never be thrown from this Message.
* If the Message contains child messages (e.g. a Block containing Transaction messages) this will not force child messages to parse.
* <p/>
* This could be overidden for Transaction and it's child classes to ensure the entire tree of Message objects is parsed.
*
* @throws ProtocolException
*/
public void ensureParsed() throws ProtocolException {
try {
maybeParse();
} catch (LazyParseException e) {
if (e.getCause() instanceof ProtocolException)
throw (ProtocolException) e.getCause();
throw new ProtocolException(e);
}
}
/**
* To be called before any change of internal values including any setters. This ensures any cached byte array is
* removed after performing a lazy parse if necessary to ensure the object is fully populated.
* <p/>
* Child messages of this object(e.g. Transactions belonging to a Block) will not have their internal byte caches
* invalidated unless they are also modified internally.
*/
protected void unCache() {
maybeParse();
checksum = null;
payload = null;
recached = false;
}
protected void adjustLength(int newArraySize, int adjustment) {
if (length == UNKNOWN_LENGTH)
return;
// Our own length is now unknown if we have an unknown length adjustment.
if (adjustment == UNKNOWN_LENGTH) {
length = UNKNOWN_LENGTH;
return;
}
length += adjustment;
// Check if we will need more bytes to encode the length prefix.
if (newArraySize == 1)
length++; // The assumption here is we never call adjustLength with the same arraySize as before.
else if (newArraySize != 0)
length += VarInt.sizeOf(newArraySize) - VarInt.sizeOf(newArraySize - 1);
}
/**
* used for unit testing
*/
public boolean isParsed() {
return parsed;
}
/**
* used for unit testing
*/
public boolean isCached() {
return payload != null;
}
public boolean isRecached() {
return recached;
}
/**
* Should only used by BitcoinSerializer for cached checksum
*
* @return the checksum
*/
byte[] getChecksum() {
return checksum;
}
/**
* Should only used by BitcoinSerializer for caching checksum
*
* @param checksum the checksum to set
*/
void setChecksum(byte[] checksum) {
if (checksum.length != 4)
throw new IllegalArgumentException("Checksum length must be 4 bytes, actual length: " + checksum.length);
this.checksum = checksum;
}
/**
* Returns a copy of the array returned by {@link Message#unsafeBitcoinSerialize()}, which is safe to mutate.
* If you need extra performance and can guarantee you won't write to the array, you can use the unsafe version.
*
* @return a freshly allocated serialized byte array
*/
public byte[] bitcoinSerialize() {
byte[] bytes = unsafeBitcoinSerialize();
byte[] copy = new byte[bytes.length];
System.arraycopy(bytes, 0, copy, 0, bytes.length);
return copy;
}
/**
* Serialize this message to a byte array that conforms to the bitcoin wire protocol.
* <br/>
* This method may return the original byte array used to construct this message if the
* following conditions are met:
* <ol>
* <li>1) The message was parsed from a byte array with parseRetain = true</li>
* <li>2) The message has not been modified</li>
* <li>3) The array had an offset of 0 and no surplus bytes</li>
* </ol>
*
* If condition 3 is not met then an copy of the relevant portion of the array will be returned.
* Otherwise a full serialize will occur. For this reason you should only use this API if you can guarantee you
* will treat the resulting array as read only.
*
* @return a byte array owned by this object, do NOT mutate it.
*/
public byte[] unsafeBitcoinSerialize() {
// 1st attempt to use a cached array.
if (payload != null) {
if (offset == 0 && length == payload.length) {
// Cached byte array is the entire message with no extras so we can return as is and avoid an array
// copy.
return payload;
}
byte[] buf = new byte[length];
System.arraycopy(payload, offset, buf, 0, length);
return buf;
}
// No cached array available so serialize parts by stream.
ByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(length < 32 ? 32 : length + 32);
try {
bitcoinSerializeToStream(stream);
} catch (IOException e) {
// Cannot happen, we are serializing to a memory stream.
}
if (parseRetain) {
// A free set of steak knives!
// If there happens to be a call to this method we gain an opportunity to recache
// the byte array and in this case it contains no bytes from parent messages.
// This give a dual benefit. Releasing references to the larger byte array so that it
// it is more likely to be GC'd. And preventing double serializations. E.g. calculating
// merkle root calls this method. It is will frequently happen prior to serializing the block
// which means another call to bitcoinSerialize is coming. If we didn't recache then internal
// serialization would occur a 2nd time and every subsequent time the message is serialized.
payload = stream.toByteArray();
cursor = cursor - offset;
offset = 0;
recached = true;
length = payload.length;
return payload;
}
// Record length. If this Message wasn't parsed from a byte stream it won't have length field
// set (except for static length message types). Setting it makes future streaming more efficient
// because we can preallocate the ByteArrayOutputStream buffer and avoid resizing.
byte[] buf = stream.toByteArray();
length = buf.length;
return buf;
}
/**
* Serialize this message to the provided OutputStream using the bitcoin wire format.
*
* @param stream
* @throws IOException
*/
final public void bitcoinSerialize(OutputStream stream) throws IOException {
// 1st check for cached bytes.
if (payload != null && length != UNKNOWN_LENGTH) {
stream.write(payload, offset, length);
return;
}
bitcoinSerializeToStream(stream);
}
/**
* Serializes this message to the provided stream. If you just want the raw bytes use bitcoinSerialize().
*/
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
log.error("Error: {} class has not implemented bitcoinSerializeToStream method. Generating message with no payload", getClass());
}
/**
* This method is a NOP for all classes except Block and Transaction. It is only declared in Message
* so BitcoinSerializer can avoid 2 instanceof checks + a casting.
*/
public Sha256Hash getHash() {
throw new UnsupportedOperationException();
}
/**
* This should be overridden to extract correct message size in the case of lazy parsing. Until this method is
* implemented in a subclass of ChildMessage lazy parsing may have no effect.
*
* This default implementation is a safe fall back that will ensure it returns a correct value by parsing the message.
*/
public int getMessageSize() {
if (length != UNKNOWN_LENGTH)
return length;
maybeParse();
if (length == UNKNOWN_LENGTH)
checkState(false, "Length field has not been set in %s after full parse.", getClass().getSimpleName());
return length;
}
long readUint32() throws ProtocolException {
try {
long u = Utils.readUint32(payload, cursor);
cursor += 4;
return u;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
Sha256Hash readHash() throws ProtocolException {
try {
byte[] hash = new byte[32];
System.arraycopy(payload, cursor, hash, 0, 32);
// We have to flip it around, as it's been read off the wire in little endian.
// Not the most efficient way to do this but the clearest.
hash = Utils.reverseBytes(hash);
cursor += 32;
return new Sha256Hash(hash);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
long readInt64() throws ProtocolException {
try {
long u = Utils.readInt64(payload, cursor);
cursor += 8;
return u;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
BigInteger readUint64() throws ProtocolException {
try {
// Java does not have an unsigned 64 bit type. So scrape it off the wire then flip.
byte[] valbytes = new byte[8];
System.arraycopy(payload, cursor, valbytes, 0, 8);
valbytes = Utils.reverseBytes(valbytes);
cursor += valbytes.length;
return new BigInteger(valbytes);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
long readVarInt() throws ProtocolException {
return readVarInt(0);
}
long readVarInt(int offset) throws ProtocolException {
try {
VarInt varint = new VarInt(payload, cursor + offset);
cursor += offset + varint.getOriginalSizeInBytes();
return varint.value;
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
byte[] readBytes(int length) throws ProtocolException {
if (length > MAX_SIZE) {
throw new ProtocolException("Claimed byte array length too large: " + length);
}
try {
byte[] b = new byte[length];
System.arraycopy(payload, cursor, b, 0, length);
cursor += length;
return b;
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
byte[] readByteArray() throws ProtocolException {
long len = readVarInt();
return readBytes((int)len);
}
String readStr() throws ProtocolException {
try {
VarInt varInt = new VarInt(payload, cursor);
if (varInt.value == 0) {
cursor += 1;
return "";
}
cursor += varInt.getOriginalSizeInBytes();
if (varInt.value > MAX_SIZE) {
throw new ProtocolException("Claimed var_str length too large: " + varInt.value);
}
byte[] characters = new byte[(int) varInt.value];
System.arraycopy(payload, cursor, characters, 0, characters.length);
cursor += characters.length;
try {
return new String(characters, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported.
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new ProtocolException(e);
} catch (IndexOutOfBoundsException e) {
throw new ProtocolException(e);
}
}
boolean hasMoreBytes() {
return cursor < payload.length;
}
/** Network parameters this message was created with. */
public NetworkParameters getParams() {
return params;
}
public static class LazyParseException extends RuntimeException {
private static final long serialVersionUID = 6971943053112975594L;
public LazyParseException(String message, Throwable cause) {
super(message, cause);
}
public LazyParseException(String message) {
super(message);
}
}
}

View File

@@ -1,38 +0,0 @@
/**
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.Serializable;
/**
* Classes implementing this interface represent a monetary value, such as a Bitcoin or fiat amount.
*/
public interface Monetary extends Serializable {
/**
* Returns the absolute value of exponent of the value of a "smallest unit" in scientific notation. For Bitcoin, a
* satoshi is worth 1E-8 so this would be 8.
*/
int smallestUnitExponent();
/**
* Returns the number of "smallest units" of this monetary value. For Bitcoin, this would be the number of satoshis.
*/
long getValue();
int signum();
}

View File

@@ -1,366 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.params.*;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptOpCodes;
import com.google.common.base.Objects;
import javax.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.*;
import static org.bitcoinj.core.Coin.*;
/**
* <p>NetworkParameters contains the data needed for working with an instantiation of a Bitcoin chain.</p>
*
* <p>This is an abstract class, concrete instantiations can be found in the params package. There are four:
* one for the main network ({@link MainNetParams}), one for the public test network, and two others that are
* intended for unit testing and local app development purposes. Although this class contains some aliases for
* them, you are encouraged to call the static get() methods on each specific params class directly.</p>
*/
public abstract class NetworkParameters implements Serializable {
/**
* The protocol version this library implements.
*/
public static final int PROTOCOL_VERSION = 70001;
/**
* The alert signing key originally owned by Satoshi, and now passed on to Gavin along with a few others.
*/
public static final byte[] SATOSHI_KEY = Utils.HEX.decode("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284");
/** The string returned by getId() for the main, production network where people trade things. */
public static final String ID_MAINNET = "org.bitcoin.production";
/** The string returned by getId() for the testnet. */
public static final String ID_TESTNET = "org.bitcoin.test";
/** The string returned by getId() for regtest mode. */
public static final String ID_REGTEST = "org.bitcoin.regtest";
/** Unit test network. */
public static final String ID_UNITTESTNET = "org.bitcoinj.unittest";
/** The string used by the payment protocol to represent the main net. */
public static final String PAYMENT_PROTOCOL_ID_MAINNET = "main";
/** The string used by the payment protocol to represent the test net. */
public static final String PAYMENT_PROTOCOL_ID_TESTNET = "test";
/** The string used by the payment protocol to represent unit testing (note that this is non-standard). */
public static final String PAYMENT_PROTOCOL_ID_UNIT_TESTS = "unittest";
public static final String PAYMENT_PROTOCOL_ID_REGTEST = "regtest";
// TODO: Seed nodes should be here as well.
protected Block genesisBlock;
protected BigInteger maxTarget;
protected int port;
protected long packetMagic; // Indicates message origin network and is used to seek to the next message when stream state is unknown.
protected int addressHeader;
protected int p2shHeader;
protected int dumpedPrivateKeyHeader;
protected int interval;
protected int targetTimespan;
protected byte[] alertSigningKey;
protected int bip32HeaderPub;
protected int bip32HeaderPriv;
/**
* See getId(). This may be null for old deserialized wallets. In that case we derive it heuristically
* by looking at the port number.
*/
protected String id;
/**
* The depth of blocks required for a coinbase transaction to be spendable.
*/
protected int spendableCoinbaseDepth;
protected int subsidyDecreaseBlockCount;
protected int[] acceptableAddressCodes;
protected String[] dnsSeeds;
protected Map<Integer, Sha256Hash> checkpoints = new HashMap<Integer, Sha256Hash>();
protected NetworkParameters() {
alertSigningKey = SATOSHI_KEY;
genesisBlock = createGenesis(this);
}
private static Block createGenesis(NetworkParameters n) {
Block genesisBlock = new Block(n);
Transaction t = new Transaction(n);
try {
// A script containing the difficulty bits and the following message:
//
// "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
byte[] bytes = Utils.HEX.decode
("04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73");
t.addInput(new TransactionInput(n, t, bytes));
ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream();
Script.writeBytes(scriptPubKeyBytes, Utils.HEX.decode
("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
scriptPubKeyBytes.write(ScriptOpCodes.OP_CHECKSIG);
t.addOutput(new TransactionOutput(n, t, FIFTY_COINS, scriptPubKeyBytes.toByteArray()));
} catch (Exception e) {
// Cannot happen.
throw new RuntimeException(e);
}
genesisBlock.addTransaction(t);
return genesisBlock;
}
public static final int TARGET_TIMESPAN = 14 * 24 * 60 * 60; // 2 weeks per difficulty cycle, on average.
public static final int TARGET_SPACING = 10 * 60; // 10 minutes per block.
public static final int INTERVAL = TARGET_TIMESPAN / TARGET_SPACING;
/**
* Blocks with a timestamp after this should enforce BIP 16, aka "Pay to script hash". This BIP changed the
* network rules in a soft-forking manner, that is, blocks that don't follow the rules are accepted but not
* mined upon and thus will be quickly re-orged out as long as the majority are enforcing the rule.
*/
public static final int BIP16_ENFORCE_TIME = 1333238400;
/**
* The maximum number of coins to be generated
*/
public static final long MAX_COINS = 21000000;
/**
* The maximum money to be generated
*/
public static final Coin MAX_MONEY = COIN.multiply(MAX_COINS);
/** Alias for TestNet3Params.get(), use that instead. */
@Deprecated
public static NetworkParameters testNet() {
return TestNet3Params.get();
}
/** Alias for TestNet2Params.get(), use that instead. */
@Deprecated
public static NetworkParameters testNet2() {
return TestNet2Params.get();
}
/** Alias for TestNet3Params.get(), use that instead. */
@Deprecated
public static NetworkParameters testNet3() {
return TestNet3Params.get();
}
/** Alias for MainNetParams.get(), use that instead */
@Deprecated
public static NetworkParameters prodNet() {
return MainNetParams.get();
}
/** Returns a testnet params modified to allow any difficulty target. */
@Deprecated
public static NetworkParameters unitTests() {
return UnitTestParams.get();
}
/** Returns a standard regression test params (similar to unitTests) */
@Deprecated
public static NetworkParameters regTests() {
return RegTestParams.get();
}
/**
* A Java package style string acting as unique ID for these parameters
*/
public String getId() {
return id;
}
public abstract String getPaymentProtocolId();
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NetworkParameters other = (NetworkParameters) o;
return getId().equals(other.getId());
}
@Override
public int hashCode() {
return Objects.hashCode(getId());
}
/** Returns the network parameters for the given string ID or NULL if not recognized. */
@Nullable
public static NetworkParameters fromID(String id) {
if (id.equals(ID_MAINNET)) {
return MainNetParams.get();
} else if (id.equals(ID_TESTNET)) {
return TestNet3Params.get();
} else if (id.equals(ID_UNITTESTNET)) {
return UnitTestParams.get();
} else if (id.equals(ID_REGTEST)) {
return RegTestParams.get();
} else {
return null;
}
}
/** Returns the network parameters for the given string paymentProtocolID or NULL if not recognized. */
@Nullable
public static NetworkParameters fromPmtProtocolID(String pmtProtocolId) {
if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_MAINNET)) {
return MainNetParams.get();
} else if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_TESTNET)) {
return TestNet3Params.get();
} else if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_UNIT_TESTS)) {
return UnitTestParams.get();
} else if (pmtProtocolId.equals(PAYMENT_PROTOCOL_ID_REGTEST)) {
return RegTestParams.get();
} else {
return null;
}
}
public int getSpendableCoinbaseDepth() {
return spendableCoinbaseDepth;
}
/**
* Returns true if the block height is either not a checkpoint, or is a checkpoint and the hash matches.
*/
public boolean passesCheckpoint(int height, Sha256Hash hash) {
Sha256Hash checkpointHash = checkpoints.get(height);
return checkpointHash == null || checkpointHash.equals(hash);
}
/**
* Returns true if the given height has a recorded checkpoint.
*/
public boolean isCheckpoint(int height) {
Sha256Hash checkpointHash = checkpoints.get(height);
return checkpointHash != null;
}
public int getSubsidyDecreaseBlockCount() {
return subsidyDecreaseBlockCount;
}
/** Returns DNS names that when resolved, give IP addresses of active peers. */
public String[] getDnsSeeds() {
return dnsSeeds;
}
/**
* <p>Genesis block for this chain.</p>
*
* <p>The first block in every chain is a well known constant shared between all Bitcoin implemenetations. For a
* block to be valid, it must be eventually possible to work backwards to the genesis block by following the
* prevBlockHash pointers in the block headers.</p>
*
* <p>The genesis blocks for both test and main networks contain the timestamp of when they were created,
* and a message in the coinbase transaction. It says, <i>"The Times 03/Jan/2009 Chancellor on brink of second
* bailout for banks"</i>.</p>
*/
public Block getGenesisBlock() {
return genesisBlock;
}
/** Default TCP port on which to connect to nodes. */
public int getPort() {
return port;
}
/** The header bytes that identify the start of a packet on this network. */
public long getPacketMagic() {
return packetMagic;
}
/**
* First byte of a base58 encoded address. See {@link org.bitcoinj.core.Address}. This is the same as acceptableAddressCodes[0] and
* is the one used for "normal" addresses. Other types of address may be encountered with version codes found in
* the acceptableAddressCodes array.
*/
public int getAddressHeader() {
return addressHeader;
}
/**
* First byte of a base58 encoded P2SH address. P2SH addresses are defined as part of BIP0013.
*/
public int getP2SHHeader() {
return p2shHeader;
}
/** First byte of a base58 encoded dumped private key. See {@link org.bitcoinj.core.DumpedPrivateKey}. */
public int getDumpedPrivateKeyHeader() {
return dumpedPrivateKeyHeader;
}
/**
* How much time in seconds is supposed to pass between "interval" blocks. If the actual elapsed time is
* significantly different from this value, the network difficulty formula will produce a different value. Both
* test and main Bitcoin networks use 2 weeks (1209600 seconds).
*/
public int getTargetTimespan() {
return targetTimespan;
}
/**
* The version codes that prefix addresses which are acceptable on this network. Although Satoshi intended these to
* be used for "versioning", in fact they are today used to discriminate what kind of data is contained in the
* address and to prevent accidentally sending coins across chains which would destroy them.
*/
public int[] getAcceptableAddressCodes() {
return acceptableAddressCodes;
}
/**
* If we are running in testnet-in-a-box mode, we allow connections to nodes with 0 non-genesis blocks.
*/
public boolean allowEmptyPeerChain() {
return true;
}
/** How many blocks pass between difficulty adjustment periods. Bitcoin standardises this to be 2015. */
public int getInterval() {
return interval;
}
/** Maximum target represents the easiest allowable proof of work. */
public BigInteger getMaxTarget() {
return maxTarget;
}
/**
* The key used to sign {@link org.bitcoinj.core.AlertMessage}s. You can use {@link org.bitcoinj.core.ECKey#verify(byte[], byte[], byte[])} to verify
* signatures using it.
*/
public byte[] getAlertSigningKey() {
return alertSigningKey;
}
/** Returns the 4 byte header for BIP32 (HD) wallet - public key part. */
public int getBip32HeaderPub() {
return bip32HeaderPub;
}
/** Returns the 4 byte header for BIP32 (HD) wallet - private key part. */
public int getBip32HeaderPriv() {
return bip32HeaderPriv;
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.util.ArrayList;
import java.util.List;
/**
* Sent by a peer when a getdata request doesn't find the requested data in the mempool. It has the same format
* as an inventory message and lists the hashes of the missing items.
*/
public class NotFoundMessage extends InventoryMessage {
public static int MIN_PROTOCOL_VERSION = 70001;
public NotFoundMessage(NetworkParameters params) {
super(params);
}
public NotFoundMessage(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes);
}
public NotFoundMessage(NetworkParameters params, List<InventoryItem> items) {
super(params);
this.items = new ArrayList<InventoryItem>(items);
}
}

View File

@@ -1,298 +0,0 @@
/**
* Copyright 2012 The Bitcoin Developers
* Copyright 2012 Matt Corallo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.bitcoinj.core.Utils.*;
/**
* <p>A data structure that contains proofs of block inclusion for one or more transactions, in an efficient manner.</p>
*
* <p>The encoding works as follows: we traverse the tree in depth-first order, storing a bit for each traversed node,
* signifying whether the node is the parent of at least one matched leaf txid (or a matched txid itself). In case we
* are at the leaf level, or this bit is 0, its merkle node hash is stored, and its children are not explored further.
* Otherwise, no hash is stored, but we recurse into both (or the only) child branch. During decoding, the same
* depth-first traversal is performed, consuming bits and hashes as they were written during encoding.</p>
*
* <p>The serialization is fixed and provides a hard guarantee about the encoded size,
* <tt>SIZE <= 10 + ceil(32.25*N)</tt> where N represents the number of leaf nodes of the partial tree. N itself
* is bounded by:</p>
*
* <p>
* N <= total_transactions<br>
* N <= 1 + matched_transactions*tree_height
* </p>
*
* <p><pre>The serialization format:
* - uint32 total_transactions (4 bytes)
* - varint number of hashes (1-3 bytes)
* - uint256[] hashes in depth-first order (<= 32*N bytes)
* - varint number of bytes of flag bits (1-3 bytes)
* - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits)
* The size constraints follow from this.</pre></p>
*/
public class PartialMerkleTree extends Message {
// the total number of transactions in the block
private int transactionCount;
// node-is-parent-of-matched-txid bits
private byte[] matchedChildBits;
// txids and internal hashes
private List<Sha256Hash> hashes;
public PartialMerkleTree(NetworkParameters params, byte[] payloadBytes, int offset) throws ProtocolException {
super(params, payloadBytes, offset);
}
/**
* Constructs a new PMT with the given bit set (little endian) and the raw list of hashes including internal hashes,
* taking ownership of the list.
*/
public PartialMerkleTree(NetworkParameters params, byte[] bits, List<Sha256Hash> hashes, int origTxCount) {
super(params);
this.matchedChildBits = bits;
this.hashes = hashes;
this.transactionCount = origTxCount;
}
/**
* Calculates a PMT given the list of leaf hashes and which leaves need to be included. The relevant interior hashes
* are calculated and a new PMT returned.
*/
public static PartialMerkleTree buildFromLeaves(NetworkParameters params, byte[] includeBits, List<Sha256Hash> allLeafHashes) {
// Calculate height of the tree.
int height = 0;
while (getTreeWidth(allLeafHashes.size(), height) > 1)
height++;
List<Boolean> bitList = new ArrayList<Boolean>();
List<Sha256Hash> hashes = new ArrayList<Sha256Hash>();
traverseAndBuild(height, 0, allLeafHashes, includeBits, bitList, hashes);
byte[] bits = new byte[(int)Math.ceil(bitList.size() / 8.0)];
for (int i = 0; i < bitList.size(); i++)
if (bitList.get(i))
Utils.setBitLE(bits, i);
return new PartialMerkleTree(params, bits, hashes, allLeafHashes.size());
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
uint32ToByteStreamLE(transactionCount, stream);
stream.write(new VarInt(hashes.size()).encode());
for (Sha256Hash hash : hashes)
stream.write(reverseBytes(hash.getBytes()));
stream.write(new VarInt(matchedChildBits.length).encode());
stream.write(matchedChildBits);
}
@Override
void parse() throws ProtocolException {
transactionCount = (int)readUint32();
int nHashes = (int) readVarInt();
hashes = new ArrayList<Sha256Hash>(nHashes);
for (int i = 0; i < nHashes; i++)
hashes.add(readHash());
int nFlagBytes = (int) readVarInt();
matchedChildBits = readBytes(nFlagBytes);
length = cursor - offset;
}
// Based on CPartialMerkleTree::TraverseAndBuild in Bitcoin Core.
private static void traverseAndBuild(int height, int pos, List<Sha256Hash> allLeafHashes, byte[] includeBits,
List<Boolean> matchedChildBits, List<Sha256Hash> resultHashes) {
boolean parentOfMatch = false;
// Is this node a parent of at least one matched hash?
for (int p = pos << height; p < (pos+1) << height && p < allLeafHashes.size(); p++) {
if (Utils.checkBitLE(includeBits, p)) {
parentOfMatch = true;
break;
}
}
// Store as a flag bit.
matchedChildBits.add(parentOfMatch);
if (height == 0 || !parentOfMatch) {
// If at height 0, or nothing interesting below, store hash and stop.
resultHashes.add(calcHash(height, pos, allLeafHashes));
} else {
// Otherwise descend into the subtrees.
int h = height - 1;
int p = pos * 2;
traverseAndBuild(h, p, allLeafHashes, includeBits, matchedChildBits, resultHashes);
if (p + 1 < getTreeWidth(allLeafHashes.size(), h))
traverseAndBuild(h, p + 1, allLeafHashes, includeBits, matchedChildBits, resultHashes);
}
}
private static Sha256Hash calcHash(int height, int pos, List<Sha256Hash> hashes) {
if (height == 0) {
// Hash at height 0 is just the regular tx hash itself.
return hashes.get(pos);
}
int h = height - 1;
int p = pos * 2;
Sha256Hash left = calcHash(h, p, hashes);
// Calculate right hash if not beyond the end of the array - copy left hash otherwise.
Sha256Hash right;
if (p + 1 < getTreeWidth(hashes.size(), h)) {
right = calcHash(h, p + 1, hashes);
} else {
right = left;
}
return combineLeftRight(left.getBytes(), right.getBytes());
}
@Override
protected void parseLite() {
}
// helper function to efficiently calculate the number of nodes at given height in the merkle tree
private static int getTreeWidth(int transactionCount, int height) {
return (transactionCount + (1 << height) - 1) >> height;
}
private static class ValuesUsed {
public int bitsUsed = 0, hashesUsed = 0;
}
// recursive function that traverses tree nodes, consuming the bits and hashes produced by TraverseAndBuild.
// it returns the hash of the respective node.
private Sha256Hash recursiveExtractHashes(int height, int pos, ValuesUsed used, List<Sha256Hash> matchedHashes) throws VerificationException {
if (used.bitsUsed >= matchedChildBits.length*8) {
// overflowed the bits array - failure
throw new VerificationException("PartialMerkleTree overflowed its bits array");
}
boolean parentOfMatch = checkBitLE(matchedChildBits, used.bitsUsed++);
if (height == 0 || !parentOfMatch) {
// if at height 0, or nothing interesting below, use stored hash and do not descend
if (used.hashesUsed >= hashes.size()) {
// overflowed the hash array - failure
throw new VerificationException("PartialMerkleTree overflowed its hash array");
}
Sha256Hash hash = hashes.get(used.hashesUsed++);
if (height == 0 && parentOfMatch) // in case of height 0, we have a matched txid
matchedHashes.add(hash);
return hash;
} else {
// otherwise, descend into the subtrees to extract matched txids and hashes
byte[] left = recursiveExtractHashes(height - 1, pos * 2, used, matchedHashes).getBytes(), right;
if (pos * 2 + 1 < getTreeWidth(transactionCount, height-1)) {
right = recursiveExtractHashes(height - 1, pos * 2 + 1, used, matchedHashes).getBytes();
if (Arrays.equals(right, left))
throw new VerificationException("Invalid merkle tree with duplicated left/right branches");
} else {
right = left;
}
// and combine them before returning
return combineLeftRight(left, right);
}
}
private static Sha256Hash combineLeftRight(byte[] left, byte[] right) {
return new Sha256Hash(reverseBytes(doubleDigestTwoBuffers(
reverseBytes(left), 0, 32,
reverseBytes(right), 0, 32)));
}
/**
* Extracts tx hashes that are in this merkle tree
* and returns the merkle root of this tree.
*
* The returned root should be checked against the
* merkle root contained in the block header for security.
*
* @param matchedHashesOut A list which will contain the matched txn (will be cleared).
* @return the merkle root of this merkle tree
* @throws ProtocolException if this partial merkle tree is invalid
*/
public Sha256Hash getTxnHashAndMerkleRoot(List<Sha256Hash> matchedHashesOut) throws VerificationException {
matchedHashesOut.clear();
// An empty set will not work
if (transactionCount == 0)
throw new VerificationException("Got a CPartialMerkleTree with 0 transactions");
// check for excessively high numbers of transactions
if (transactionCount > Block.MAX_BLOCK_SIZE / 60) // 60 is the lower bound for the size of a serialized CTransaction
throw new VerificationException("Got a CPartialMerkleTree with more transactions than is possible");
// there can never be more hashes provided than one for every txid
if (hashes.size() > transactionCount)
throw new VerificationException("Got a CPartialMerkleTree with more hashes than transactions");
// there must be at least one bit per node in the partial tree, and at least one node per hash
if (matchedChildBits.length*8 < hashes.size())
throw new VerificationException("Got a CPartialMerkleTree with fewer matched bits than hashes");
// calculate height of tree
int height = 0;
while (getTreeWidth(transactionCount, height) > 1)
height++;
// traverse the partial tree
ValuesUsed used = new ValuesUsed();
Sha256Hash merkleRoot = recursiveExtractHashes(height, 0, used, matchedHashesOut);
// verify that all bits were consumed (except for the padding caused by serializing it as a byte sequence)
if ((used.bitsUsed+7)/8 != matchedChildBits.length ||
// verify that all hashes were consumed
used.hashesUsed != hashes.size())
throw new VerificationException("Got a CPartialMerkleTree that didn't need all the data it provided");
return merkleRoot;
}
public int getTransactionCount() {
return transactionCount;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PartialMerkleTree tree = (PartialMerkleTree) o;
if (transactionCount != tree.transactionCount) return false;
if (!hashes.equals(tree.hashes)) return false;
if (!Arrays.equals(matchedChildBits, tree.matchedChildBits)) return false;
return true;
}
@Override
public int hashCode() {
int result = transactionCount;
result = 31 * result + Arrays.hashCode(matchedChildBits);
result = 31 * result + hashes.hashCode();
return result;
}
@Override
public String toString() {
return "PartialMerkleTree{" +
"transactionCount=" + transactionCount +
", matchedChildBits=" + Arrays.toString(matchedChildBits) +
", hashes=" + hashes +
'}';
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,241 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.params.MainNetParams;
import com.google.common.net.InetAddresses;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import static org.bitcoinj.core.Utils.uint32ToByteStreamLE;
import static org.bitcoinj.core.Utils.uint64ToByteStreamLE;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A PeerAddress holds an IP address and port number representing the network location of
* a peer in the Bitcoin P2P network. It exists primarily for serialization purposes.
*/
public class PeerAddress extends ChildMessage {
private static final long serialVersionUID = 7501293709324197411L;
static final int MESSAGE_SIZE = 30;
private InetAddress addr;
private int port;
private BigInteger services;
private long time;
/**
* Construct a peer address from a serialized payload.
*/
public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException {
super(params, payload, offset, protocolVersion);
}
/**
* Construct a peer address from a serialized payload.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param protocolVersion Bitcoin protocol version.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @throws ProtocolException
*/
public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion, Message parent, boolean parseLazy,
boolean parseRetain) throws ProtocolException {
super(params, payload, offset, protocolVersion, parent, parseLazy, parseRetain, UNKNOWN_LENGTH);
// Message length is calculated in parseLite which is guaranteed to be called before it is ever read.
// Even though message length is static for a PeerAddress it is safer to leave it there
// as it will be set regardless of which constructor was used.
}
/**
* Construct a peer address from a memorized or hardcoded address.
*/
public PeerAddress(InetAddress addr, int port, int protocolVersion) {
this.addr = checkNotNull(addr);
this.port = port;
this.protocolVersion = protocolVersion;
this.services = BigInteger.ZERO;
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
}
/**
* Constructs a peer address from the given IP address and port. Protocol version is the default.
*/
public PeerAddress(InetAddress addr, int port) {
this(addr, port, NetworkParameters.PROTOCOL_VERSION);
}
/**
* Constructs a peer address from the given IP address. Port and protocol version are default for the mainnet.
*/
public PeerAddress(InetAddress addr) {
this(addr, MainNetParams.get().getPort());
}
public PeerAddress(InetSocketAddress addr) {
this(addr.getAddress(), addr.getPort());
}
public static PeerAddress localhost(NetworkParameters params) {
return new PeerAddress(InetAddresses.forString("127.0.0.1"), params.getPort());
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (protocolVersion >= 31402) {
//TODO this appears to be dynamic because the client only ever sends out it's own address
//so assumes itself to be up. For a fuller implementation this needs to be dynamic only if
//the address refers to this client.
int secs = (int) (Utils.currentTimeSeconds());
uint32ToByteStreamLE(secs, stream);
}
uint64ToByteStreamLE(services, stream); // nServices.
// Java does not provide any utility to map an IPv4 address into IPv6 space, so we have to do it by hand.
byte[] ipBytes = addr.getAddress();
if (ipBytes.length == 4) {
byte[] v6addr = new byte[16];
System.arraycopy(ipBytes, 0, v6addr, 12, 4);
v6addr[10] = (byte) 0xFF;
v6addr[11] = (byte) 0xFF;
ipBytes = v6addr;
}
stream.write(ipBytes);
// And write out the port. Unlike the rest of the protocol, address and port is in big endian byte order.
stream.write((byte) (0xFF & port >> 8));
stream.write((byte) (0xFF & port));
}
@Override
protected void parseLite() {
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
}
@Override
protected void parse() throws ProtocolException {
// Format of a serialized address:
// uint32 timestamp
// uint64 services (flags determining what the node can do)
// 16 bytes ip address
// 2 bytes port num
if (protocolVersion > 31402)
time = readUint32();
else
time = -1;
services = readUint64();
byte[] addrBytes = readBytes(16);
try {
addr = InetAddress.getByAddress(addrBytes);
} catch (UnknownHostException e) {
throw new RuntimeException(e); // Cannot happen.
}
port = ((0xFF & payload[cursor++]) << 8) | (0xFF & payload[cursor++]);
}
@Override
public int getMessageSize() {
// The 4 byte difference is the uint32 timestamp that was introduced in version 31402
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
return length;
}
public InetAddress getAddr() {
maybeParse();
return addr;
}
public InetSocketAddress getSocketAddress() {
return new InetSocketAddress(getAddr(), getPort());
}
public void setAddr(InetAddress addr) {
unCache();
this.addr = addr;
}
public int getPort() {
maybeParse();
return port;
}
public void setPort(int port) {
unCache();
this.port = port;
}
public BigInteger getServices() {
maybeParse();
return services;
}
public void setServices(BigInteger services) {
unCache();
this.services = services;
}
public long getTime() {
maybeParse();
return time;
}
public void setTime(long time) {
unCache();
this.time = time;
}
@Override
public String toString() {
return "[" + addr.getHostAddress() + "]:" + port;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PeerAddress other = (PeerAddress) o;
return other.addr.equals(addr) &&
other.port == port &&
other.services.equals(services) &&
other.time == time;
//TODO: including services and time could cause same peer to be added multiple times in collections
}
@Override
public int hashCode() {
return addr.hashCode() ^ port ^ (int) time ^ services.hashCode();
}
public InetSocketAddress toSocketAddress() {
return new InetSocketAddress(addr, port);
}
}

View File

@@ -1,101 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Set;
/**
* <p>Implementors can listen to events like blocks being downloaded/transactions being broadcast/connect/disconnects,
* they can pre-filter messages before they are procesesed by a {@link Peer} or {@link PeerGroup}, and they can
* provide transactions to remote peers when they ask for them.</p>
*/
public interface PeerEventListener {
/**
* <p>Called when peers are discovered, this happens at startup of {@link PeerGroup} or if we run out of
* suitable {@link Peer}s to connect to.</p>
*
* @param peerAddresses the set of discovered {@link PeerAddress}es
*/
public void onPeersDiscovered(Set<PeerAddress> peerAddresses);
/**
* Called on a Peer thread when a block is received.<p>
*
* The block may have transactions or may be a header only once getheaders is implemented.
*
* @param peer the peer receiving the block
* @param block the downloaded block
* @param blocksLeft the number of blocks left to download
*/
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft);
/**
* Called when a download is started with the initial number of blocks to be downloaded.
*
* @param peer the peer receiving the block
* @param blocksLeft the number of blocks left to download
*/
public void onChainDownloadStarted(Peer peer, int blocksLeft);
/**
* Called when a peer is connected. If this listener is registered to a {@link Peer} instead of a {@link PeerGroup},
* peerCount will always be 1.
*
* @param peer
* @param peerCount the total number of connected peers
*/
public void onPeerConnected(Peer peer, int peerCount);
/**
* Called when a peer is disconnected. Note that this won't be called if the listener is registered on a
* {@link PeerGroup} and the group is in the process of shutting down. If this listener is registered to a
* {@link Peer} instead of a {@link PeerGroup}, peerCount will always be 0. This handler can be called without
* a corresponding invocation of onPeerConnected if the initial connection is never successful.
*
* @param peer
* @param peerCount the total number of connected peers
*/
public void onPeerDisconnected(Peer peer, int peerCount);
/**
* <p>Called when a message is received by a peer, before the message is processed. The returned message is
* processed instead. Returning null will cause the message to be ignored by the Peer returning the same message
* object allows you to see the messages received but not change them. The result from one event listeners
* callback is passed as "m" to the next, forming a chain.</p>
*
* <p>Note that this will never be called if registered with any executor other than
* {@link org.bitcoinj.utils.Threading#SAME_THREAD}</p>
*/
public Message onPreMessageReceived(Peer peer, Message m);
/**
* Called when a new transaction is broadcast over the network.
*/
public void onTransaction(Peer peer, Transaction t);
/**
* <p>Called when a peer receives a getdata message, usually in response to an "inv" being broadcast. Return as many
* items as possible which appear in the {@link GetDataMessage}, or null if you're not interested in responding.</p>
*
* <p>Note that this will never be called if registered with any executor other than
* {@link org.bitcoinj.utils.Threading#SAME_THREAD}</p>
*/
@Nullable
public List<Message> getData(Peer peer, GetDataMessage m);
}

View File

@@ -1,60 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.util.concurrent.locks.Lock;
/**
* An interface which provides the information required to properly filter data downloaded from Peers.
* Note that an implementer is responsible for calling {@link PeerGroup#recalculateFastCatchupAndFilter(org.bitcoinj.core.PeerGroup.FilterRecalculateMode)}
* whenever a change occurs which effects the data provided via this interface.
*/
public interface PeerFilterProvider {
/**
* Returns the earliest timestamp (seconds since epoch) for which full/bloom-filtered blocks must be downloaded.
* Blocks with timestamps before this time will only have headers downloaded. 0 requires that all blocks be
* downloaded, and thus this should default to {@link System#currentTimeMillis()}/1000.
*/
public long getEarliestKeyCreationTime();
/**
* Called on all registered filter providers before getBloomFilterElementCount and getBloomFilter are called.
* Once called, the provider should ensure that the items it will want to insert into the filter don't change.
* The reason is that all providers will have their element counts queried, and then a filter big enough for
* all of them will be specified. So the provider must use consistent state. There is guaranteed to be a matching
* call to endBloomFilterCalculation that can be used to e.g. unlock a lock.
*/
public void beginBloomFilterCalculation();
/**
* Gets the number of elements that will be added to a bloom filter returned by
* {@link PeerFilterProvider#getBloomFilter(int, double, long)}
*/
public int getBloomFilterElementCount();
/**
* Gets a bloom filter that contains all the necessary elements for the listener to receive relevant transactions.
* Default value should be an empty bloom filter with the given size, falsePositiveRate, and nTweak.
*/
public BloomFilter getBloomFilter(int size, double falsePositiveRate, long nTweak);
/** Whether this filter provider depends on the server updating the filter on all matches */
public boolean isRequiringUpdateAllBloomFilter();
public void endBloomFilterCalculation();
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,235 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.net.AbstractTimeoutHandler;
import org.bitcoinj.net.MessageWriteTarget;
import org.bitcoinj.net.StreamParser;
import org.bitcoinj.utils.Threading;
import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.channels.NotYetConnectedException;
import java.util.concurrent.locks.Lock;
import static com.google.common.base.Preconditions.*;
/**
* Handles high-level message (de)serialization for peers, acting as the bridge between the
* {@link org.bitcoinj.net} classes and {@link Peer}.
*/
public abstract class PeerSocketHandler extends AbstractTimeoutHandler implements StreamParser {
private static final Logger log = LoggerFactory.getLogger(PeerSocketHandler.class);
private final BitcoinSerializer serializer;
protected PeerAddress peerAddress;
// If we close() before we know our writeTarget, set this to true to call writeTarget.closeConnection() right away.
private boolean closePending = false;
// writeTarget will be thread-safe, and may call into PeerGroup, which calls us, so we should call it unlocked
@VisibleForTesting protected MessageWriteTarget writeTarget = null;
// The ByteBuffers passed to us from the writeTarget are static in size, and usually smaller than some messages we
// will receive. For SPV clients, this should be rare (ie we're mostly dealing with small transactions), but for
// messages which are larger than the read buffer, we have to keep a temporary buffer with its bytes.
private byte[] largeReadBuffer;
private int largeReadBufferPos;
private BitcoinSerializer.BitcoinPacketHeader header;
private Lock lock = Threading.lock("PeerSocketHandler");
public PeerSocketHandler(NetworkParameters params, InetSocketAddress remoteIp) {
serializer = new BitcoinSerializer(checkNotNull(params));
this.peerAddress = new PeerAddress(remoteIp);
}
public PeerSocketHandler(NetworkParameters params, PeerAddress peerAddress) {
serializer = new BitcoinSerializer(checkNotNull(params));
this.peerAddress = checkNotNull(peerAddress);
}
/**
* Sends the given message to the peer. Due to the asynchronousness of network programming, there is no guarantee
* the peer will have received it. Throws NotYetConnectedException if we are not yet connected to the remote peer.
* TODO: Maybe use something other than the unchecked NotYetConnectedException here
*/
public void sendMessage(Message message) throws NotYetConnectedException {
lock.lock();
try {
if (writeTarget == null)
throw new NotYetConnectedException();
} finally {
lock.unlock();
}
// TODO: Some round-tripping could be avoided here
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
serializer.serialize(message, out);
writeTarget.writeBytes(out.toByteArray());
} catch (IOException e) {
exceptionCaught(e);
}
}
/**
* Closes the connection to the peer if one exists, or immediately closes the connection as soon as it opens
*/
public void close() {
lock.lock();
try {
if (writeTarget == null) {
closePending = true;
return;
}
} finally {
lock.unlock();
}
writeTarget.closeConnection();
}
@Override
protected void timeoutOccurred() {
log.info("{}: Timed out", getAddress());
close();
}
/**
* Called every time a message is received from the network
*/
protected abstract void processMessage(Message m) throws Exception;
@Override
public int receiveBytes(ByteBuffer buff) {
checkArgument(buff.position() == 0 &&
buff.capacity() >= BitcoinSerializer.BitcoinPacketHeader.HEADER_LENGTH + 4);
try {
// Repeatedly try to deserialize messages until we hit a BufferUnderflowException
for (int i = 0; true; i++) {
// If we are in the middle of reading a message, try to fill that one first, before we expect another
if (largeReadBuffer != null) {
// This can only happen in the first iteration
checkState(i == 0);
// Read new bytes into the largeReadBuffer
int bytesToGet = Math.min(buff.remaining(), largeReadBuffer.length - largeReadBufferPos);
buff.get(largeReadBuffer, largeReadBufferPos, bytesToGet);
largeReadBufferPos += bytesToGet;
// Check the largeReadBuffer's status
if (largeReadBufferPos == largeReadBuffer.length) {
// ...processing a message if one is available
processMessage(serializer.deserializePayload(header, ByteBuffer.wrap(largeReadBuffer)));
largeReadBuffer = null;
header = null;
} else // ...or just returning if we don't have enough bytes yet
return buff.position();
}
// Now try to deserialize any messages left in buff
Message message;
int preSerializePosition = buff.position();
try {
message = serializer.deserialize(buff);
} catch (BufferUnderflowException e) {
// If we went through the whole buffer without a full message, we need to use the largeReadBuffer
if (i == 0 && buff.limit() == buff.capacity()) {
// ...so reposition the buffer to 0 and read the next message header
buff.position(0);
try {
serializer.seekPastMagicBytes(buff);
header = serializer.deserializeHeader(buff);
// Initialize the largeReadBuffer with the next message's size and fill it with any bytes
// left in buff
largeReadBuffer = new byte[header.size];
largeReadBufferPos = buff.remaining();
buff.get(largeReadBuffer, 0, largeReadBufferPos);
} catch (BufferUnderflowException e1) {
// If we went through a whole buffer's worth of bytes without getting a header, give up
// In cases where the buff is just really small, we could create a second largeReadBuffer
// that we use to deserialize the magic+header, but that is rather complicated when the buff
// should probably be at least that big anyway (for efficiency)
throw new ProtocolException("No magic bytes+header after reading " + buff.capacity() + " bytes");
}
} else {
// Reposition the buffer to its original position, which saves us from skipping messages by
// seeking past part of the magic bytes before all of them are in the buffer
buff.position(preSerializePosition);
}
return buff.position();
}
// Process our freshly deserialized message
processMessage(message);
}
} catch (Exception e) {
exceptionCaught(e);
return -1; // Returning -1 also throws an IllegalStateException upstream and kills the connection
}
}
/**
* Sets the {@link MessageWriteTarget} used to write messages to the peer. This should almost never be called, it is
* called automatically by {@link org.bitcoinj.net.NioClient} or
* {@link org.bitcoinj.net.NioClientManager} once the socket finishes initialization.
*/
@Override
public void setWriteTarget(MessageWriteTarget writeTarget) {
checkArgument(writeTarget != null);
lock.lock();
boolean closeNow = false;
try {
checkArgument(this.writeTarget == null);
closeNow = closePending;
this.writeTarget = writeTarget;
} finally {
lock.unlock();
}
if (closeNow)
writeTarget.closeConnection();
}
@Override
public int getMaxMessageSize() {
return Message.MAX_SIZE;
}
/**
* @return the IP address and port of peer.
*/
public PeerAddress getAddress() {
return peerAddress;
}
/** Catch any exceptions, logging them and then closing the channel. */
private void exceptionCaught(Exception e) {
PeerAddress addr = getAddress();
String s = addr == null ? "?" : addr.toString();
if (e instanceof ConnectException || e instanceof IOException) {
// Short message for network errors
log.info(s + " - " + e.getMessage());
} else {
log.warn(s + " - ", e);
Thread.UncaughtExceptionHandler handler = Threading.uncaughtExceptionHandler;
if (handler != null)
handler.uncaughtException(Thread.currentThread(), e);
}
close();
}
}

View File

@@ -1,76 +0,0 @@
/**
* Copyright 2011 Noa Resare
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
public class Ping extends Message {
private long nonce;
private boolean hasNonce;
public Ping(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
/**
* Create a Ping with a nonce value.
* Only use this if the remote node has a protocol version > 60000
*/
public Ping(long nonce) {
this.nonce = nonce;
this.hasNonce = true;
}
/**
* Create a Ping without a nonce value.
* Only use this if the remote node has a protocol version <= 60000
*/
public Ping() {
this.hasNonce = false;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (hasNonce)
Utils.int64ToByteStreamLE(nonce, stream);
}
@Override
void parse() throws ProtocolException {
try {
nonce = readInt64();
hasNonce = true;
} catch(ProtocolException e) {
hasNonce = false;
}
length = hasNonce ? 8 : 0;
}
@Override
protected void parseLite() {
}
public boolean hasNonce() {
return hasNonce;
}
public long getNonce() {
return nonce;
}
}

View File

@@ -1,59 +0,0 @@
/**
* Copyright 2012 Matt Corallo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
public class Pong extends Message {
/** The smallest protocol version that supports the pong response (BIP 31). Anything beyond version 60000. */
public static final int MIN_PROTOCOL_VERSION = 60001;
private long nonce;
public Pong(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
}
/**
* Create a Pong with a nonce value.
* Only use this if the remote node has a protocol version > 60000
*/
public Pong(long nonce) {
this.nonce = nonce;
}
@Override
void parse() throws ProtocolException {
nonce = readInt64();
length = 8;
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
Utils.int64ToByteStreamLE(nonce, stream);
}
@Override
protected void parseLite() {
}
/** Returns the nonce sent by the remote peer. */
public long getNonce() {
return nonce;
}
}

View File

@@ -1,33 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
@SuppressWarnings("serial")
public class ProtocolException extends VerificationException {
public ProtocolException(String msg) {
super(msg);
}
public ProtocolException(Exception e) {
super(e);
}
public ProtocolException(String msg, Exception e) {
super(msg, e);
}
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
// TODO: Rename PrunedException to something like RequiredDataWasPrunedException
/**
* PrunedException is thrown in cases where a fully verifying node has deleted (pruned) old block data that turned
* out to be necessary for handling a re-org. Normally this should never happen unless you're playing with the testnet
* as the pruning parameters should be set very conservatively, such that an absolutely enormous re-org would be
* required to trigger it.
*/
@SuppressWarnings("serial")
public class PrunedException extends Exception {
private Sha256Hash hash;
public PrunedException(Sha256Hash hash) {
super(hash.toString());
this.hash = hash;
}
public Sha256Hash getHash() {
return hash;
}
}

View File

@@ -1,182 +0,0 @@
/**
* Copyright 2013 Matt Corallo
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
/**
* A message sent by nodes when a message we sent was rejected (ie a transaction had too little fee/was invalid/etc)
*/
public class RejectMessage extends Message {
private static final long serialVersionUID = -5246995579800334336L;
private String message, reason;
public static enum RejectCode {
/** The message was not able to be parsed */
MALFORMED((byte) 0x01),
/** The message described an invalid object */
INVALID((byte) 0x10),
/** The message was obsolete or described an object which is obsolete (eg unsupported, old version, v1 block) */
OBSOLETE((byte) 0x11),
/**
* The message was relayed multiple times or described an object which is in conflict with another.
* This message can describe errors in protocol implementation or the presence of an attempt to DOUBLE SPEND.
*/
DUPLICATE((byte) 0x12),
/**
* The message described an object was not standard and was thus not accepted.
* The reference client has a concept of standard transaction forms, which describe scripts and encodings which
* it is willing to relay further. Other transactions are neither relayed nor mined, though they are considered
* valid if they appear in a block.
*/
NONSTANDARD((byte) 0x40),
/**
* This refers to a specific form of NONSTANDARD transactions, which have an output smaller than some constant
* defining them as dust (this is no longer used).
*/
DUST((byte) 0x41),
/** The messages described an object which did not have sufficient fee to be relayed further. */
INSUFFICIENTFEE((byte) 0x42),
/** The message described a block which was invalid according to hard-coded checkpoint blocks. */
CHECKPOINT((byte) 0x43),
OTHER((byte) 0xff);
byte code;
RejectCode(byte code) { this.code = code; }
static RejectCode fromCode(byte code) {
for (RejectCode rejectCode : RejectCode.values())
if (rejectCode.code == code)
return rejectCode;
return OTHER;
}
}
private RejectCode code;
private Sha256Hash messageHash;
public RejectMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0);
}
/** Constructs a reject message that fingers the object with the given hash as rejected for the given reason. */
public RejectMessage(NetworkParameters params, RejectCode code, Sha256Hash hash, String message, String reason) throws ProtocolException {
super(params);
this.code = code;
this.messageHash = hash;
this.message = message;
this.reason = reason;
}
@Override
protected void parseLite() throws ProtocolException {
message = readStr();
code = RejectCode.fromCode(readBytes(1)[0]);
reason = readStr();
if (message.equals("block") || message.equals("tx"))
messageHash = readHash();
length = cursor - offset;
}
@Override
public void parse() throws ProtocolException {
if (length == UNKNOWN_LENGTH)
parseLite();
}
@Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
byte[] messageBytes = message.getBytes("UTF-8");
stream.write(new VarInt(messageBytes.length).encode());
stream.write(messageBytes);
stream.write(code.code);
byte[] reasonBytes = reason.getBytes("UTF-8");
stream.write(new VarInt(reasonBytes.length).encode());
stream.write(reasonBytes);
if (message.equals("block") || message.equals("tx"))
stream.write(Utils.reverseBytes(messageHash.getBytes()));
}
/**
* Provides the type of message which was rejected by the peer.
* Note that this is ENTIRELY UNTRUSTED and should be sanity-checked before it is printed or processed.
*/
public String getRejectedMessage() {
ensureParsed();
return message;
}
/**
* Provides the hash of the rejected object (if getRejectedMessage() is either "tx" or "block"), otherwise null.
*/
public Sha256Hash getRejectedObjectHash() {
ensureParsed();
return messageHash;
}
/**
* The reason code given for why the peer rejected the message.
*/
public RejectCode getReasonCode() {
return code;
}
/**
* The reason message given for rejection.
* Note that this is ENTIRELY UNTRUSTED and should be sanity-checked before it is printed or processed.
*/
public String getReasonString() {
return reason;
}
/**
* A String representation of the relevant details of this reject message.
* Be aware that the value returned by this method includes the value returned by
* {@link #getReasonString() getReasonString}, which is taken from the reject message unchecked.
* Through malice or otherwise, it might contain control characters or other harmful content.
*/
@Override
public String toString() {
Sha256Hash hash = getRejectedObjectHash();
if (hash != null)
return String.format("Reject: %s %s for reason '%s' (%d)", getRejectedMessage(), getRejectedObjectHash(),
getReasonString(), getReasonCode().code);
else
return String.format("Reject: %s for reason '%s' (%d)", getRejectedMessage(),
getReasonString(), getReasonCode().code);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
RejectMessage other = (RejectMessage) o;
return message.equals(other.message) &&
code.equals(other.code) &&
reason.equals(other.reason) &&
messageHash.equals(other.messageHash);
}
@Override
public int hashCode() {
int result = message.hashCode();
result = 31 * result + reason.hashCode();
result = 31 * result + code.hashCode();
result = 31 * result + messageHash.hashCode();
return result;
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2014 Adam Mackler
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
/**
* This exception is used by the TransactionBroadcast class to indicate that a broadcast
* Transaction has been rejected by the network, for example because it violates a
* protocol rule. Note that not all invalid transactions generate a reject message, and
* some peers may never do so.
*/
public class RejectedTransactionException extends Exception {
private Transaction tx;
private RejectMessage rejectMessage;
public RejectedTransactionException(Transaction tx, RejectMessage rejectMessage) {
super(rejectMessage.toString());
this.tx = tx;
this.rejectMessage = rejectMessage;
}
/** Return the original Transaction object whose broadcast was rejected. */
public Transaction getTransaction() { return tx; }
/** Return the RejectMessage object representing the broadcast rejection. */
public RejectMessage getRejectMessage() { return rejectMessage; }
}

View File

@@ -1,29 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
@SuppressWarnings("serial")
public class ScriptException extends VerificationException {
public ScriptException(String msg) {
super(msg);
}
public ScriptException(String msg, Exception e) {
super(msg, e);
}
}

View File

@@ -1,135 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import com.google.common.io.ByteStreams;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkArgument;
/**
* A Sha256Hash just wraps a byte[] so that equals and hashcode work correctly, allowing it to be used as keys in a
* map. It also checks that the length is correct and provides a bit more type safety.
*/
public class Sha256Hash implements Serializable, Comparable<Sha256Hash> {
private byte[] bytes;
public static final Sha256Hash ZERO_HASH = new Sha256Hash(new byte[32]);
/**
* Creates a Sha256Hash by wrapping the given byte array. It must be 32 bytes long. Takes ownership!
*/
public Sha256Hash(byte[] rawHashBytes) {
checkArgument(rawHashBytes.length == 32);
this.bytes = rawHashBytes;
}
/**
* Creates a Sha256Hash by decoding the given hex string. It must be 64 characters long.
*/
public Sha256Hash(String hexString) {
checkArgument(hexString.length() == 64);
this.bytes = Utils.HEX.decode(hexString);
}
/**
* Calculates the (one-time) hash of contents and returns it as a new wrapped hash.
*/
public static Sha256Hash create(byte[] contents) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return new Sha256Hash(digest.digest(contents));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/**
* Calculates the hash of the hash of the contents. This is a standard operation in Bitcoin.
*/
public static Sha256Hash createDouble(byte[] contents) {
return new Sha256Hash(Utils.doubleDigest(contents));
}
/**
* Returns a hash of the given files contents. Reads the file fully into memory before hashing so only use with
* small files.
* @throws IOException
*/
public static Sha256Hash hashFileContents(File f) throws IOException {
FileInputStream in = new FileInputStream(f);
try {
return create(ByteStreams.toByteArray(in));
} finally {
in.close();
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Sha256Hash other = (Sha256Hash) o;
return Arrays.equals(bytes, other.bytes);
}
/**
* Hash code of the byte array as calculated by {@link Arrays#hashCode()}. Note the difference between a SHA256
* secure bytes and the type of quick/dirty bytes used by the Java hashCode method which is designed for use in
* bytes tables.
*/
@Override
public int hashCode() {
// Use the last 4 bytes, not the first 4 which are often zeros in Bitcoin.
return (bytes[31] & 0xFF) | ((bytes[30] & 0xFF) << 8) | ((bytes[29] & 0xFF) << 16) | ((bytes[28] & 0xFF) << 24);
}
@Override
public String toString() {
return Utils.HEX.encode(bytes);
}
/**
* Returns the bytes interpreted as a positive integer.
*/
public BigInteger toBigInteger() {
return new BigInteger(1, bytes);
}
public byte[] getBytes() {
return bytes;
}
public Sha256Hash duplicate() {
return new Sha256Hash(bytes);
}
@Override
public int compareTo(Sha256Hash o) {
int thisCode = this.hashCode();
int oCode = ((Sha256Hash)o).hashCode();
return thisCode > oCode ? 1 : (thisCode == oCode ? 0 : -1);
}
}

View File

@@ -1,153 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.store.BlockStore;
import org.bitcoinj.store.BlockStoreException;
import java.io.*;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import static com.google.common.base.Preconditions.checkState;
/**
* Wraps a {@link Block} object with extra data that can be derived from the block chain but is slow or inconvenient to
* calculate. By storing it alongside the block header we reduce the amount of work required significantly.
* Recalculation is slow because the fields are cumulative - to find the chainWork you have to iterate over every
* block in the chain back to the genesis block, which involves lots of seeking/loading etc. So we just keep a
* running total: it's a disk space vs cpu/io tradeoff.<p>
*
* StoredBlocks are put inside a {@link BlockStore} which saves them to memory or disk.
*/
public class StoredBlock implements Serializable {
private static final long serialVersionUID = -6097565241243701771L;
// A BigInteger representing the total amount of work done so far on this chain. As of May 2011 it takes 8
// bytes to represent this field, so 12 bytes should be plenty for now.
public static final int CHAIN_WORK_BYTES = 12;
public static final byte[] EMPTY_BYTES = new byte[CHAIN_WORK_BYTES];
public static final int COMPACT_SERIALIZED_SIZE = Block.HEADER_SIZE + CHAIN_WORK_BYTES + 4; // for height
private Block header;
private BigInteger chainWork;
private int height;
public StoredBlock(Block header, BigInteger chainWork, int height) {
this.header = header;
this.chainWork = chainWork;
this.height = height;
}
/**
* The block header this object wraps. The referenced block object must not have any transactions in it.
*/
public Block getHeader() {
return header;
}
/**
* The total sum of work done in this block, and all the blocks below it in the chain. Work is a measure of how
* many tries are needed to solve a block. If the target is set to cover 10% of the total hash value space,
* then the work represented by a block is 10.
*/
public BigInteger getChainWork() {
return chainWork;
}
/**
* Position in the chain for this block. The genesis block has a height of zero.
*/
public int getHeight() {
return height;
}
/** Returns true if this objects chainWork is higher than the others. */
public boolean moreWorkThan(StoredBlock other) {
return chainWork.compareTo(other.chainWork) > 0;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StoredBlock other = (StoredBlock) o;
return header.equals(other.header) &&
chainWork.equals(other.chainWork) &&
height == other.height;
}
@Override
public int hashCode() {
// A better hashCode is possible, but this works for now.
return header.hashCode() ^ chainWork.hashCode() ^ height;
}
/**
* Creates a new StoredBlock, calculating the additional fields by adding to the values in this block.
*/
public StoredBlock build(Block block) throws VerificationException {
// Stored blocks track total work done in this chain, because the canonical chain is the one that represents
// the largest amount of work done not the tallest.
BigInteger chainWork = this.chainWork.add(block.getWork());
int height = this.height + 1;
return new StoredBlock(block, chainWork, height);
}
/**
* Given a block store, looks up the previous block in this chain. Convenience method for doing
* <tt>store.get(this.getHeader().getPrevBlockHash())</tt>.
*
* @return the previous block in the chain or null if it was not found in the store.
*/
public StoredBlock getPrev(BlockStore store) throws BlockStoreException {
return store.get(getHeader().getPrevBlockHash());
}
/** Serializes the stored block to a custom packed format. Used by {@link CheckpointManager}. */
public void serializeCompact(ByteBuffer buffer) {
byte[] chainWorkBytes = getChainWork().toByteArray();
checkState(chainWorkBytes.length <= CHAIN_WORK_BYTES, "Ran out of space to store chain work!");
if (chainWorkBytes.length < CHAIN_WORK_BYTES) {
// Pad to the right size.
buffer.put(EMPTY_BYTES, 0, CHAIN_WORK_BYTES - chainWorkBytes.length);
}
buffer.put(chainWorkBytes);
buffer.putInt(getHeight());
// Using unsafeBitcoinSerialize here can give us direct access to the same bytes we read off the wire,
// avoiding serialization round-trips.
byte[] bytes = getHeader().unsafeBitcoinSerialize();
buffer.put(bytes, 0, Block.HEADER_SIZE); // Trim the trailing 00 byte (zero transactions).
}
/** De-serializes the stored block from a custom packed format. Used by {@link CheckpointManager}. */
public static StoredBlock deserializeCompact(NetworkParameters params, ByteBuffer buffer) throws ProtocolException {
byte[] chainWorkBytes = new byte[StoredBlock.CHAIN_WORK_BYTES];
buffer.get(chainWorkBytes);
BigInteger chainWork = new BigInteger(1, chainWorkBytes);
int height = buffer.getInt(); // +4 bytes
byte[] header = new byte[Block.HEADER_SIZE + 1]; // Extra byte for the 00 transactions length.
buffer.get(header, 0, Block.HEADER_SIZE);
return new StoredBlock(new Block(params, header), chainWork, height);
}
@Override
public String toString() {
return String.format("Block %s at height %d: %s",
getHeader().getHashAsString(), getHeight(), getHeader().toString());
}
}

View File

@@ -1,91 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2012 Matt Corallo.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.Serializable;
import java.util.List;
/**
* Contains minimal data neccessary to disconnect/connect the transactions
* in the stored block at will. Can either store the full set of
* transactions (if the inputs for the block have not been tested to work)
* or the set of transaction outputs created/destroyed when the block is
* connected.
*/
public class StoredUndoableBlock implements Serializable {
private static final long serialVersionUID = 5127353027086786117L;
Sha256Hash blockHash;
// Only one of either txOutChanges or transactions will be set
private TransactionOutputChanges txOutChanges;
private List<Transaction> transactions;
public StoredUndoableBlock(Sha256Hash hash, TransactionOutputChanges txOutChanges) {
this.blockHash = hash;
this.transactions = null;
this.txOutChanges = txOutChanges;
}
public StoredUndoableBlock(Sha256Hash hash, List<Transaction> transactions) {
this.blockHash = hash;
this.txOutChanges = null;
this.transactions = transactions;
}
/**
* Get the transaction output changes if they have been calculated, otherwise null.
* Only one of this and getTransactions() will return a non-null value.
*/
public TransactionOutputChanges getTxOutChanges() {
return txOutChanges;
}
/**
* Get the full list of transactions if it is stored, otherwise null.
* Only one of this and getTxOutChanges() will return a non-null value.
*/
public List<Transaction> getTransactions() {
return transactions;
}
/**
* Get the hash of the represented block
*/
public Sha256Hash getHash() {
return blockHash;
}
@Override
public int hashCode() {
return blockHash.hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
StoredUndoableBlock other = (StoredUndoableBlock) o;
return getHash().equals(other.getHash());
}
@Override
public String toString() {
return "Undoable Block " + blockHash.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +0,0 @@
/**
* Copyright 2014 Giannis Dzegoutanis
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.wallet.WalletTransaction;
import java.util.Map;
/**
* This interface is used to abstract the {@link org.bitcoinj.core.Wallet} and the {@link org.bitcoinj.core.Transaction}
*/
public interface TransactionBag {
/** Returns true if this wallet contains a public key which hashes to the given hash. */
public boolean isPubKeyHashMine(byte[] pubkeyHash);
/** Returns true if this wallet is watching transactions for outputs with the script. */
public boolean isWatchedScript(Script script);
/** Returns true if this wallet contains a keypair with the given public key. */
public boolean isPubKeyMine(byte[] pubkey);
/** Returns true if this wallet knows the script corresponding to the given hash. */
public boolean isPayToScriptHashMine(byte[] payToScriptHash);
/** Returns transactions from a specific pool. */
public Map<Sha256Hash, Transaction> getTransactionPool(WalletTransaction.Pool pool);
}

View File

@@ -1,181 +0,0 @@
/**
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import com.google.common.annotations.*;
import com.google.common.base.*;
import com.google.common.util.concurrent.*;
import org.bitcoinj.utils.*;
import org.slf4j.*;
import javax.annotation.*;
import java.util.*;
/**
* Represents a single transaction broadcast that we are performing. A broadcast occurs after a new transaction is created
* (typically by a {@link Wallet} and needs to be sent to the network. A broadcast can succeed or fail. A success is
* defined as seeing the transaction be announced by peers via inv messages, thus indicating their acceptance. A failure
* is defined as not reaching acceptance within a timeout period, or getting an explicit reject message from a peer
* indicating that the transaction was not acceptable.
*/
public class TransactionBroadcast {
private static final Logger log = LoggerFactory.getLogger(TransactionBroadcast.class);
private final SettableFuture<Transaction> future = SettableFuture.create();
private final PeerGroup peerGroup;
private final Transaction tx;
@Nullable private final Context context;
private int minConnections;
private int numWaitingFor;
/** Used for shuffling the peers before broadcast: unit tests can replace this to make themselves deterministic. */
@VisibleForTesting
public static Random random = new Random();
private Transaction pinnedTx;
// Tracks which nodes sent us a reject message about this broadcast, if any. Useful for debugging.
private Map<Peer, RejectMessage> rejects = Collections.synchronizedMap(new HashMap<Peer, RejectMessage>());
// TODO: Context being owned by BlockChain isn't right w.r.t future intentions so it shouldn't really be optional here.
TransactionBroadcast(PeerGroup peerGroup, @Nullable Context context, Transaction tx) {
this.peerGroup = peerGroup;
this.context = context;
this.tx = tx;
this.minConnections = Math.max(1, peerGroup.getMinBroadcastConnections());
}
public ListenableFuture<Transaction> future() {
return future;
}
public void setMinConnections(int minConnections) {
this.minConnections = minConnections;
}
private PeerEventListener rejectionListener = new AbstractPeerEventListener() {
@Override
public Message onPreMessageReceived(Peer peer, Message m) {
if (m instanceof RejectMessage) {
RejectMessage rejectMessage = (RejectMessage)m;
if (tx.getHash().equals(rejectMessage.getRejectedObjectHash())) {
rejects.put(peer, rejectMessage);
int size = rejects.size();
long threshold = Math.round(numWaitingFor / 2.0);
if (size > threshold) {
log.warn("Threshold for considering broadcast rejected has been reached ({}/{})", size, threshold);
future.setException(new RejectedTransactionException(tx, rejectMessage));
peerGroup.removeEventListener(this);
}
}
}
return m;
}
};
public ListenableFuture<Transaction> broadcast() {
peerGroup.addEventListener(rejectionListener, Threading.SAME_THREAD);
log.info("Waiting for {} peers required for broadcast, we have {} ...", minConnections, peerGroup.getConnectedPeers().size());
peerGroup.waitForPeers(minConnections).addListener(new EnoughAvailablePeers(), Threading.SAME_THREAD);
return future;
}
private class EnoughAvailablePeers implements Runnable {
@Override
public void run() {
// We now have enough connected peers to send the transaction.
// This can be called immediately if we already have enough. Otherwise it'll be called from a peer
// thread.
// We will send the tx simultaneously to half the connected peers and wait to hear back from at least half
// of the other half, i.e., with 4 peers connected we will send the tx to 2 randomly chosen peers, and then
// wait for it to show up on one of the other two. This will be taken as sign of network acceptance. As can
// be seen, 4 peers is probably too little - it doesn't taken many broken peers for tx propagation to have
// a big effect.
List<Peer> peers = peerGroup.getConnectedPeers(); // snapshots
// We intern the tx here so we are using a canonical version of the object (as it's unfortunately mutable).
// TODO: Once confidence state is moved out of Transaction we can kill off this step.
pinnedTx = context != null ? context.getConfidenceTable().intern(tx) : tx;
// Prepare to send the transaction by adding a listener that'll be called when confidence changes.
// Only bother with this if we might actually hear back:
if (minConnections > 1)
pinnedTx.getConfidence().addEventListener(new ConfidenceChange());
// Satoshis code sends an inv in this case and then lets the peer request the tx data. We just
// blast out the TX here for a couple of reasons. Firstly it's simpler: in the case where we have
// just a single connection we don't have to wait for getdata to be received and handled before
// completing the future in the code immediately below. Secondly, it's faster. The reason the
// Satoshi client sends an inv is privacy - it means you can't tell if the peer originated the
// transaction or not. However, we are not a fully validating node and this is advertised in
// our version message, as SPV nodes cannot relay it doesn't give away any additional information
// to skip the inv here - we wouldn't send invs anyway.
int numConnected = peers.size();
int numToBroadcastTo = (int) Math.max(1, Math.round(Math.ceil(peers.size() / 2.0)));
numWaitingFor = (int) Math.ceil((peers.size() - numToBroadcastTo) / 2.0);
Collections.shuffle(peers, random);
peers = peers.subList(0, numToBroadcastTo);
log.info("broadcastTransaction: We have {} peers, adding {} to the memory pool and sending to {} peers, will wait for {}, sending to: {}",
numConnected, tx.getHashAsString(), numToBroadcastTo, numWaitingFor, Joiner.on(",").join(peers));
for (Peer peer : peers) {
try {
peer.sendMessage(pinnedTx);
// We don't record the peer as having seen the tx in the memory pool because we want to track only
// how many peers announced to us.
} catch (Exception e) {
log.error("Caught exception sending to {}", peer, e);
}
}
// If we've been limited to talk to only one peer, we can't wait to hear back because the
// remote peer won't tell us about transactions we just announced to it for obvious reasons.
// So we just have to assume we're done, at that point. This happens when we're not given
// any peer discovery source and the user just calls connectTo() once.
if (minConnections == 1) {
peerGroup.removeEventListener(rejectionListener);
future.set(pinnedTx);
}
}
}
private class ConfidenceChange implements TransactionConfidence.Listener {
@Override
public void onConfidenceChanged(TransactionConfidence conf, ChangeReason reason) {
// The number of peers that announced this tx has gone up.
int numSeenPeers = conf.numBroadcastPeers() + rejects.size();
boolean mined = tx.getAppearsInHashes() != null;
log.info("broadcastTransaction: {}: TX {} seen by {} peers{}", reason, pinnedTx.getHashAsString(),
numSeenPeers, mined ? " and mined" : "");
if (numSeenPeers >= numWaitingFor || mined) {
// We've seen the min required number of peers announce the transaction, or it was included
// in a block. Normally we'd expect to see it fully propagate before it gets mined, but
// it can be that a block is solved very soon after broadcast, and it's also possible that
// due to version skew and changes in the relay rules our transaction is not going to
// fully propagate yet can get mined anyway.
//
// Note that we can't wait for the current number of connected peers right now because we
// could have added more peers after the broadcast took place, which means they won't
// have seen the transaction. In future when peers sync up their memory pools after they
// connect we could come back and change this.
//
// We're done! It's important that the PeerGroup lock is not held (by this thread) at this
// point to avoid triggering inversions when the Future completes.
log.info("broadcastTransaction: {} complete", pinnedTx.getHashAsString());
peerGroup.removeEventListener(rejectionListener);
conf.removeEventListener(this);
future.set(pinnedTx); // RE-ENTRANCY POINT
}
}
}
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import com.google.common.util.concurrent.ListenableFuture;
/**
* A general interface which declares the ability to broadcast transactions. This is implemented
* by {@link org.bitcoinj.core.PeerGroup}.
*/
public interface TransactionBroadcaster {
/** Broadcast the given transaction on the network */
public ListenableFuture<Transaction> broadcastTransaction(final Transaction tx);
}

View File

@@ -1,461 +0,0 @@
/*
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import com.google.common.collect.Sets;
import org.bitcoinj.utils.ListenerRegistration;
import org.bitcoinj.utils.Threading;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.ListIterator;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import static com.google.common.base.Preconditions.*;
/**
* <p>A TransactionConfidence object tracks data you can use to make a confidence decision about a transaction.
* It also contains some pre-canned rules for common scenarios: if you aren't really sure what level of confidence
* you need, these should prove useful. You can get a confidence object using {@link Transaction#getConfidence()}.
* They cannot be constructed directly.</p>
*
* <p>Confidence in a transaction can come in multiple ways:</p>
*
* <ul>
* <li>Because you created it yourself and only you have the necessary keys.</li>
* <li>Receiving it from a fully validating peer you know is trustworthy, for instance, because it's run by yourself.</li>
* <li>Receiving it from a peer on the network you randomly chose. If your network connection is not being
* intercepted, you have a pretty good chance of connecting to a node that is following the rules.</li>
* <li>Receiving it from multiple peers on the network. If your network connection is not being intercepted,
* hearing about a transaction from multiple peers indicates the network has accepted the transaction and
* thus miners likely have too (miners have the final say in whether a transaction becomes valid or not).</li>
* <li>Seeing the transaction appear appear in a block on the main chain. Your confidence increases as the transaction
* becomes further buried under work. Work can be measured either in blocks (roughly, units of time), or
* amount of work done.</li>
* </ul>
*
* <p>Alternatively, you may know that the transaction is "dead", that is, one or more of its inputs have
* been double spent and will never confirm unless there is another re-org.</p>
*
* <p>TransactionConfidence is updated via the {@link org.bitcoinj.core.TransactionConfidence#incrementDepthInBlocks()}
* method to ensure the block depth is up to date.</p>
* To make a copy that won't be changed, use {@link org.bitcoinj.core.TransactionConfidence#duplicate()}.
*/
public class TransactionConfidence implements Serializable {
private static final long serialVersionUID = 4577920141400556444L;
/**
* The peers that have announced the transaction to us. Network nodes don't have stable identities, so we use
* IP address as an approximation. It's obviously vulnerable to being gamed if we allow arbitrary people to connect
* to us, so only peers we explicitly connected to should go here.
*/
private CopyOnWriteArrayList<PeerAddress> broadcastBy;
/** The Transaction that this confidence object is associated with. */
private final Sha256Hash hash;
// Lazily created listeners array.
private transient CopyOnWriteArrayList<ListenerRegistration<Listener>> listeners;
// The depth of the transaction on the best chain in blocks. An unconfirmed block has depth 0.
private int depth;
/** Describes the state of the transaction in general terms. Properties can be read to learn specifics. */
public enum ConfidenceType {
/** If BUILDING, then the transaction is included in the best chain and your confidence in it is increasing. */
BUILDING(1),
/**
* If PENDING, then the transaction is unconfirmed and should be included shortly, as long as it is being
* announced and is considered valid by the network. A pending transaction will be announced if the containing
* wallet has been attached to a live {@link PeerGroup} using {@link PeerGroup#addWallet(Wallet)}.
* You can estimate how likely the transaction is to be included by connecting to a bunch of nodes then measuring
* how many announce it, using {@link org.bitcoinj.core.TransactionConfidence#numBroadcastPeers()}.
* Or if you saw it from a trusted peer, you can assume it's valid and will get mined sooner or later as well.
*/
PENDING(2),
/**
* If DEAD, then it means the transaction won't confirm unless there is another re-org,
* because some other transaction is spending one of its inputs. Such transactions should be alerted to the user
* so they can take action, eg, suspending shipment of goods if they are a merchant.
* It can also mean that a coinbase transaction has been made dead from it being moved onto a side chain.
*/
DEAD(4),
/**
* If a transaction hasn't been broadcast yet, or there's no record of it, its confidence is UNKNOWN.
*/
UNKNOWN(0);
private int value;
ConfidenceType(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
private ConfidenceType confidenceType = ConfidenceType.UNKNOWN;
private int appearedAtChainHeight = -1;
// The transaction that double spent this one, if any.
private Transaction overridingTransaction;
/**
* Information about where the transaction was first seen (network, sent direct from peer, created by ourselves).
* Useful for risk analyzing pending transactions. Probably not that useful after a tx is included in the chain,
* unless re-org double spends start happening frequently.
*/
public enum Source {
/** We don't know where the transaction came from. */
UNKNOWN,
/** We got this transaction from a network peer. */
NETWORK,
/** This transaction was created by our own wallet, so we know it's not a double spend. */
SELF
}
private Source source = Source.UNKNOWN;
public TransactionConfidence(Sha256Hash hash) {
// Assume a default number of peers for our set.
broadcastBy = new CopyOnWriteArrayList<PeerAddress>();
listeners = new CopyOnWriteArrayList<ListenerRegistration<Listener>>();
this.hash = hash;
}
/**
* <p>A confidence listener is informed when the level of {@link TransactionConfidence} is updated by something, like
* for example a {@link Wallet}. You can add listeners to update your user interface or manage your order tracking
* system when confidence levels pass a certain threshold. <b>Note that confidence can go down as well as up.</b>
* For example, this can happen if somebody is doing a double-spend attack against you. Whilst it's unlikely, your
* code should be able to handle that in order to be correct.</p>
*
* <p>During listener execution, it's safe to remove the current listener but not others.</p>
*/
public interface Listener {
/** An enum that describes why a transaction confidence listener is being invoked (i.e. the class of change). */
public enum ChangeReason {
/**
* Occurs when the type returned by {@link org.bitcoinj.core.TransactionConfidence#getConfidenceType()}
* has changed. For example, if a PENDING transaction changes to BUILDING or DEAD, then this reason will
* be given. It's a high level summary.
*/
TYPE,
/**
* Occurs when a transaction that is in the best known block chain gets buried by another block. If you're
* waiting for a certain number of confirmations, this is the reason to watch out for.
*/
DEPTH,
/**
* Occurs when a pending transaction (not in the chain) was announced by another connected peers. By
* watching the number of peers that announced a transaction go up, you can see whether it's being
* accepted by the network or not. If all your peers announce, it's a pretty good bet the transaction
* is considered relayable and has thus reached the miners.
*/
SEEN_PEERS,
}
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason);
}
/**
* <p>Adds an event listener that will be run when this confidence object is updated. The listener will be locked and
* is likely to be invoked on a peer thread.</p>
*
* <p>Note that this is NOT called when every block arrives. Instead it is called when the transaction
* transitions between confidence states, ie, from not being seen in the chain to being seen (not necessarily in
* the best chain). If you want to know when the transaction gets buried under another block, consider using
* a future from {@link #getDepthFuture(int)}.</p>
*/
public void addEventListener(Listener listener, Executor executor) {
checkNotNull(listener);
listeners.addIfAbsent(new ListenerRegistration<Listener>(listener, executor));
}
/**
* <p>Adds an event listener that will be run when this confidence object is updated. The listener will be locked and
* is likely to be invoked on a peer thread.</p>
*
* <p>Note that this is NOT called when every block arrives. Instead it is called when the transaction
* transitions between confidence states, ie, from not being seen in the chain to being seen (not necessarily in
* the best chain). If you want to know when the transaction gets buried under another block, implement a
* {@link BlockChainListener}, attach it to a {@link BlockChain} and then use the getters on the
* confidence object to determine the new depth.</p>
*/
public void addEventListener(Listener listener) {
addEventListener(listener, Threading.USER_THREAD);
}
public boolean removeEventListener(Listener listener) {
checkNotNull(listener);
return ListenerRegistration.removeFromList(listener, listeners);
}
/**
* Returns the chain height at which the transaction appeared if confidence type is BUILDING.
* @throws IllegalStateException if the confidence type is not BUILDING.
*/
public synchronized int getAppearedAtChainHeight() {
if (getConfidenceType() != ConfidenceType.BUILDING)
throw new IllegalStateException("Confidence type is " + getConfidenceType() + ", not BUILDING");
return appearedAtChainHeight;
}
/**
* The chain height at which the transaction appeared, if it has been seen in the best chain. Automatically sets
* the current type to {@link ConfidenceType#BUILDING} and depth to one.
*/
public synchronized void setAppearedAtChainHeight(int appearedAtChainHeight) {
if (appearedAtChainHeight < 0)
throw new IllegalArgumentException("appearedAtChainHeight out of range");
this.appearedAtChainHeight = appearedAtChainHeight;
this.depth = 1;
setConfidenceType(ConfidenceType.BUILDING);
}
/**
* Returns a general statement of the level of confidence you can have in this transaction.
*/
public synchronized ConfidenceType getConfidenceType() {
return confidenceType;
}
/**
* Called by other objects in the system, like a {@link Wallet}, when new information about the confidence of a
* transaction becomes available.
*/
public synchronized void setConfidenceType(ConfidenceType confidenceType) {
if (confidenceType == this.confidenceType)
return;
this.confidenceType = confidenceType;
if (confidenceType != ConfidenceType.DEAD) {
overridingTransaction = null;
}
if (confidenceType == ConfidenceType.PENDING) {
depth = 0;
appearedAtChainHeight = -1;
}
}
/**
* Called by a {@link Peer} when a transaction is pending and announced by a peer. The more peers announce the
* transaction, the more peers have validated it (assuming your internet connection is not being intercepted).
* If confidence is currently unknown, sets it to {@link ConfidenceType#PENDING}. Listeners will be
* invoked in this case.
*
* @param address IP address of the peer, used as a proxy for identity.
*/
public synchronized boolean markBroadcastBy(PeerAddress address) {
if (!broadcastBy.addIfAbsent(address))
return false; // Duplicate.
if (getConfidenceType() == ConfidenceType.UNKNOWN) {
this.confidenceType = ConfidenceType.PENDING;
}
return true;
}
/**
* Returns how many peers have been passed to {@link TransactionConfidence#markBroadcastBy}.
*/
public int numBroadcastPeers() {
return broadcastBy.size();
}
/**
* Returns a snapshot of {@link PeerAddress}es that announced the transaction.
*/
public Set<PeerAddress> getBroadcastBy() {
ListIterator<PeerAddress> iterator = broadcastBy.listIterator();
return Sets.newHashSet(iterator);
}
/** Returns true if the given address has been seen via markBroadcastBy() */
public boolean wasBroadcastBy(PeerAddress address) {
return broadcastBy.contains(address);
}
@Override
public synchronized String toString() {
StringBuilder builder = new StringBuilder();
int peers = numBroadcastPeers();
if (peers > 0) {
builder.append("Seen by ");
builder.append(peers);
if (peers > 1)
builder.append(" peers. ");
else
builder.append(" peer. ");
}
switch (getConfidenceType()) {
case UNKNOWN:
builder.append("Unknown confidence level.");
break;
case DEAD:
builder.append("Dead: overridden by double spend and will not confirm.");
break;
case PENDING:
builder.append("Pending/unconfirmed.");
break;
case BUILDING:
builder.append(String.format("Appeared in best chain at height %d, depth %d.",
getAppearedAtChainHeight(), getDepthInBlocks()));
break;
}
return builder.toString();
}
/**
* Called by the wallet when the tx appears on the best chain and a new block is added to the top. Updates the
* internal counter that tracks how deeply buried the block is.
*/
public synchronized void incrementDepthInBlocks() {
this.depth++;
}
/**
* <p>Depth in the chain is an approximation of how much time has elapsed since the transaction has been confirmed.
* On average there is supposed to be a new block every 10 minutes, but the actual rate may vary. The reference
* (Satoshi) implementation considers a transaction impractical to reverse after 6 blocks, but as of EOY 2011 network
* security is high enough that often only one block is considered enough even for high value transactions. For low
* value transactions like songs, or other cheap items, no blocks at all may be necessary.</p>
*
* <p>If the transaction appears in the top block, the depth is one. If it's anything else (pending, dead, unknown)
* the depth is zero.</p>
*/
public synchronized int getDepthInBlocks() {
return depth;
}
/*
* Set the depth in blocks. Having one block confirmation is a depth of one.
*/
public synchronized void setDepthInBlocks(int depth) {
this.depth = depth;
}
/**
* If this transaction has been overridden by a double spend (is dead), this call returns the overriding transaction.
* Note that this call <b>can return null</b> if you have migrated an old wallet, as pre-Jan 2012 wallets did not
* store this information.
*
* @return the transaction that double spent this one
* @throws IllegalStateException if confidence type is not OVERRIDDEN_BY_DOUBLE_SPEND.
*/
public synchronized Transaction getOverridingTransaction() {
if (getConfidenceType() != ConfidenceType.DEAD)
throw new IllegalStateException("Confidence type is " + getConfidenceType() +
", not OVERRIDDEN_BY_DOUBLE_SPEND");
return overridingTransaction;
}
/**
* Called when the transaction becomes newly dead, that is, we learn that one of its inputs has already been spent
* in such a way that the double-spending transaction takes precedence over this one. It will not become valid now
* unless there is a re-org. Automatically sets the confidence type to DEAD. The overriding transaction may not
* directly double spend this one, but could also have double spent a dependency of this tx.
*/
public synchronized void setOverridingTransaction(@Nullable Transaction overridingTransaction) {
this.overridingTransaction = overridingTransaction;
setConfidenceType(ConfidenceType.DEAD);
}
/** Returns a copy of this object. Event listeners are not duplicated. */
public synchronized TransactionConfidence duplicate() {
TransactionConfidence c = new TransactionConfidence(hash);
// There is no point in this sync block, it's just to help FindBugs.
synchronized (c) {
c.broadcastBy.addAll(broadcastBy);
c.confidenceType = confidenceType;
c.overridingTransaction = overridingTransaction;
c.appearedAtChainHeight = appearedAtChainHeight;
return c;
}
}
/**
* Call this after adjusting the confidence, for cases where listeners should be notified. This has to be done
* explicitly rather than being done automatically because sometimes complex changes to transaction states can
* result in a series of confidence changes that are not really useful to see separately. By invoking listeners
* explicitly, more precise control is available. Note that this will run the listeners on the user code thread.
*/
public void queueListeners(final Listener.ChangeReason reason) {
for (final ListenerRegistration<Listener> registration : listeners) {
registration.executor.execute(new Runnable() {
@Override
public void run() {
registration.listener.onConfidenceChanged(TransactionConfidence.this, reason);
}
});
}
}
/**
* The source of a transaction tries to identify where it came from originally. For instance, did we download it
* from the peer to peer network, or make it ourselves, or receive it via Bluetooth, or import it from another app,
* and so on. This information is useful for {@link org.bitcoinj.wallet.CoinSelector} implementations to risk analyze
* transactions and decide when to spend them.
*/
public synchronized Source getSource() {
return source;
}
/**
* The source of a transaction tries to identify where it came from originally. For instance, did we download it
* from the peer to peer network, or make it ourselves, or receive it via Bluetooth, or import it from another app,
* and so on. This information is useful for {@link org.bitcoinj.wallet.CoinSelector} implementations to risk analyze
* transactions and decide when to spend them.
*/
public synchronized void setSource(Source source) {
this.source = source;
}
/**
* Returns a future that completes when the transaction has been confirmed by "depth" blocks. For instance setting
* depth to one will wait until it appears in a block on the best chain, and zero will wait until it has been seen
* on the network.
*/
public synchronized ListenableFuture<TransactionConfidence> getDepthFuture(final int depth, Executor executor) {
final SettableFuture<TransactionConfidence> result = SettableFuture.create();
if (getDepthInBlocks() >= depth) {
result.set(this);
}
addEventListener(new Listener() {
@Override public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
if (getDepthInBlocks() >= depth) {
removeEventListener(this);
result.set(confidence);
}
}
}, executor);
return result;
}
public synchronized ListenableFuture<TransactionConfidence> getDepthFuture(final int depth) {
return getDepthFuture(depth, Threading.USER_THREAD);
}
public Sha256Hash getTransactionHash() {
return hash;
}
}

View File

@@ -1,499 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.wallet.DefaultRiskAnalysis;
import org.bitcoinj.wallet.KeyBag;
import org.bitcoinj.wallet.RedeemData;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.Map;
import static com.google.common.base.Preconditions.checkElementIndex;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* A transfer of coins from one address to another creates a transaction in which the outputs
* can be claimed by the recipient in the input of another transaction. You can imagine a
* transaction as being a module which is wired up to others, the inputs of one have to be wired
* to the outputs of another. The exceptions are coinbase transactions, which create new coins.
*/
public class TransactionInput extends ChildMessage implements Serializable {
public static final long NO_SEQUENCE = 0xFFFFFFFFL;
private static final long serialVersionUID = 2;
public static final byte[] EMPTY_ARRAY = new byte[0];
// Allows for altering transactions after they were broadcast. Tx replacement is currently disabled in the C++
// client so this is always the UINT_MAX.
// TODO: Document this in more detail and build features that use it.
private long sequence;
// Data needed to connect to the output of the transaction we're gathering coins from.
private TransactionOutPoint outpoint;
// The "script bytes" might not actually be a script. In coinbase transactions where new coins are minted there
// is no input transaction, so instead the scriptBytes contains some extra stuff (like a rollover nonce) that we
// don't care about much. The bytes are turned into a Script object (cached below) on demand via a getter.
private byte[] scriptBytes;
// The Script object obtained from parsing scriptBytes. Only filled in on demand and if the transaction is not
// coinbase.
transient private WeakReference<Script> scriptSig;
/** Value of the output connected to the input, if known. This field does not participate in equals()/hashCode(). */
@Nullable
private Coin value;
/**
* Creates an input that connects to nothing - used only in creation of coinbase transactions.
*/
public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] scriptBytes) {
this(params, parentTransaction, scriptBytes, new TransactionOutPoint(params, NO_SEQUENCE, (Transaction) null));
}
public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] scriptBytes,
TransactionOutPoint outpoint) {
this(params, parentTransaction, scriptBytes, outpoint, null);
}
public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] scriptBytes,
TransactionOutPoint outpoint, @Nullable Coin value) {
super(params);
this.scriptBytes = scriptBytes;
this.outpoint = outpoint;
this.sequence = NO_SEQUENCE;
this.value = value;
setParent(parentTransaction);
length = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
}
/**
* Creates an UNSIGNED input that links to the given output
*/
TransactionInput(NetworkParameters params, Transaction parentTransaction, TransactionOutput output) {
super(params);
long outputIndex = output.getIndex();
if(output.getParentTransaction() != null ) {
outpoint = new TransactionOutPoint(params, outputIndex, output.getParentTransaction());
} else {
outpoint = new TransactionOutPoint(params, output);
}
scriptBytes = EMPTY_ARRAY;
sequence = NO_SEQUENCE;
setParent(parentTransaction);
this.value = output.getValue();
length = 41;
}
/**
* Deserializes an input message. This is usually part of a transaction message.
*/
public TransactionInput(NetworkParameters params, @Nullable Transaction parentTransaction, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
setParent(parentTransaction);
this.value = null;
}
/**
* Deserializes an input message. This is usually part of a transaction message.
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* as the length will be provided as part of the header. If unknown then set to Message.UNKNOWN_LENGTH
* @throws ProtocolException
*/
public TransactionInput(NetworkParameters params, Transaction parentTransaction, byte[] payload, int offset,
boolean parseLazy, boolean parseRetain)
throws ProtocolException {
super(params, payload, offset, parentTransaction, parseLazy, parseRetain, UNKNOWN_LENGTH);
this.value = null;
}
@Override
protected void parseLite() throws ProtocolException {
int curs = cursor;
int scriptLen = (int) readVarInt(36);
length = cursor - offset + scriptLen + 4;
cursor = curs;
}
@Override
void parse() throws ProtocolException {
outpoint = new TransactionOutPoint(params, payload, cursor, this, parseLazy, parseRetain);
cursor += outpoint.getMessageSize();
int scriptLen = (int) readVarInt();
scriptBytes = readBytes(scriptLen);
sequence = readUint32();
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
outpoint.bitcoinSerialize(stream);
stream.write(new VarInt(scriptBytes.length).encode());
stream.write(scriptBytes);
Utils.uint32ToByteStreamLE(sequence, stream);
}
/**
* Coinbase transactions have special inputs with hashes of zero. If this is such an input, returns true.
*/
public boolean isCoinBase() {
maybeParse();
return outpoint.getHash().equals(Sha256Hash.ZERO_HASH) &&
(outpoint.getIndex() & 0xFFFFFFFFL) == 0xFFFFFFFFL; // -1 but all is serialized to the wire as unsigned int.
}
/**
* Returns the script that is fed to the referenced output (scriptPubKey) script in order to satisfy it: usually
* contains signatures and maybe keys, but can contain arbitrary data if the output script accepts it.
*/
public Script getScriptSig() throws ScriptException {
// Transactions that generate new coins don't actually have a script. Instead this
// parameter is overloaded to be something totally different.
Script script = scriptSig == null ? null : scriptSig.get();
if (script == null) {
maybeParse();
script = new Script(scriptBytes);
scriptSig = new WeakReference<Script>(script);
return script;
}
return script;
}
/** Set the given program as the scriptSig that is supposed to satisfy the connected output script. */
public void setScriptSig(Script scriptSig) {
this.scriptSig = new WeakReference<Script>(checkNotNull(scriptSig));
// TODO: This should all be cleaned up so we have a consistent internal representation.
setScriptBytes(scriptSig.getProgram());
}
/**
* Convenience method that returns the from address of this input by parsing the scriptSig. The concept of a
* "from address" is not well defined in Bitcoin and you should not assume that senders of a transaction can
* actually receive coins on the same address they used to sign (e.g. this is not true for shared wallets).
*/
@Deprecated
public Address getFromAddress() throws ScriptException {
if (isCoinBase()) {
throw new ScriptException(
"This is a coinbase transaction which generates new coins. It does not have a from address.");
}
return getScriptSig().getFromAddress(params);
}
/**
* Sequence numbers allow participants in a multi-party transaction signing protocol to create new versions of the
* transaction independently of each other. Newer versions of a transaction can replace an existing version that's
* in nodes memory pools if the existing version is time locked. See the Contracts page on the Bitcoin wiki for
* examples of how you can use this feature to build contract protocols. Note that as of 2012 the tx replacement
* feature is disabled so sequence numbers are unusable.
*/
public long getSequenceNumber() {
maybeParse();
return sequence;
}
/**
* Sequence numbers allow participants in a multi-party transaction signing protocol to create new versions of the
* transaction independently of each other. Newer versions of a transaction can replace an existing version that's
* in nodes memory pools if the existing version is time locked. See the Contracts page on the Bitcoin wiki for
* examples of how you can use this feature to build contract protocols. Note that as of 2012 the tx replacement
* feature is disabled so sequence numbers are unusable.
*/
public void setSequenceNumber(long sequence) {
unCache();
this.sequence = sequence;
}
/**
* @return The previous output transaction reference, as an OutPoint structure. This contains the
* data needed to connect to the output of the transaction we're gathering coins from.
*/
public TransactionOutPoint getOutpoint() {
maybeParse();
return outpoint;
}
/**
* The "script bytes" might not actually be a script. In coinbase transactions where new coins are minted there
* is no input transaction, so instead the scriptBytes contains some extra stuff (like a rollover nonce) that we
* don't care about much. The bytes are turned into a Script object (cached below) on demand via a getter.
* @return the scriptBytes
*/
public byte[] getScriptBytes() {
maybeParse();
return scriptBytes;
}
/**
* @param scriptBytes the scriptBytes to set
*/
void setScriptBytes(byte[] scriptBytes) {
unCache();
this.scriptSig = null;
int oldLength = length;
this.scriptBytes = scriptBytes;
// 40 = previous_outpoint (36) + sequence (4)
int newLength = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
adjustLength(newLength - oldLength);
}
/**
* @return The Transaction that owns this input.
*/
public Transaction getParentTransaction() {
return (Transaction) parent;
}
/**
* @return Value of the output connected to this input, if known. Null if unknown.
*/
@Nullable
public Coin getValue() {
return value;
}
/**
* Returns a human readable debug string.
*/
@Override
public String toString() {
if (isCoinBase())
return "TxIn: COINBASE";
try {
return "TxIn for [" + outpoint + "]: " + getScriptSig();
} catch (ScriptException e) {
throw new RuntimeException(e);
}
}
public enum ConnectionResult {
NO_SUCH_TX,
ALREADY_SPENT,
SUCCESS
}
// TODO: Clean all this up once TransactionOutPoint disappears.
/**
* Locates the referenced output from the given pool of transactions.
*
* @return The TransactionOutput or null if the transactions map doesn't contain the referenced tx.
*/
@Nullable
TransactionOutput getConnectedOutput(Map<Sha256Hash, Transaction> transactions) {
Transaction tx = transactions.get(outpoint.getHash());
if (tx == null)
return null;
return tx.getOutputs().get((int) outpoint.getIndex());
}
/**
* Alias for getOutpoint().getConnectedRedeemData(keyBag)
* @see TransactionOutPoint#getConnectedRedeemData(org.bitcoinj.wallet.KeyBag)
*/
@Nullable
public RedeemData getConnectedRedeemData(KeyBag keyBag) throws ScriptException {
return getOutpoint().getConnectedRedeemData(keyBag);
}
public enum ConnectMode {
DISCONNECT_ON_CONFLICT,
ABORT_ON_CONFLICT
}
/**
* Connects this input to the relevant output of the referenced transaction if it's in the given map.
* Connecting means updating the internal pointers and spent flags. If the mode is to ABORT_ON_CONFLICT then
* the spent output won't be changed, but the outpoint.fromTx pointer will still be updated.
*
* @param transactions Map of txhash->transaction.
* @param mode Whether to abort if there's a pre-existing connection or not.
* @return NO_SUCH_TX if the prevtx wasn't found, ALREADY_SPENT if there was a conflict, SUCCESS if not.
*/
public ConnectionResult connect(Map<Sha256Hash, Transaction> transactions, ConnectMode mode) {
Transaction tx = transactions.get(outpoint.getHash());
if (tx == null) {
return TransactionInput.ConnectionResult.NO_SUCH_TX;
}
return connect(tx, mode);
}
/**
* Connects this input to the relevant output of the referenced transaction.
* Connecting means updating the internal pointers and spent flags. If the mode is to ABORT_ON_CONFLICT then
* the spent output won't be changed, but the outpoint.fromTx pointer will still be updated.
*
* @param transaction The transaction to try.
* @param mode Whether to abort if there's a pre-existing connection or not.
* @return NO_SUCH_TX if transaction is not the prevtx, ALREADY_SPENT if there was a conflict, SUCCESS if not.
*/
public ConnectionResult connect(Transaction transaction, ConnectMode mode) {
if (!transaction.getHash().equals(outpoint.getHash()))
return ConnectionResult.NO_SUCH_TX;
checkElementIndex((int) outpoint.getIndex(), transaction.getOutputs().size(), "Corrupt transaction");
TransactionOutput out = transaction.getOutput((int) outpoint.getIndex());
if (!out.isAvailableForSpending()) {
if (getParentTransaction().equals(outpoint.fromTx)) {
// Already connected.
return ConnectionResult.SUCCESS;
} else if (mode == ConnectMode.DISCONNECT_ON_CONFLICT) {
out.markAsUnspent();
} else if (mode == ConnectMode.ABORT_ON_CONFLICT) {
outpoint.fromTx = out.getParentTransaction();
return TransactionInput.ConnectionResult.ALREADY_SPENT;
}
}
connect(out);
return TransactionInput.ConnectionResult.SUCCESS;
}
/** Internal use only: connects this TransactionInput to the given output (updates pointers and spent flags) */
public void connect(TransactionOutput out) {
outpoint.fromTx = out.getParentTransaction();
out.markAsSpent(this);
value = out.getValue();
}
/**
* If this input is connected, check the output is connected back to this input and release it if so, making
* it spendable once again.
*
* @return true if the disconnection took place, false if it was not connected.
*/
public boolean disconnect() {
if (outpoint.fromTx == null) return false;
TransactionOutput output = outpoint.fromTx.getOutput((int) outpoint.getIndex());
if (output.getSpentBy() == this) {
output.markAsUnspent();
outpoint.fromTx = null;
return true;
} else {
return false;
}
}
/**
* Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
maybeParse();
out.defaultWriteObject();
}
/**
* @return true if this transaction's sequence number is set (ie it may be a part of a time-locked transaction)
*/
public boolean hasSequence() {
return sequence != NO_SEQUENCE;
}
/**
* For a connected transaction, runs the script against the connected pubkey and verifies they are correct.
* @throws ScriptException if the script did not verify.
* @throws VerificationException If the outpoint doesn't match the given output.
*/
public void verify() throws VerificationException {
final Transaction fromTx = getOutpoint().fromTx;
long spendingIndex = getOutpoint().getIndex();
checkNotNull(fromTx, "Not connected");
final TransactionOutput output = fromTx.getOutput((int) spendingIndex);
verify(output);
}
/**
* Verifies that this input can spend the given output. Note that this input must be a part of a transaction.
* Also note that the consistency of the outpoint will be checked, even if this input has not been connected.
*
* @param output the output that this input is supposed to spend.
* @throws ScriptException If the script doesn't verify.
* @throws VerificationException If the outpoint doesn't match the given output.
*/
public void verify(TransactionOutput output) throws VerificationException {
if (output.parent != null) {
if (!getOutpoint().getHash().equals(output.getParentTransaction().getHash()))
throw new VerificationException("This input does not refer to the tx containing the output.");
if (getOutpoint().getIndex() != output.getIndex())
throw new VerificationException("This input refers to a different output on the given tx.");
}
Script pubKey = output.getScriptPubKey();
int myIndex = getParentTransaction().getInputs().indexOf(this);
getScriptSig().correctlySpends(getParentTransaction(), myIndex, pubKey);
}
/**
* Returns the connected output, assuming the input was connected with
* {@link TransactionInput#connect(TransactionOutput)} or variants at some point. If it wasn't connected, then
* this method returns null.
*/
@Nullable
public TransactionOutput getConnectedOutput() {
return getOutpoint().getConnectedOutput();
}
/** Returns a copy of the input detached from its containing transaction, if need be. */
public TransactionInput duplicateDetached() {
return new TransactionInput(params, null, bitcoinSerialize(), 0);
}
/**
* <p>Returns either RuleViolation.NONE if the input is standard, or which rule makes it non-standard if so.
* The "IsStandard" rules control whether the default Bitcoin Core client blocks relay of a tx / refuses to mine it,
* however, non-standard transactions can still be included in blocks and will be accepted as valid if so.</p>
*
* <p>This method simply calls <tt>DefaultRiskAnalysis.isInputStandard(this)</tt>.</p>
*/
public DefaultRiskAnalysis.RuleViolation isStandard() {
return DefaultRiskAnalysis.isInputStandard(this);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TransactionInput input = (TransactionInput) o;
if (sequence != input.sequence) return false;
if (!outpoint.equals(input.outpoint)) return false;
if (!Arrays.equals(scriptBytes, input.scriptBytes)) return false;
if (scriptSig != null ? !scriptSig.equals(input.scriptSig) : input.scriptSig != null) return false;
if (parent != input.parent) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (sequence ^ (sequence >>> 32));
result = 31 * result + outpoint.hashCode();
result = 31 * result + (scriptBytes != null ? Arrays.hashCode(scriptBytes) : 0);
result = 31 * result + (scriptSig != null ? scriptSig.hashCode() : 0);
return result;
}
}

View File

@@ -1,250 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.wallet.KeyBag;
import org.bitcoinj.wallet.RedeemData;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
/**
* This message is a reference or pointer to an output of a different transaction.
*/
public class TransactionOutPoint extends ChildMessage implements Serializable {
private static final long serialVersionUID = -6320880638344662579L;
static final int MESSAGE_LENGTH = 36;
/** Hash of the transaction to which we refer. */
private Sha256Hash hash;
/** Which output of that transaction we are talking about. */
private long index;
// This is not part of Bitcoin serialization. It's included in Java serialization.
// It points to the connected transaction.
Transaction fromTx;
// The connected output.
private TransactionOutput connectedOutput;
public TransactionOutPoint(NetworkParameters params, long index, @Nullable Transaction fromTx) {
super(params);
this.index = index;
if (fromTx != null) {
this.hash = fromTx.getHash();
this.fromTx = fromTx;
} else {
// This happens when constructing the genesis block.
hash = Sha256Hash.ZERO_HASH;
}
length = MESSAGE_LENGTH;
}
public TransactionOutPoint(NetworkParameters params, long index, Sha256Hash hash) {
super(params);
this.index = index;
this.hash = hash;
length = MESSAGE_LENGTH;
}
public TransactionOutPoint(NetworkParameters params, TransactionOutput connectedOutput) {
this(params, connectedOutput.getIndex(), connectedOutput.getParentTransactionHash());
this.connectedOutput = connectedOutput;
}
/**
/**
* Deserializes the message. This is usually part of a transaction message.
*/
public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset);
}
/**
* Deserializes the message. This is usually part of a transaction message.
* @param params NetworkParameters object.
* @param offset The location of the first payload byte within the array.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @throws ProtocolException
*/
public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset, Message parent, boolean parseLazy, boolean parseRetain) throws ProtocolException {
super(params, payload, offset, parent, parseLazy, parseRetain, MESSAGE_LENGTH);
}
@Override
protected void parseLite() throws ProtocolException {
length = MESSAGE_LENGTH;
}
@Override
void parse() throws ProtocolException {
hash = readHash();
index = readUint32();
}
/* (non-Javadoc)
* @see Message#getMessageSize()
*/
@Override
public int getMessageSize() {
return MESSAGE_LENGTH;
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(Utils.reverseBytes(hash.getBytes()));
Utils.uint32ToByteStreamLE(index, stream);
}
/**
* An outpoint is a part of a transaction input that points to the output of another transaction. If we have both
* sides in memory, and they have been linked together, this returns a pointer to the connected output, or null
* if there is no such connection.
*/
@Nullable
public TransactionOutput getConnectedOutput() {
if (fromTx != null) {
return fromTx.getOutputs().get((int) index);
} else if (connectedOutput != null) {
return connectedOutput;
}
return null;
}
/**
* Returns the pubkey script from the connected output.
* @throws java.lang.NullPointerException if there is no connected output.
*/
public byte[] getConnectedPubKeyScript() {
byte[] result = checkNotNull(getConnectedOutput()).getScriptBytes();
checkState(result.length > 0);
return result;
}
/**
* Returns the ECKey identified in the connected output, for either pay-to-address scripts or pay-to-key scripts.
* For P2SH scripts you can use {@link #getConnectedRedeemData(org.bitcoinj.wallet.KeyBag)} and then get the
* key from RedeemData.
* If the script form cannot be understood, throws ScriptException.
*
* @return an ECKey or null if the connected key cannot be found in the wallet.
*/
@Nullable
public ECKey getConnectedKey(KeyBag keyBag) throws ScriptException {
TransactionOutput connectedOutput = getConnectedOutput();
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
Script connectedScript = connectedOutput.getScriptPubKey();
if (connectedScript.isSentToAddress()) {
byte[] addressBytes = connectedScript.getPubKeyHash();
return keyBag.findKeyFromPubHash(addressBytes);
} else if (connectedScript.isSentToRawPubKey()) {
byte[] pubkeyBytes = connectedScript.getPubKey();
return keyBag.findKeyFromPubKey(pubkeyBytes);
} else {
throw new ScriptException("Could not understand form of connected output script: " + connectedScript);
}
}
/**
* Returns the RedeemData identified in the connected output, for either pay-to-address scripts, pay-to-key
* or P2SH scripts.
* If the script forms cannot be understood, throws ScriptException.
*
* @return a RedeemData or null if the connected data cannot be found in the wallet.
*/
@Nullable
public RedeemData getConnectedRedeemData(KeyBag keyBag) throws ScriptException {
TransactionOutput connectedOutput = getConnectedOutput();
checkNotNull(connectedOutput, "Input is not connected so cannot retrieve key");
Script connectedScript = connectedOutput.getScriptPubKey();
if (connectedScript.isSentToAddress()) {
byte[] addressBytes = connectedScript.getPubKeyHash();
return RedeemData.of(keyBag.findKeyFromPubHash(addressBytes), connectedScript);
} else if (connectedScript.isSentToRawPubKey()) {
byte[] pubkeyBytes = connectedScript.getPubKey();
return RedeemData.of(keyBag.findKeyFromPubKey(pubkeyBytes), connectedScript);
} else if (connectedScript.isPayToScriptHash()) {
byte[] scriptHash = connectedScript.getPubKeyHash();
return keyBag.findRedeemDataFromScriptHash(scriptHash);
} else {
throw new ScriptException("Could not understand form of connected output script: " + connectedScript);
}
}
@Override
public String toString() {
return hash.toString() + ":" + index;
}
/**
* Returns the hash of the transaction this outpoint references/spends/is connected to.
*/
@Override
public Sha256Hash getHash() {
maybeParse();
return hash;
}
void setHash(Sha256Hash hash) {
this.hash = hash;
}
public long getIndex() {
maybeParse();
return index;
}
public void setIndex(long index) {
this.index = index;
}
/**
* Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
maybeParse();
out.defaultWriteObject();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TransactionOutPoint other = (TransactionOutPoint) o;
return getIndex() == other.getIndex() &&
getHash().equals(other.getHash());
}
@Override
public int hashCode() {
return getHash().hashCode();
}
}

View File

@@ -1,466 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import static com.google.common.base.Preconditions.*;
/**
* A TransactionOutput message contains a scriptPubKey that controls who is able to spend its value. It is a sub-part
* of the Transaction message.
*/
public class TransactionOutput extends ChildMessage implements Serializable {
private static final Logger log = LoggerFactory.getLogger(TransactionOutput.class);
private static final long serialVersionUID = -590332479859256824L;
// The output's value is kept as a native type in order to save class instances.
private long value;
// A transaction output has a script used for authenticating that the redeemer is allowed to spend
// this output.
private byte[] scriptBytes;
// The script bytes are parsed and turned into a Script on demand.
private transient WeakReference<Script> scriptPubKey;
// These fields are Java serialized but not Bitcoin serialized. They are used for tracking purposes in our wallet
// only. If set to true, this output is counted towards our balance. If false and spentBy is null the tx output
// was owned by us and was sent to somebody else. If false and spentBy is set it means this output was owned by
// us and used in one of our own transactions (eg, because it is a change output).
private boolean availableForSpending;
@Nullable private TransactionInput spentBy;
private transient int scriptLen;
/**
* Deserializes a transaction output message. This is usually part of a transaction message.
*/
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, byte[] payload,
int offset) throws ProtocolException {
super(params, payload, offset);
setParent(parent);
availableForSpending = true;
}
/**
* Deserializes a transaction output message. This is usually part of a transaction message.
*
* @param params NetworkParameters object.
* @param payload Bitcoin protocol formatted byte array containing message content.
* @param offset The location of the first payload byte within the array.
* @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
* @param parseRetain Whether to retain the backing byte array for quick reserialization.
* If true and the backing byte array is invalidated due to modification of a field then
* the cached bytes may be repopulated and retained if the message is serialized again in the future.
* @throws ProtocolException
*/
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, byte[] payload, int offset,
boolean parseLazy, boolean parseRetain) throws ProtocolException {
super(params, payload, offset, parent, parseLazy, parseRetain, UNKNOWN_LENGTH);
availableForSpending = true;
}
/**
* Creates an output that sends 'value' to the given address (public key hash). The amount should be created with
* something like {@link Coin#valueOf(int, int)}. Typically you would use
* {@link Transaction#addOutput(Coin, Address)} instead of creating a TransactionOutput directly.
*/
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, Coin value, Address to) {
this(params, parent, value, ScriptBuilder.createOutputScript(to).getProgram());
}
/**
* Creates an output that sends 'value' to the given public key using a simple CHECKSIG script (no addresses). The
* amount should be created with something like {@link Coin#valueOf(int, int)}. Typically you would use
* {@link Transaction#addOutput(Coin, ECKey)} instead of creating an output directly.
*/
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, Coin value, ECKey to) {
this(params, parent, value, ScriptBuilder.createOutputScript(to).getProgram());
}
public TransactionOutput(NetworkParameters params, @Nullable Transaction parent, Coin value, byte[] scriptBytes) {
super(params);
// Negative values obviously make no sense, except for -1 which is used as a sentinel value when calculating
// SIGHASH_SINGLE signatures, so unfortunately we have to allow that here.
checkArgument(value.signum() >= 0 || value.equals(Coin.NEGATIVE_SATOSHI), "Negative values not allowed");
checkArgument(value.compareTo(NetworkParameters.MAX_MONEY) < 0, "Values larger than MAX_MONEY not allowed");
this.value = value.value;
this.scriptBytes = scriptBytes;
setParent(parent);
availableForSpending = true;
length = 8 + VarInt.sizeOf(scriptBytes.length) + scriptBytes.length;
}
public Script getScriptPubKey() throws ScriptException {
// Quick hack to try and reduce memory consumption on Androids. SoftReference is the same as WeakReference
// on Dalvik (by design), so this arrangement just means that we can avoid the cost of re-parsing the script
// bytes if getScriptPubKey is called multiple times in quick succession in between garbage collections.
Script script = scriptPubKey == null ? null : scriptPubKey.get();
if (script == null) {
maybeParse();
script = new Script(scriptBytes);
scriptPubKey = new WeakReference<Script>(script);
return script;
}
return script;
}
/**
* <p>If the output script pays to an address as in <a href="https://bitcoin.org/en/developer-guide#term-p2pkh">
* P2PKH</a>, return the address of the receiver, i.e., a base58 encoded hash of the public key in the script. </p>
*
* @param networkParameters needed to specify an address
* @return null, if the output script is not the form <i>OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG</i>,
* i.e., not P2PKH
* @return an address made out of the public key hash
*/
@Nullable
public Address getAddressFromP2PKHScript(NetworkParameters networkParameters) throws ScriptException{
if (getScriptPubKey().isSentToAddress())
return getScriptPubKey().getToAddress(networkParameters);
return null;
}
/**
* <p>If the output script pays to a redeem script, return the address of the redeem script as described by,
* i.e., a base58 encoding of [one-byte version][20-byte hash][4-byte checksum], where the 20-byte hash refers to
* the redeem script.</p>
*
* <p>P2SH is described by <a href="https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki">BIP 16</a> and
* <a href="https://bitcoin.org/en/developer-guide#p2sh-scripts">documented in the Bitcoin Developer Guide</a>.</p>
*
* @param networkParameters needed to specify an address
* @return null if the output script does not pay to a script hash
* @return an address that belongs to the redeem script
*/
@Nullable
public Address getAddressFromP2SH(NetworkParameters networkParameters) throws ScriptException{
if (getScriptPubKey().isPayToScriptHash())
return getScriptPubKey().getToAddress(networkParameters);
return null;
}
@Override
protected void parseLite() throws ProtocolException {
value = readInt64();
scriptLen = (int) readVarInt();
length = cursor - offset + scriptLen;
}
@Override
void parse() throws ProtocolException {
scriptBytes = readBytes(scriptLen);
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
checkNotNull(scriptBytes);
maybeParse();
Utils.int64ToByteStreamLE(value, stream);
// TODO: Move script serialization into the Script class, where it belongs.
stream.write(new VarInt(scriptBytes.length).encode());
stream.write(scriptBytes);
}
/**
* Returns the value of this output. This is the amount of currency that the destination address
* receives.
*/
public Coin getValue() {
maybeParse();
try {
return Coin.valueOf(value);
} catch (IllegalArgumentException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
/**
* Sets the value of this output.
*/
public void setValue(Coin value) {
checkNotNull(value);
unCache();
this.value = value.value;
}
/**
* Gets the index of this output in the parent transaction, or throws if this output is free standing. Iterates
* over the parents list to discover this.
*/
public int getIndex() {
for (int i = 0; i < getParentTransaction().getOutputs().size(); i++) {
if (getParentTransaction().getOutputs().get(i) == this)
return i;
}
throw new IllegalStateException("Output linked to wrong parent transaction?");
}
/**
* <p>Gets the minimum value for a txout of this size to be considered non-dust by a reference client
* (and thus relayed). See: CTxOut::IsDust() in the reference client. The assumption is that any output that would
* consume more than a third of its value in fees is not something the Bitcoin system wants to deal with right now,
* so we call them "dust outputs" and they're made non standard. The choice of one third is somewhat arbitrary and
* may change in future.</p>
*
* <p>You probably should use {@link org.bitcoinj.core.TransactionOutput#getMinNonDustValue()} which uses
* a safe fee-per-kb by default.</p>
*
* @param feePerKbRequired The fee required per kilobyte. Note that this is the same as the reference client's -minrelaytxfee * 3
* If you want a safe default, use {@link Transaction#REFERENCE_DEFAULT_MIN_TX_FEE}*3
*/
public Coin getMinNonDustValue(Coin feePerKbRequired) {
// A typical output is 33 bytes (pubkey hash + opcodes) and requires an input of 148 bytes to spend so we add
// that together to find out the total amount of data used to transfer this amount of value. Note that this
// formula is wrong for anything that's not a pay-to-address output, unfortunately, we must follow the reference
// clients wrongness in order to ensure we're considered standard. A better formula would either estimate the
// size of data needed to satisfy all different script types, or just hard code 33 below.
final long size = this.bitcoinSerialize().length + 148;
Coin[] nonDustAndRemainder = feePerKbRequired.multiply(size).divideAndRemainder(1000);
return nonDustAndRemainder[1].equals(Coin.ZERO) ? nonDustAndRemainder[0] : nonDustAndRemainder[0].add(Coin.SATOSHI);
}
/**
* Returns the minimum value for this output to be considered "not dust", i.e. the transaction will be relayable
* and mined by default miners. For normal pay to address outputs, this is 546 satoshis, the same as
* {@link Transaction#MIN_NONDUST_OUTPUT}.
*/
public Coin getMinNonDustValue() {
return getMinNonDustValue(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(3));
}
/**
* Sets this objects availableForSpending flag to false and the spentBy pointer to the given input.
* If the input is null, it means this output was signed over to somebody else rather than one of our own keys.
* @throws IllegalStateException if the transaction was already marked as spent.
*/
public void markAsSpent(TransactionInput input) {
checkState(availableForSpending);
availableForSpending = false;
spentBy = input;
if (parent != null)
if (log.isDebugEnabled()) log.debug("Marked {}:{} as spent by {}", getParentTransaction().getHash(), getIndex(), input);
else
if (log.isDebugEnabled()) log.debug("Marked floating output as spent by {}", input);
}
/**
* Resets the spent pointer / availableForSpending flag to null.
*/
public void markAsUnspent() {
if (parent != null)
if (log.isDebugEnabled()) log.debug("Un-marked {}:{} as spent by {}", getParentTransaction().getHash(), getIndex(), spentBy);
else
if (log.isDebugEnabled()) log.debug("Un-marked floating output as spent by {}", spentBy);
availableForSpending = true;
spentBy = null;
}
/**
* Returns whether {@link TransactionOutput#markAsSpent(TransactionInput)} has been called on this class. A
* {@link Wallet} will mark a transaction output as spent once it sees a transaction input that is connected to it.
* Note that this flag can be false when an output has in fact been spent according to the rest of the network if
* the spending transaction wasn't downloaded yet, and it can be marked as spent when in reality the rest of the
* network believes it to be unspent if the signature or script connecting to it was not actually valid.
*/
public boolean isAvailableForSpending() {
return availableForSpending;
}
/**
* The backing script bytes which can be turned into a Script object.
* @return the scriptBytes
*/
public byte[] getScriptBytes() {
maybeParse();
return scriptBytes;
}
/**
* Returns true if this output is to a key in the wallet or to an address/script we are watching.
*/
public boolean isMineOrWatched(TransactionBag transactionBag) {
return isMine(transactionBag) || isWatched(transactionBag);
}
/**
* Returns true if this output is to a key, or an address we have the keys for, in the wallet.
*/
public boolean isWatched(TransactionBag transactionBag) {
try {
Script script = getScriptPubKey();
return transactionBag.isWatchedScript(script);
} catch (ScriptException e) {
// Just means we didn't understand the output of this transaction: ignore it.
log.debug("Could not parse tx output script: {}", e.toString());
return false;
}
}
/**
* Returns true if this output is to a key, or an address we have the keys for, in the wallet.
*/
public boolean isMine(TransactionBag transactionBag) {
try {
Script script = getScriptPubKey();
if (script.isSentToRawPubKey()) {
byte[] pubkey = script.getPubKey();
return transactionBag.isPubKeyMine(pubkey);
} if (script.isPayToScriptHash()) {
return transactionBag.isPayToScriptHashMine(script.getPubKeyHash());
} else {
byte[] pubkeyHash = script.getPubKeyHash();
return transactionBag.isPubKeyHashMine(pubkeyHash);
}
} catch (ScriptException e) {
// Just means we didn't understand the output of this transaction: ignore it.
log.debug("Could not parse tx output script: {}", e.toString());
return false;
}
}
/**
* Returns a human readable debug string.
*/
@Override
public String toString() {
try {
Script script = getScriptPubKey();
StringBuilder buf = new StringBuilder("TxOut of ");
buf.append(Coin.valueOf(value).toFriendlyString());
if (script.isSentToAddress() || script.isPayToScriptHash())
buf.append(" to ").append(script.getToAddress(params));
else if (script.isSentToRawPubKey())
buf.append(" to pubkey ").append(Utils.HEX.encode(script.getPubKey()));
else if (script.isSentToMultiSig())
buf.append(" to multisig");
else
buf.append(" (unknown type)");
buf.append(" script:");
buf.append(script);
return buf.toString();
} catch (ScriptException e) {
throw new RuntimeException(e);
}
}
/**
* Returns the connected input.
*/
@Nullable
public TransactionInput getSpentBy() {
return spentBy;
}
/**
* Returns the transaction that owns this output.
*/
@Nullable
public Transaction getParentTransaction() {
if(parent != null) {
return (Transaction) parent;
}
return null;
}
/**
* Returns the transaction hash that owns this output.
*/
@Nullable
public Sha256Hash getParentTransactionHash() {
if (getParentTransaction() != null) {
return getParentTransaction().getHash();
}
return null;
}
/**
* Returns the depth in blocks of the parent tx.
*
* <p>If the transaction appears in the top block, the depth is one. If it's anything else (pending, dead, unknown)
* then -1.</p>
* @return The tx depth or -1.
*/
public int getParentTransactionDepthInBlocks() {
if (getParentTransaction() != null) {
TransactionConfidence confidence = getParentTransaction().getConfidence();
if (confidence.getConfidenceType() == TransactionConfidence.ConfidenceType.BUILDING) {
return confidence.getDepthInBlocks();
}
}
return -1;
}
/**
* Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
maybeParse();
out.defaultWriteObject();
}
/**
* Returns a new {@link TransactionOutPoint}, which is essentially a structure pointing to this output.
* Requires that this output is not detached.
*/
public TransactionOutPoint getOutPointFor() {
return new TransactionOutPoint(params, getIndex(), getParentTransaction());
}
/** Returns a copy of the output detached from its containing transaction, if need be. */
public TransactionOutput duplicateDetached() {
return new TransactionOutput(params, null, Coin.valueOf(value), org.spongycastle.util.Arrays.clone(scriptBytes));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TransactionOutput other = (TransactionOutput) o;
if (!Arrays.equals(scriptBytes, other.scriptBytes)) return false;
if (value != other.value) return false;
if (parent != null && parent != other.parent) return false;
return true;
}
@Override
public int hashCode() {
return 31 * (int) value + (scriptBytes != null ? Arrays.hashCode(scriptBytes) : 0);
}
}

View File

@@ -1,77 +0,0 @@
/**
* Copyright 2012 Matt Corallo.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;
/**
* <p>TransactionOutputChanges represents a delta to the set of unspent outputs. It used as a return value for
* {@link AbstractBlockChain#connectTransactions(int, Block)}. It contains the full list of transaction outputs created
* and spent in a block. It DOES contain outputs created that were spent later in the block, as those are needed for
* BIP30 (no duplicate txid creation if the previous one was not fully spent prior to this block) verification.</p>
*/
public class TransactionOutputChanges {
public final List<UTXO> txOutsCreated;
public final List<UTXO> txOutsSpent;
public TransactionOutputChanges(List<UTXO> txOutsCreated, List<UTXO> txOutsSpent) {
this.txOutsCreated = txOutsCreated;
this.txOutsSpent = txOutsSpent;
}
public TransactionOutputChanges(InputStream in) throws IOException {
int numOutsCreated = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
txOutsCreated = new LinkedList<UTXO>();
for (int i = 0; i < numOutsCreated; i++)
txOutsCreated.add(new UTXO(in));
int numOutsSpent = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
txOutsSpent = new LinkedList<UTXO>();
for (int i = 0; i < numOutsSpent; i++)
txOutsSpent.add(new UTXO(in));
}
public void serializeToStream(OutputStream bos) throws IOException {
int numOutsCreated = txOutsCreated.size();
bos.write(0xFF & (numOutsCreated >> 0));
bos.write(0xFF & (numOutsCreated >> 8));
bos.write(0xFF & (numOutsCreated >> 16));
bos.write(0xFF & (numOutsCreated >> 24));
for (UTXO output : txOutsCreated) {
output.serializeToStream(bos);
}
int numOutsSpent = txOutsSpent.size();
bos.write(0xFF & (numOutsSpent >> 0));
bos.write(0xFF & (numOutsSpent >> 8));
bos.write(0xFF & (numOutsSpent >> 16));
bos.write(0xFF & (numOutsSpent >> 24));
for (UTXO output : txOutsSpent) {
output.serializeToStream(bos);
}
}
}

View File

@@ -1,318 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.utils.Threading;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
/**
* <p>Tracks transactions that are being announced across the network. Typically one is created for you by a
* {@link PeerGroup} and then given to each Peer to update. The current purpose is to let Peers update the confidence
* (number of peers broadcasting). It helps address an attack scenario in which a malicious remote peer (or several)
* feeds you invalid transactions, eg, ones that spend coins which don't exist. If you don't see most of the peers
* announce the transaction within a reasonable time, it may be that the TX is not valid. Alternatively, an attacker
* may control your entire internet connection: in this scenario counting broadcasting peers does not help you.</p>
*
* <p>It is <b>not</b> at this time directly equivalent to the Satoshi clients memory pool, which tracks
* all transactions not currently included in the best chain - it's simply a cache.</p>
*/
public class TxConfidenceTable {
private static final Logger log = LoggerFactory.getLogger(TxConfidenceTable.class);
protected ReentrantLock lock = Threading.lock("txconfidencetable");
// For each transaction we may have seen:
// - only its hash in an inv packet
// - the full transaction itself, if we asked for it to be sent to us (or a peer sent it regardless), or if we
// sent it.
//
// Before we see the full transaction, we need to track how many peers advertised it, so we can estimate its
// confidence pre-chain inclusion assuming an un-tampered with network connection. After we see the full transaction
// we need to switch from tracking that data in the Entry to tracking it in the TransactionConfidence object itself.
private static class WeakTransactionReference extends WeakReference<Transaction> {
public Sha256Hash hash;
public WeakTransactionReference(Transaction tx, ReferenceQueue<Transaction> queue) {
super(tx, queue);
hash = tx.getHash();
}
}
private static class Entry {
// Invariants: one of the two fields must be null, to indicate which is used.
Set<PeerAddress> addresses;
// We keep a weak reference to the transaction. This means that if no other bit of code finds the transaction
// worth keeping around it will drop out of memory and we will, at some point, forget about it, which means
// both addresses and tx.get() will be null. When this happens the WeakTransactionReference appears in the queue
// allowing us to delete the associated entry (the tx itself has already gone away).
WeakTransactionReference tx;
}
private LinkedHashMap<Sha256Hash, Entry> table;
// This ReferenceQueue gets entries added to it when they are only weakly reachable, ie, the TxConfidenceTable is the
// only thing that is tracking the transaction anymore. We check it from time to time and delete table entries
// corresponding to expired transactions. In this way memory usage of the system is in line with however many
// transactions you actually care to track the confidence of. We can still end up with lots of hashes being stored
// if our peers flood us with invs but the MAX_SIZE param caps this.
private ReferenceQueue<Transaction> referenceQueue;
/** The max size of a table created with the no-args constructor. */
public static final int MAX_SIZE = 1000;
/**
* Creates a table that will track at most the given number of transactions (allowing you to bound memory
* usage).
* @param size Max number of transactions to track. The table will fill up to this size then stop growing.
*/
public TxConfidenceTable(final int size) {
table = new LinkedHashMap<Sha256Hash, Entry>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Sha256Hash, TxConfidenceTable.Entry> entry) {
// An arbitrary choice to stop the memory used by tracked transactions getting too huge in the event
// of some kind of DoS attack.
return size() > size;
}
};
referenceQueue = new ReferenceQueue<Transaction>();
}
/**
* Creates a table that will track at most {@link TxConfidenceTable#MAX_SIZE} entries. You should normally use
* this constructor.
*/
public TxConfidenceTable() {
this(MAX_SIZE);
}
/**
* If any transactions have expired due to being only weakly reachable through us, go ahead and delete their
* table entries - it means we downloaded the transaction and sent it to various event listeners, none of
* which bothered to keep a reference. Typically, this is because the transaction does not involve any keys that
* are relevant to any of our wallets.
*/
private void cleanTable() {
lock.lock();
try {
Reference<? extends Transaction> ref;
while ((ref = referenceQueue.poll()) != null) {
// Find which transaction got deleted by the GC.
WeakTransactionReference txRef = (WeakTransactionReference) ref;
// And remove the associated map entry so the other bits of memory can also be reclaimed.
table.remove(txRef.hash);
}
} finally {
lock.unlock();
}
}
/**
* Returns the number of peers that have seen the given hash recently.
*/
public int numBroadcastPeers(Sha256Hash txHash) {
lock.lock();
try {
cleanTable();
Entry entry = table.get(txHash);
if (entry == null) {
// No such TX known.
return 0;
} else if (entry.tx == null) {
// We've seen at least one peer announce with an inv.
checkNotNull(entry.addresses);
return entry.addresses.size();
} else {
final Transaction tx = entry.tx.get();
if (tx == null) {
// We previously downloaded this transaction, but nothing cared about it so the garbage collector threw
// it away. We also deleted the set that tracked which peers had seen it. Treat this case as a zero and
// just delete it from the map.
table.remove(txHash);
return 0;
} else {
checkState(entry.addresses == null);
return tx.getConfidence().numBroadcastPeers();
}
}
} finally {
lock.unlock();
}
}
/**
* Puts the tx into the table and returns either it, or a different Transaction object that has the same hash.
* Unlike seen and the other methods, this one does not imply that a tx has been announced by a peer and does
* not mark it as such.
*/
public Transaction intern(Transaction tx) {
lock.lock();
try {
cleanTable();
Entry entry = table.get(tx.getHash());
if (entry != null) {
// This TX or its hash have been previously interned.
if (entry.tx != null) {
// We already interned it (but may have thrown it away).
checkState(entry.addresses == null);
// We only want one canonical object instance for a transaction no matter how many times it is
// deserialized.
Transaction transaction = entry.tx.get();
if (transaction != null) {
// We saw it before and kept it around. Hand back the canonical copy.
tx = transaction;
}
return tx;
} else {
// We received a transaction that we have previously seen announced but not downloaded until now.
checkNotNull(entry.addresses);
entry.tx = new WeakTransactionReference(tx, referenceQueue);
Set<PeerAddress> addrs = entry.addresses;
entry.addresses = null;
TransactionConfidence confidence = tx.getConfidence();
log.debug("Adding tx [{}] {} to the confidence table",
confidence.numBroadcastPeers(), tx.getHashAsString());
for (PeerAddress a : addrs) {
markBroadcast(a, tx);
}
return tx;
}
} else {
// This often happens when we are downloading a Bloom filtered chain, or recursively downloading
// dependencies of a relevant transaction (see Peer.downloadDependencies).
log.debug("Provided with a downloaded transaction we didn't see announced yet: {}", tx.getHashAsString());
entry = new Entry();
entry.tx = new WeakTransactionReference(tx, referenceQueue);
table.put(tx.getHash(), entry);
return tx;
}
} finally {
lock.unlock();
}
}
/**
* Called by peers when they receive a "tx" message containing a valid serialized transaction.
* @param tx The TX deserialized from the wire.
* @param byPeer The Peer that received it.
* @return An object that is semantically the same TX but may be a different object instance.
*/
public Transaction seen(Transaction tx, PeerAddress byPeer) {
lock.lock();
try {
final Transaction interned = intern(tx);
markBroadcast(byPeer, interned);
return interned;
} finally {
lock.unlock();
}
}
/**
* Called by peers when they see a transaction advertised in an "inv" message. It either will increase the
* confidence of the pre-existing transaction or will just keep a record of the address for future usage.
*/
public void seen(Sha256Hash hash, PeerAddress byPeer) {
lock.lock();
try {
cleanTable();
Entry entry = table.get(hash);
if (entry != null) {
// This TX or its hash have been previously announced.
if (entry.tx != null) {
checkState(entry.addresses == null);
Transaction tx = entry.tx.get();
if (tx != null) {
markBroadcast(byPeer, tx);
log.debug("{}: Peer announced transaction we have seen before [{}] {}",
byPeer, tx.getConfidence().numBroadcastPeers(), tx.getHashAsString());
} else {
// The inv is telling us about a transaction that we previously downloaded, and threw away
// because nothing found it interesting enough to keep around. So do nothing.
}
} else {
checkNotNull(entry.addresses);
entry.addresses.add(byPeer);
log.debug("{}: Peer announced transaction we have seen announced before [{}] {}",
byPeer, entry.addresses.size(), hash);
}
} else {
// This TX has never been seen before.
entry = new Entry();
// TODO: Using hashsets here is inefficient compared to just having an array.
entry.addresses = new HashSet<PeerAddress>();
entry.addresses.add(byPeer);
table.put(hash, entry);
log.info("{}: Peer announced new transaction [1] {}", byPeer, hash);
}
} finally {
lock.unlock();
}
}
private void markBroadcast(PeerAddress byPeer, Transaction tx) {
checkState(lock.isHeldByCurrentThread());
final TransactionConfidence confidence = tx.getConfidence();
if (confidence.markBroadcastBy(byPeer))
confidence.queueListeners(TransactionConfidence.Listener.ChangeReason.SEEN_PEERS);
}
/**
* Returns the {@link Transaction} for the given hash if we have downloaded it, or null if that hash is unknown or
* we only saw advertisements for it yet or it has been downloaded but garbage collected due to nowhere else
* holding a reference to it.
*/
@Nullable
public Transaction get(Sha256Hash hash) {
lock.lock();
try {
Entry entry = table.get(hash);
if (entry == null) return null; // Unknown.
if (entry.tx == null) return null; // Seen but only in advertisements.
if (entry.tx.get() == null) return null; // Was downloaded but garbage collected.
Transaction tx = entry.tx.get();
checkNotNull(tx);
return tx;
} finally {
lock.unlock();
}
}
/**
* Returns true if the TX identified by hash has been seen before (ie, in an inv). Note that a transaction that
* was broadcast, downloaded and nothing kept a reference to it will eventually be cleared out by the garbage
* collector and wasSeen() will return false - it does not keep a permanent record of every hash ever broadcast.
*/
public boolean maybeWasSeen(Sha256Hash hash) {
lock.lock();
try {
Entry entry = table.get(hash);
return entry != null;
} finally {
lock.unlock();
}
}
}

View File

@@ -1,249 +0,0 @@
/**
* Copyright 2012 Matt Corallo.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigInteger;
/**
* A UTXO message contains the information necessary to check a spending transaction.
* It avoids having to store the entire parentTransaction just to get the hash and index.
* Useful when working with free standing outputs.
*/
public class UTXO implements Serializable {
private static final Logger log = LoggerFactory.getLogger(UTXO.class);
private static final long serialVersionUID = -8744924157056340509L;
/**
* A transaction output has some value and a script used for authenticating that the redeemer is allowed to spend
* this output.
*/
private Coin value;
private byte[] scriptBytes;
/** Hash of the transaction to which we refer. */
private Sha256Hash hash;
/** Which output of that transaction we are talking about. */
private long index;
/** The height of the tx of this output */
private int height;
/** If this output is from a coinbase tx */
private boolean coinbase;
/** The address of this output */
private String address;
/** The type of this address */
private int addressType;
/**
* Creates a stored transaction output.
* @param hash The hash of the containing transaction.
* @param index The outpoint.
* @param value The value available.
* @param height The height this output was created in.
* @param coinbase The coinbase flag.
* @param scriptBytes The script bytes.
*/
public UTXO(Sha256Hash hash,
long index,
Coin value,
int height,
boolean coinbase,
byte[] scriptBytes) {
this.hash = hash;
this.index = index;
this.value = value;
this.height = height;
this.scriptBytes = scriptBytes;
this.coinbase = coinbase;
this.address = "";
this.addressType = 0;
}
/**
* Creates a stored transaction output.
* @param hash The hash of the containing transaction.
* @param index The outpoint.
* @param value The value available.
* @param height The height this output was created in.
* @param coinbase The coinbase flag.
* @param scriptBytes The script bytes.
* @param address The address.
* @param addressType The address type.
*/
public UTXO(Sha256Hash hash,
long index,
Coin value,
int height,
boolean coinbase,
byte[] scriptBytes,
String address,
int addressType) {
this(hash, index, value, height, coinbase, scriptBytes);
this.address = address;
this.addressType = addressType;
}
public UTXO(InputStream in) throws IOException {
byte[] valueBytes = new byte[8];
if (in.read(valueBytes, 0, 8) != 8)
throw new EOFException();
value = Coin.valueOf(Utils.readInt64(valueBytes, 0));
int scriptBytesLength = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
scriptBytes = new byte[scriptBytesLength];
if (in.read(scriptBytes) != scriptBytesLength)
throw new EOFException();
byte[] hashBytes = new byte[32];
if (in.read(hashBytes) != 32)
throw new EOFException();
hash = new Sha256Hash(hashBytes);
byte[] indexBytes = new byte[4];
if (in.read(indexBytes) != 4)
throw new EOFException();
index = Utils.readUint32(indexBytes, 0);
height = ((in.read() & 0xFF) << 0) |
((in.read() & 0xFF) << 8) |
((in.read() & 0xFF) << 16) |
((in.read() & 0xFF) << 24);
byte[] coinbaseByte = new byte[1];
in.read(coinbaseByte);
if (coinbaseByte[0] == 1) {
coinbase = true;
} else {
coinbase = false;
}
}
/**
* The value which this Transaction output holds.
* @return the value.
*/
public Coin getValue() {
return value;
}
/**
* The backing script bytes which can be turned into a Script object.
* @return the scriptBytes.
*/
public byte[] getScriptBytes() {
return scriptBytes;
}
/**
* The hash of the transaction which holds this output.
* @return the hash.
*/
public Sha256Hash getHash() {
return hash;
}
/**
* The index of this output in the transaction which holds it.
* @return the index.
*/
public long getIndex() {
return index;
}
/**
* Gets the height of the block that created this output.
* @return The height.
*/
public int getHeight() {
return height;
}
/**
* Gets the flag of whether this was created by a coinbase tx.
* @return The coinbase flag.
*/
public boolean isCoinbase() {
return coinbase;
}
/**
* The address of this output.
* @return The address.
*/
public String getAddress() {
return address;
}
/**
* The type of the address.
* @return The address type.
*/
public int getAddressType() {
return addressType;
}
@Override
public String toString() {
return String.format("Stored TxOut of %s (%s:%d)", value.toFriendlyString(), hash.toString(), index);
}
@Override
public int hashCode() {
return hash.hashCode() + (int)index;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UTXO other = (UTXO) o;
return getHash().equals(other.getHash()) &&
getIndex() == other.getIndex();
}
public void serializeToStream(OutputStream bos) throws IOException {
Utils.uint64ToByteStreamLE(BigInteger.valueOf(value.value), bos);
bos.write(0xFF & scriptBytes.length >> 0);
bos.write(0xFF & scriptBytes.length >> 8);
bos.write(0xFF & (scriptBytes.length >> 16));
bos.write(0xFF & (scriptBytes.length >> 24));
bos.write(scriptBytes);
bos.write(hash.getBytes());
Utils.uint32ToByteStreamLE(index, bos);
bos.write(0xFF & (height >> 0));
bos.write(0xFF & (height >> 8));
bos.write(0xFF & (height >> 16));
bos.write(0xFF & (height >> 24));
byte[] coinbaseByte = new byte[1];
if(coinbase) {
coinbaseByte[0] = 1;
} else {
coinbaseByte[0] = 0;
}
bos.write(coinbaseByte);
}
}

View File

@@ -1,49 +0,0 @@
/**
* Copyright 2014 Kalpesh Parmar.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.util.List;
/**
* A UTXOProvider encapsulates functionality for returning unspent transaction outputs,
* for use by the wallet or other code that crafts spends.
*
* <p>A {@link org.bitcoinj.store.FullPrunedBlockStore} is an internal implementation within bitcoinj.</p>
*/
public interface UTXOProvider {
/**
* // TODO currently the access to outputs is by address. Change to ECKey
* Get the list of {@link UTXO}'s for a given address.
* @param addresses List of address.
* @return The list of transaction outputs.
* @throws UTXOProvider If there is an error.
*/
List<UTXO> getOpenTransactionOutputs(List<Address> addresses) throws UTXOProviderException;
/**
* Get the height of the chain head.
* @return The chain head height.
* @throws UTXOProvider If there is an error.
*/
int getChainHeadHeight() throws UTXOProviderException;
/**
* The {@link NetworkParameters} of this provider.
* @return The network parameters.
*/
NetworkParameters getParams();
}

View File

@@ -1,34 +0,0 @@
/**
* Copyright 2014 Kalpesh Parmar.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
public class UTXOProviderException extends Exception {
public UTXOProviderException() {
super();
}
public UTXOProviderException(String message) {
super(message);
}
public UTXOProviderException(String message, Throwable cause) {
super(message, cause);
}
public UTXOProviderException(Throwable cause) {
super(cause);
}
}

View File

@@ -1,161 +0,0 @@
/*
* Copyright 2014 the bitcoinj authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** Message representing a list of unspent transaction outputs, returned in response to sending a GetUTXOsMessage. */
public class UTXOsMessage extends Message {
private long height;
private Sha256Hash chainHead;
private byte[] hits; // little-endian bitset indicating whether an output was found or not.
private List<TransactionOutput> outputs;
private long[] heights;
/** This is a special sentinel value that can appear in the heights field if the given tx is in the mempool. */
public static long MEMPOOL_HEIGHT = 0x7FFFFFFFL;
public UTXOsMessage(NetworkParameters params, byte[] payloadBytes) {
super(params, payloadBytes, 0);
}
/**
* Provide an array of output objects, with nulls indicating that the output was missing. The bitset will
* be calculated from this.
*/
public UTXOsMessage(NetworkParameters params, List<TransactionOutput> outputs, long[] heights, Sha256Hash chainHead, long height) {
super(params);
hits = new byte[(int) Math.ceil(outputs.size() / 8.0)];
for (int i = 0; i < outputs.size(); i++) {
if (outputs.get(i) != null)
Utils.setBitLE(hits, i);
}
this.outputs = new ArrayList<TransactionOutput>(outputs.size());
for (TransactionOutput output : outputs) {
if (output != null) this.outputs.add(output);
}
this.chainHead = chainHead;
this.height = height;
this.heights = Arrays.copyOf(heights, heights.length);
}
@Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException {
Utils.uint32ToByteStreamLE(height, stream);
stream.write(chainHead.getBytes());
stream.write(new VarInt(hits.length).encode());
stream.write(hits);
stream.write(new VarInt(outputs.size()).encode());
for (TransactionOutput output : outputs) {
// TODO: Allow these to be specified, if one day we care about sending this message ourselves
// (currently it's just used for unit testing).
Utils.uint32ToByteStreamLE(0L, stream); // Version
Utils.uint32ToByteStreamLE(0L, stream); // Height
output.bitcoinSerializeToStream(stream);
}
}
@Override
void parse() throws ProtocolException {
// Format is:
// uint32 chainHeight
// uint256 chainHeadHash
// vector<unsigned char> hitsBitmap;
// vector<CCoin> outs;
//
// A CCoin is { int nVersion, int nHeight, CTxOut output }
// The bitmap indicates which of the requested TXOs were found in the UTXO set.
height = readUint32();
chainHead = readHash();
int numBytes = (int) readVarInt();
if (numBytes < 0 || numBytes > InventoryMessage.MAX_INVENTORY_ITEMS / 8)
throw new ProtocolException("hitsBitmap out of range: " + numBytes);
hits = readBytes(numBytes);
int numOuts = (int) readVarInt();
if (numOuts < 0 || numOuts > InventoryMessage.MAX_INVENTORY_ITEMS)
throw new ProtocolException("numOuts out of range: " + numOuts);
outputs = new ArrayList<TransactionOutput>(numOuts);
heights = new long[numOuts];
for (int i = 0; i < numOuts; i++) {
long version = readUint32();
long height = readUint32();
if (version > 1)
throw new ProtocolException("Unknown tx version in getutxo output: " + version);
TransactionOutput output = new TransactionOutput(params, null, payload, cursor);
outputs.add(output);
heights[i] = height;
cursor += output.length;
}
length = cursor;
}
@Override
protected void parseLite() throws ProtocolException {
// Not used.
}
public byte[] getHitMap() {
return Arrays.copyOf(hits, hits.length);
}
public List<TransactionOutput> getOutputs() {
return new ArrayList<TransactionOutput>(outputs);
}
public long[] getHeights() { return Arrays.copyOf(heights, heights.length); }
@Override
public String toString() {
return "UTXOsMessage{" +
"height=" + height +
", chainHead=" + chainHead +
", hitMap=" + Arrays.toString(hits) +
", outputs=" + outputs +
", heights=" + Arrays.toString(heights) +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UTXOsMessage message = (UTXOsMessage) o;
if (height != message.height) return false;
if (!chainHead.equals(message.chainHead)) return false;
if (!Arrays.equals(heights, message.heights)) return false;
if (!Arrays.equals(hits, message.hits)) return false;
if (!outputs.equals(message.outputs)) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (height ^ (height >>> 32));
result = 31 * result + chainHead.hashCode();
result = 31 * result + Arrays.hashCode(hits);
result = 31 * result + outputs.hashCode();
result = 31 * result + Arrays.hashCode(heights);
return result;
}
}

View File

@@ -1,33 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
public class UnknownMessage extends EmptyMessage {
private static final long serialVersionUID = 3614705938207918775L;
private String name;
public UnknownMessage(NetworkParameters params, String name, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0);
this.name = name;
}
@Override
public String toString() {
return "Unknown message [" + name + "]: " + (payload == null ? "" : Utils.HEX.encode(payload));
}
}

View File

@@ -1,132 +0,0 @@
/**
* Copyright 2011 Steve Coughlan.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* An unsynchronized implementation of ByteArrayOutputStream that will return the backing byte array if its length == size().
* This avoids unneeded array copy where the BOS is simply being used to extract a byte array of known length from a
* 'serialized to stream' method.
* <p/>
* Unless the final length can be accurately predicted the only performance this will yield is due to unsynchronized
* methods.
*
* @author git
*/
public class UnsafeByteArrayOutputStream extends ByteArrayOutputStream {
public UnsafeByteArrayOutputStream() {
super(32);
}
public UnsafeByteArrayOutputStream(int size) {
super(size);
}
/**
* Writes the specified byte to this byte array output stream.
*
* @param b the byte to be written.
*/
@Override
public void write(int b) {
int newcount = count + 1;
if (newcount > buf.length) {
buf = Utils.copyOf(buf, Math.max(buf.length << 1, newcount));
}
buf[count] = (byte) b;
count = newcount;
}
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this byte array output stream.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
@Override
public void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
int newcount = count + len;
if (newcount > buf.length) {
buf = Utils.copyOf(buf, Math.max(buf.length << 1, newcount));
}
System.arraycopy(b, off, buf, count, len);
count = newcount;
}
/**
* Writes the complete contents of this byte array output stream to
* the specified output stream argument, as if by calling the output
* stream's write method using <code>out.write(buf, 0, count)</code>.
*
* @param out the output stream to which to write the data.
* @throws IOException if an I/O error occurs.
*/
@Override
public void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}
/**
* Resets the <code>count</code> field of this byte array output
* stream to zero, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space.
*
* @see java.io.ByteArrayInputStream#count
*/
@Override
public void reset() {
count = 0;
}
/**
* Creates a newly allocated byte array. Its size is the current
* size of this output stream and the valid contents of the buffer
* have been copied into it.
*
* @return the current contents of this output stream, as a byte array.
* @see java.io.ByteArrayOutputStream#size()
*/
@Override
public byte toByteArray()[] {
return count == buf.length ? buf : Utils.copyOf(buf, count);
}
/**
* Returns the current size of the buffer.
*
* @return the value of the <code>count</code> field, which is the number
* of valid bytes in this output stream.
* @see java.io.ByteArrayOutputStream#count
*/
@Override
public int size() {
return count;
}
}

View File

@@ -1,648 +0,0 @@
/**
* Copyright 2011 Google Inc.
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.common.io.BaseEncoding;
import com.google.common.io.Resources;
import com.google.common.primitives.Ints;
import com.google.common.primitives.UnsignedLongs;
import org.spongycastle.crypto.digests.RIPEMD160Digest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
/**
* A collection of various utility methods that are helpful for working with the Bitcoin protocol.
* To enable debug logging from the library, run with -Dbitcoinj.logging=true on your command line.
*/
public class Utils {
private static final MessageDigest digest;
static {
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Can't happen.
}
}
/** The string that prefixes all text messages signed using Bitcoin keys. */
public static final String BITCOIN_SIGNED_MESSAGE_HEADER = "Bitcoin Signed Message:\n";
public static final byte[] BITCOIN_SIGNED_MESSAGE_HEADER_BYTES = BITCOIN_SIGNED_MESSAGE_HEADER.getBytes(Charsets.UTF_8);
private static BlockingQueue<Boolean> mockSleepQueue;
/**
* The regular {@link java.math.BigInteger#toByteArray()} method isn't quite what we often need: it appends a
* leading zero to indicate that the number is positive and may need padding.
*
* @param b the integer to format into a byte array
* @param numBytes the desired size of the resulting byte array
* @return numBytes byte long array.
*/
public static byte[] bigIntegerToBytes(BigInteger b, int numBytes) {
if (b == null) {
return null;
}
byte[] bytes = new byte[numBytes];
byte[] biBytes = b.toByteArray();
int start = (biBytes.length == numBytes + 1) ? 1 : 0;
int length = Math.min(biBytes.length, numBytes);
System.arraycopy(biBytes, start, bytes, numBytes - length, length);
return bytes;
}
public static void uint32ToByteArrayBE(long val, byte[] out, int offset) {
out[offset + 0] = (byte) (0xFF & (val >> 24));
out[offset + 1] = (byte) (0xFF & (val >> 16));
out[offset + 2] = (byte) (0xFF & (val >> 8));
out[offset + 3] = (byte) (0xFF & (val >> 0));
}
public static void uint32ToByteArrayLE(long val, byte[] out, int offset) {
out[offset + 0] = (byte) (0xFF & (val >> 0));
out[offset + 1] = (byte) (0xFF & (val >> 8));
out[offset + 2] = (byte) (0xFF & (val >> 16));
out[offset + 3] = (byte) (0xFF & (val >> 24));
}
public static void uint64ToByteArrayLE(long val, byte[] out, int offset) {
out[offset + 0] = (byte) (0xFF & (val >> 0));
out[offset + 1] = (byte) (0xFF & (val >> 8));
out[offset + 2] = (byte) (0xFF & (val >> 16));
out[offset + 3] = (byte) (0xFF & (val >> 24));
out[offset + 4] = (byte) (0xFF & (val >> 32));
out[offset + 5] = (byte) (0xFF & (val >> 40));
out[offset + 6] = (byte) (0xFF & (val >> 48));
out[offset + 7] = (byte) (0xFF & (val >> 56));
}
public static void uint32ToByteStreamLE(long val, OutputStream stream) throws IOException {
stream.write((int) (0xFF & (val >> 0)));
stream.write((int) (0xFF & (val >> 8)));
stream.write((int) (0xFF & (val >> 16)));
stream.write((int) (0xFF & (val >> 24)));
}
public static void int64ToByteStreamLE(long val, OutputStream stream) throws IOException {
stream.write((int) (0xFF & (val >> 0)));
stream.write((int) (0xFF & (val >> 8)));
stream.write((int) (0xFF & (val >> 16)));
stream.write((int) (0xFF & (val >> 24)));
stream.write((int) (0xFF & (val >> 32)));
stream.write((int) (0xFF & (val >> 40)));
stream.write((int) (0xFF & (val >> 48)));
stream.write((int) (0xFF & (val >> 56)));
}
public static void uint64ToByteStreamLE(BigInteger val, OutputStream stream) throws IOException {
byte[] bytes = val.toByteArray();
if (bytes.length > 8) {
throw new RuntimeException("Input too large to encode into a uint64");
}
bytes = reverseBytes(bytes);
stream.write(bytes);
if (bytes.length < 8) {
for (int i = 0; i < 8 - bytes.length; i++)
stream.write(0);
}
}
/**
* See {@link Utils#doubleDigest(byte[], int, int)}.
*/
public static byte[] doubleDigest(byte[] input) {
return doubleDigest(input, 0, input.length);
}
/**
* Calculates the SHA-256 hash of the given byte range, and then hashes the resulting hash again. This is
* standard procedure in Bitcoin. The resulting hash is in big endian form.
*/
public static byte[] doubleDigest(byte[] input, int offset, int length) {
synchronized (digest) {
digest.reset();
digest.update(input, offset, length);
byte[] first = digest.digest();
return digest.digest(first);
}
}
public static byte[] singleDigest(byte[] input, int offset, int length) {
synchronized (digest) {
digest.reset();
digest.update(input, offset, length);
return digest.digest();
}
}
/**
* Calculates SHA256(SHA256(byte range 1 + byte range 2)).
*/
public static byte[] doubleDigestTwoBuffers(byte[] input1, int offset1, int length1,
byte[] input2, int offset2, int length2) {
synchronized (digest) {
digest.reset();
digest.update(input1, offset1, length1);
digest.update(input2, offset2, length2);
byte[] first = digest.digest();
return digest.digest(first);
}
}
/**
* Work around lack of unsigned types in Java.
*/
public static boolean isLessThanUnsigned(long n1, long n2) {
return UnsignedLongs.compare(n1, n2) < 0;
}
/**
* Work around lack of unsigned types in Java.
*/
public static boolean isLessThanOrEqualToUnsigned(long n1, long n2) {
return UnsignedLongs.compare(n1, n2) <= 0;
}
/**
* Hex encoding used throughout the framework. Use with HEX.encode(byte[]) or HEX.decode(CharSequence).
*/
public static final BaseEncoding HEX = BaseEncoding.base16().lowerCase();
/**
* Returns a copy of the given byte array in reverse order.
*/
public static byte[] reverseBytes(byte[] bytes) {
// We could use the XOR trick here but it's easier to understand if we don't. If we find this is really a
// performance issue the matter can be revisited.
byte[] buf = new byte[bytes.length];
for (int i = 0; i < bytes.length; i++)
buf[i] = bytes[bytes.length - 1 - i];
return buf;
}
/**
* Returns a copy of the given byte array with the bytes of each double-word (4 bytes) reversed.
*
* @param bytes length must be divisible by 4.
* @param trimLength trim output to this length. If positive, must be divisible by 4.
*/
public static byte[] reverseDwordBytes(byte[] bytes, int trimLength) {
checkArgument(bytes.length % 4 == 0);
checkArgument(trimLength < 0 || trimLength % 4 == 0);
byte[] rev = new byte[trimLength >= 0 && bytes.length > trimLength ? trimLength : bytes.length];
for (int i = 0; i < rev.length; i += 4) {
System.arraycopy(bytes, i, rev, i , 4);
for (int j = 0; j < 4; j++) {
rev[i + j] = bytes[i + 3 - j];
}
}
return rev;
}
public static long readUint32(byte[] bytes, int offset) {
return ((bytes[offset++] & 0xFFL) << 0) |
((bytes[offset++] & 0xFFL) << 8) |
((bytes[offset++] & 0xFFL) << 16) |
((bytes[offset] & 0xFFL) << 24);
}
public static long readInt64(byte[] bytes, int offset) {
return ((bytes[offset++] & 0xFFL) << 0) |
((bytes[offset++] & 0xFFL) << 8) |
((bytes[offset++] & 0xFFL) << 16) |
((bytes[offset++] & 0xFFL) << 24) |
((bytes[offset++] & 0xFFL) << 32) |
((bytes[offset++] & 0xFFL) << 40) |
((bytes[offset++] & 0xFFL) << 48) |
((bytes[offset] & 0xFFL) << 56);
}
public static long readUint32BE(byte[] bytes, int offset) {
return ((bytes[offset + 0] & 0xFFL) << 24) |
((bytes[offset + 1] & 0xFFL) << 16) |
((bytes[offset + 2] & 0xFFL) << 8) |
((bytes[offset + 3] & 0xFFL) << 0);
}
public static int readUint16BE(byte[] bytes, int offset) {
return ((bytes[offset] & 0xff) << 8) | bytes[offset + 1] & 0xff;
}
/**
* Calculates RIPEMD160(SHA256(input)). This is used in Address calculations.
*/
public static byte[] sha256hash160(byte[] input) {
try {
byte[] sha256 = MessageDigest.getInstance("SHA-256").digest(input);
RIPEMD160Digest digest = new RIPEMD160Digest();
digest.update(sha256, 0, sha256.length);
byte[] out = new byte[20];
digest.doFinal(out, 0);
return out;
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
/**
* MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
* a 4 byte big endian length field, followed by the stated number of bytes representing
* the number in big endian format (with a sign bit).
* @param hasLength can be set to false if the given array is missing the 4 byte length field
*/
public static BigInteger decodeMPI(byte[] mpi, boolean hasLength) {
byte[] buf;
if (hasLength) {
int length = (int) readUint32BE(mpi, 0);
buf = new byte[length];
System.arraycopy(mpi, 4, buf, 0, length);
} else
buf = mpi;
if (buf.length == 0)
return BigInteger.ZERO;
boolean isNegative = (buf[0] & 0x80) == 0x80;
if (isNegative)
buf[0] &= 0x7f;
BigInteger result = new BigInteger(buf);
return isNegative ? result.negate() : result;
}
/**
* MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
* a 4 byte big endian length field, followed by the stated number of bytes representing
* the number in big endian format (with a sign bit).
* @param includeLength indicates whether the 4 byte length field should be included
*/
public static byte[] encodeMPI(BigInteger value, boolean includeLength) {
if (value.equals(BigInteger.ZERO)) {
if (!includeLength)
return new byte[] {};
else
return new byte[] {0x00, 0x00, 0x00, 0x00};
}
boolean isNegative = value.signum() < 0;
if (isNegative)
value = value.negate();
byte[] array = value.toByteArray();
int length = array.length;
if ((array[0] & 0x80) == 0x80)
length++;
if (includeLength) {
byte[] result = new byte[length + 4];
System.arraycopy(array, 0, result, length - array.length + 3, array.length);
uint32ToByteArrayBE(length, result, 0);
if (isNegative)
result[4] |= 0x80;
return result;
} else {
byte[] result;
if (length != array.length) {
result = new byte[length];
System.arraycopy(array, 0, result, 1, array.length);
}else
result = array;
if (isNegative)
result[0] |= 0x80;
return result;
}
}
/**
* <p>The "compact" format is a representation of a whole number N using an unsigned 32 bit number similar to a
* floating point format. The most significant 8 bits are the unsigned exponent of base 256. This exponent can
* be thought of as "number of bytes of N". The lower 23 bits are the mantissa. Bit number 24 (0x800000) represents
* the sign of N. Therefore, N = (-1^sign) * mantissa * 256^(exponent-3).</p>
*
* <p>Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn(). MPI uses the most significant bit of the
* first byte as sign. Thus 0x1234560000 is compact 0x05123456 and 0xc0de000000 is compact 0x0600c0de. Compact
* 0x05c0de00 would be -0x40de000000.</p>
*
* <p>Bitcoin only uses this "compact" format for encoding difficulty targets, which are unsigned 256bit quantities.
* Thus, all the complexities of the sign bit and using base 256 are probably an implementation accident.</p>
*/
public static BigInteger decodeCompactBits(long compact) {
int size = ((int) (compact >> 24)) & 0xFF;
byte[] bytes = new byte[4 + size];
bytes[3] = (byte) size;
if (size >= 1) bytes[4] = (byte) ((compact >> 16) & 0xFF);
if (size >= 2) bytes[5] = (byte) ((compact >> 8) & 0xFF);
if (size >= 3) bytes[6] = (byte) ((compact >> 0) & 0xFF);
return decodeMPI(bytes, true);
}
/**
* @see Utils#decodeCompactBits(long)
*/
public static long encodeCompactBits(BigInteger value) {
long result;
int size = value.toByteArray().length;
if (size <= 3)
result = value.longValue() << 8 * (3 - size);
else
result = value.shiftRight(8 * (size - 3)).longValue();
// The 0x00800000 bit denotes the sign.
// Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
if ((result & 0x00800000L) != 0) {
result >>= 8;
size++;
}
result |= size << 24;
result |= value.signum() == -1 ? 0x00800000 : 0;
return result;
}
/**
* If non-null, overrides the return value of now().
*/
public static volatile Date mockTime;
/**
* Advances (or rewinds) the mock clock by the given number of seconds.
*/
public static Date rollMockClock(int seconds) {
return rollMockClockMillis(seconds * 1000);
}
/**
* Advances (or rewinds) the mock clock by the given number of milliseconds.
*/
public static Date rollMockClockMillis(long millis) {
if (mockTime == null)
throw new IllegalStateException("You need to use setMockClock() first.");
mockTime = new Date(mockTime.getTime() + millis);
return mockTime;
}
/**
* Sets the mock clock to the current time.
*/
public static void setMockClock() {
mockTime = new Date();
}
/**
* Sets the mock clock to the given time (in seconds).
*/
public static void setMockClock(long mockClockSeconds) {
mockTime = new Date(mockClockSeconds * 1000);
}
/**
* Returns the current time, or a mocked out equivalent.
*/
public static Date now() {
if (mockTime != null)
return mockTime;
else
return new Date();
}
// TODO: Replace usages of this where the result is / 1000 with currentTimeSeconds.
/** Returns the current time in milliseconds since the epoch, or a mocked out equivalent. */
public static long currentTimeMillis() {
if (mockTime != null)
return mockTime.getTime();
else
return System.currentTimeMillis();
}
public static long currentTimeSeconds() {
return currentTimeMillis() / 1000;
}
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
/**
* Formats a given date+time value to an ISO 8601 string.
* @param dateTime value to format, as a Date
*/
public static String dateTimeFormat(Date dateTime) {
DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
iso8601.setTimeZone(UTC);
return iso8601.format(dateTime);
}
/**
* Formats a given date+time value to an ISO 8601 string.
* @param dateTime value to format, unix time (ms)
*/
public static String dateTimeFormat(long dateTime) {
DateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
iso8601.setTimeZone(UTC);
return iso8601.format(dateTime);
}
public static byte[] copyOf(byte[] in, int length) {
byte[] out = new byte[length];
System.arraycopy(in, 0, out, 0, Math.min(length, in.length));
return out;
}
/**
* Creates a copy of bytes and appends b to the end of it
*/
public static byte[] appendByte(byte[] bytes, byte b) {
byte[] result = Arrays.copyOf(bytes, bytes.length + 1);
result[result.length - 1] = b;
return result;
}
/**
* Attempts to parse the given string as arbitrary-length hex or base58 and then return the results, or null if
* neither parse was successful.
*/
public static byte[] parseAsHexOrBase58(String data) {
try {
return HEX.decode(data);
} catch (Exception e) {
// Didn't decode as hex, try base58.
try {
return Base58.decodeChecked(data);
} catch (AddressFormatException e1) {
return null;
}
}
}
public static boolean isWindows() {
return System.getProperty("os.name").toLowerCase().contains("win");
}
/**
* <p>Given a textual message, returns a byte buffer formatted as follows:</p>
*
* <tt><p>[24] "Bitcoin Signed Message:\n" [message.length as a varint] message</p></tt>
*/
public static byte[] formatMessageForSigning(String message) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bos.write(BITCOIN_SIGNED_MESSAGE_HEADER_BYTES.length);
bos.write(BITCOIN_SIGNED_MESSAGE_HEADER_BYTES);
byte[] messageBytes = message.getBytes(Charsets.UTF_8);
VarInt size = new VarInt(messageBytes.length);
bos.write(size.encode());
bos.write(messageBytes);
return bos.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen.
}
}
// 00000001, 00000010, 00000100, 00001000, ...
private static final int bitMask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
/** Checks if the given bit is set in data, using little endian (not the same as Java native big endian) */
public static boolean checkBitLE(byte[] data, int index) {
return (data[index >>> 3] & bitMask[7 & index]) != 0;
}
/** Sets the given bit in data to one, using little endian (not the same as Java native big endian) */
public static void setBitLE(byte[] data, int index) {
data[index >>> 3] |= bitMask[7 & index];
}
/** Sleep for a span of time, or mock sleep if enabled */
public static void sleep(long millis) {
if (mockSleepQueue == null) {
sleepUninterruptibly(millis, TimeUnit.MILLISECONDS);
} else {
try {
boolean isMultiPass = mockSleepQueue.take();
rollMockClockMillis(millis);
if (isMultiPass)
mockSleepQueue.offer(true);
} catch (InterruptedException e) {
// Ignored.
}
}
}
/** Enable or disable mock sleep. If enabled, set mock time to current time. */
public static void setMockSleep(boolean isEnable) {
if (isEnable) {
mockSleepQueue = new ArrayBlockingQueue<Boolean>(1);
mockTime = new Date(System.currentTimeMillis());
} else {
mockSleepQueue = null;
}
}
/** Let sleeping thread pass the synchronization point. */
public static void passMockSleep() {
mockSleepQueue.offer(false);
}
/** Let the sleeping thread pass the synchronization point any number of times. */
public static void finishMockSleep() {
if (mockSleepQueue != null) {
mockSleepQueue.offer(true);
}
}
public static boolean isAndroidRuntime() {
final String runtime = System.getProperty("java.runtime.name");
return runtime != null && runtime.equals("Android Runtime");
}
private static class Pair implements Comparable<Pair> {
int item, count;
public Pair(int item, int count) { this.count = count; this.item = item; }
@Override public int compareTo(Pair o) { return -Ints.compare(count, o.count); }
}
public static int maxOfMostFreq(int... items) {
// Java 6 sucks.
ArrayList<Integer> list = new ArrayList<Integer>(items.length);
for (int item : items) list.add(item);
return maxOfMostFreq(list);
}
public static int maxOfMostFreq(List<Integer> items) {
if (items.isEmpty())
return 0;
// This would be much easier in a functional language (or in Java 8).
items = Ordering.natural().reverse().sortedCopy(items);
LinkedList<Pair> pairs = Lists.newLinkedList();
pairs.add(new Pair(items.get(0), 0));
for (int item : items) {
Pair pair = pairs.getLast();
if (pair.item != item)
pairs.add((pair = new Pair(item, 0)));
pair.count++;
}
// pairs now contains a uniqified list of the sorted inputs, with counts for how often that item appeared.
// Now sort by how frequently they occur, and pick the max of the most frequent.
Collections.sort(pairs);
int maxCount = pairs.getFirst().count;
int maxItem = pairs.getFirst().item;
for (Pair pair : pairs) {
if (pair.count != maxCount)
break;
maxItem = Math.max(maxItem, pair.item);
}
return maxItem;
}
/**
* Reads and joins together with LF char (\n) all the lines from given file. It's assumed that file is in UTF-8.
*/
public static String getResourceAsString(URL url) throws IOException {
List<String> lines = Resources.readLines(url, Charsets.UTF_8);
return Joiner.on('\n').join(lines);
}
// Can't use Closeable here because it's Java 7 only and Android devices only got that with KitKat.
public static InputStream closeUnchecked(InputStream stream) {
try {
stream.close();
return stream;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static OutputStream closeUnchecked(OutputStream stream) {
try {
stream.close();
return stream;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -1,114 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import static org.bitcoinj.core.Utils.isLessThanUnsigned;
import static org.bitcoinj.core.Utils.isLessThanOrEqualToUnsigned;
/**
* A variable-length encoded integer using Satoshis encoding.
*/
public class VarInt {
public final long value;
private final int originallyEncodedSize;
public VarInt(long value) {
this.value = value;
originallyEncodedSize = getSizeInBytes();
}
// Bitcoin has its own varint format, known in the C++ source as "compact size".
public VarInt(byte[] buf, int offset) {
int first = 0xFF & buf[offset];
if (first < 253) {
// 8 bits.
this.value = first;
originallyEncodedSize = 1;
} else if (first == 253) {
// 16 bits.
this.value = (0xFF & buf[offset + 1]) | ((0xFF & buf[offset + 2]) << 8);
originallyEncodedSize = 3;
} else if (first == 254) {
// 32 bits.
this.value = Utils.readUint32(buf, offset + 1);
originallyEncodedSize = 5;
} else {
// 64 bits.
this.value = Utils.readUint32(buf, offset + 1) | (Utils.readUint32(buf, offset + 5) << 32);
originallyEncodedSize = 9;
}
}
/**
* Gets the number of bytes used to encode this originally if deserialized from a byte array.
* Otherwise returns the minimum encoded size
*/
public int getOriginalSizeInBytes() {
return originallyEncodedSize;
}
/**
* Gets the minimum encoded size of the value stored in this VarInt
*/
public int getSizeInBytes() {
return sizeOf(value);
}
/**
* Gets the minimum encoded size of the given value.
*/
public static int sizeOf(int value) {
if (value < 253)
return 1;
else if (value < 65536)
return 3; // 1 marker + 2 data bytes
return 5; // 1 marker + 4 data bytes
}
/**
* Gets the minimum encoded size of the given value.
*/
public static int sizeOf(long value) {
if (isLessThanUnsigned(value, 253))
return 1;
else if (isLessThanOrEqualToUnsigned(value, 0xFFFFL))
return 3; // 1 marker + 2 data bytes
else if (isLessThanOrEqualToUnsigned(value, 0xFFFFFFFFL))
return 5; // 1 marker + 4 data bytes
else
return 9; // 1 marker + 8 data bytes
}
public byte[] encode() {
if (isLessThanUnsigned(value, 253)) {
return new byte[]{(byte) value};
} else if (isLessThanOrEqualToUnsigned(value, 0xFFFFL)) {
return new byte[]{(byte) 253, (byte) (value), (byte) (value >> 8)};
} else if (isLessThanOrEqualToUnsigned(value, 0xFFFFFFFFL)) {
byte[] bytes = new byte[5];
bytes[0] = (byte) 254;
Utils.uint32ToByteArrayLE(value, bytes, 1);
return bytes;
} else {
byte[] bytes = new byte[9];
bytes[0] = (byte) 255;
Utils.uint32ToByteArrayLE(value, bytes, 1);
Utils.uint32ToByteArrayLE(value >>> 32, bytes, 5);
return bytes;
}
}
}

View File

@@ -1,76 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
@SuppressWarnings("serial")
public class VerificationException extends RuntimeException {
public VerificationException(String msg) {
super(msg);
}
public VerificationException(Exception e) {
super(e);
}
public VerificationException(String msg, Throwable t) {
super(msg, t);
}
public static class EmptyInputsOrOutputs extends VerificationException {
public EmptyInputsOrOutputs() {
super("Transaction had no inputs or no outputs.");
}
}
public static class LargerThanMaxBlockSize extends VerificationException {
public LargerThanMaxBlockSize() {
super("Transaction larger than MAX_BLOCK_SIZE");
}
}
public static class DuplicatedOutPoint extends VerificationException {
public DuplicatedOutPoint() {
super("Duplicated outpoint");
}
}
public static class NegativeValueOutput extends VerificationException {
public NegativeValueOutput() {
super("Transaction output negative");
}
}
public static class ExcessiveValue extends VerificationException {
public ExcessiveValue() {
super("Total transaction output value greater than possible");
}
}
public static class CoinbaseScriptSizeOutOfRange extends VerificationException {
public CoinbaseScriptSizeOutOfRange() {
super("Coinbase script size out of range");
}
}
public static class UnexpectedCoinbaseInput extends VerificationException {
public UnexpectedCoinbaseInput() {
super("Coinbase input as input in non-coinbase transaction");
}
}
}

View File

@@ -1,318 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* A VersionMessage holds information exchanged during connection setup with another peer. Most of the fields are not
* particularly interesting. The subVer field, since BIP 14, acts as a User-Agent string would. You can and should
* append to or change the subVer for your own software so other implementations can identify it, and you can look at
* the subVer field received from other nodes to see what they are running. <p>
*
* After creating yourself a VersionMessage, you can pass it to {@link PeerGroup#setVersionMessage(VersionMessage)}
* to ensure it will be used for each new connection.
*/
public class VersionMessage extends Message {
private static final long serialVersionUID = 7313594258967483180L;
/** A services flag that denotes whether the peer has a copy of the block chain or not. */
public static final int NODE_NETWORK = 1;
/** A flag that denotes whether the peer supports the getutxos message or not. */
public static final int NODE_GETUTXOS = 2;
/**
* The version number of the protocol spoken.
*/
public int clientVersion;
/**
* Flags defining what optional services are supported.
*/
public long localServices;
/**
* What the other side believes the current time to be, in seconds.
*/
public long time;
/**
* What the other side believes the address of this program is. Not used.
*/
public PeerAddress myAddr;
/**
* What the other side believes their own address is. Not used.
*/
public PeerAddress theirAddr;
/**
* User-Agent as defined in <a href="https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki">BIP 14</a>.
* The official client sets it to something like "/Satoshi:0.9.1/".
*/
public String subVer;
/**
* How many blocks are in the chain, according to the other side.
*/
public long bestHeight;
/**
* Whether or not to relay tx invs before a filter is received.
* See <a href="https://github.com/bitcoin/bips/blob/master/bip-0037.mediawiki#extensions-to-existing-messages">BIP 37</a>.
*/
public boolean relayTxesBeforeFilter;
/** The version of this library release, as a string. */
public static final String BITCOINJ_VERSION = "0.13-SNAPSHOT";
/** The value that is prepended to the subVer field of this application. */
public static final String LIBRARY_SUBVER = "/bitcoinj:" + BITCOINJ_VERSION + "/";
public VersionMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0);
}
// It doesn't really make sense to ever lazily parse a version message or to retain the backing bytes.
// If you're receiving this on the wire you need to check the protocol version and it will never need to be sent
// back down the wire.
public VersionMessage(NetworkParameters params, int newBestHeight) {
super(params);
clientVersion = NetworkParameters.PROTOCOL_VERSION;
localServices = 0;
time = System.currentTimeMillis() / 1000;
// Note that the official client doesn't do anything with these, and finding out your own external IP address
// is kind of tricky anyway, so we just put nonsense here for now.
try {
// We hard-code the IPv4 localhost address here rather than use InetAddress.getLocalHost() because some
// mobile phones have broken localhost DNS entries, also, this is faster.
final byte[] localhost = { 127, 0, 0, 1 };
myAddr = new PeerAddress(InetAddress.getByAddress(localhost), params.getPort(), 0);
theirAddr = new PeerAddress(InetAddress.getByAddress(localhost), params.getPort(), 0);
} catch (UnknownHostException e) {
throw new RuntimeException(e); // Cannot happen (illegal IP length).
}
subVer = LIBRARY_SUBVER;
bestHeight = newBestHeight;
relayTxesBeforeFilter = true;
length = 85;
if (protocolVersion > 31402)
length += 8;
length += VarInt.sizeOf(subVer.length()) + subVer.length();
}
@Override
protected void parseLite() throws ProtocolException {
// NOP. VersionMessage is never lazy parsed.
}
@Override
public void parse() throws ProtocolException {
if (parsed)
return;
parsed = true;
clientVersion = (int) readUint32();
localServices = readUint64().longValue();
time = readUint64().longValue();
myAddr = new PeerAddress(params, payload, cursor, 0);
cursor += myAddr.getMessageSize();
theirAddr = new PeerAddress(params, payload, cursor, 0);
cursor += theirAddr.getMessageSize();
// uint64 localHostNonce (random data)
// We don't care about the localhost nonce. It's used to detect connecting back to yourself in cases where
// there are NATs and proxies in the way. However we don't listen for inbound connections so it's irrelevant.
readUint64();
try {
// Initialize default values for flags which may not be sent by old nodes
subVer = "";
bestHeight = 0;
relayTxesBeforeFilter = true;
if (!hasMoreBytes())
return;
// string subVer (currently "")
subVer = readStr();
if (!hasMoreBytes())
return;
// int bestHeight (size of known block chain).
bestHeight = readUint32();
if (!hasMoreBytes())
return;
relayTxesBeforeFilter = readBytes(1)[0] != 0;
} finally {
length = cursor - offset;
}
}
@Override
public void bitcoinSerializeToStream(OutputStream buf) throws IOException {
Utils.uint32ToByteStreamLE(clientVersion, buf);
Utils.uint32ToByteStreamLE(localServices, buf);
Utils.uint32ToByteStreamLE(localServices >> 32, buf);
Utils.uint32ToByteStreamLE(time, buf);
Utils.uint32ToByteStreamLE(time >> 32, buf);
try {
// My address.
myAddr.bitcoinSerialize(buf);
// Their address.
theirAddr.bitcoinSerialize(buf);
} catch (UnknownHostException e) {
throw new RuntimeException(e); // Can't happen.
} catch (IOException e) {
throw new RuntimeException(e); // Can't happen.
}
// Next up is the "local host nonce", this is to detect the case of connecting
// back to yourself. We don't care about this as we won't be accepting inbound
// connections.
Utils.uint32ToByteStreamLE(0, buf);
Utils.uint32ToByteStreamLE(0, buf);
// Now comes subVer.
byte[] subVerBytes = subVer.getBytes("UTF-8");
buf.write(new VarInt(subVerBytes.length).encode());
buf.write(subVerBytes);
// Size of known block chain.
Utils.uint32ToByteStreamLE(bestHeight, buf);
buf.write(relayTxesBeforeFilter ? 1 : 0);
}
/**
* Returns true if the version message indicates the sender has a full copy of the block chain,
* or if it's running in client mode (only has the headers).
*/
public boolean hasBlockChain() {
return (localServices & NODE_NETWORK) == NODE_NETWORK;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VersionMessage other = (VersionMessage) o;
return other.bestHeight == bestHeight &&
other.clientVersion == clientVersion &&
other.localServices == localServices &&
other.time == time &&
other.subVer.equals(subVer) &&
other.myAddr.equals(myAddr) &&
other.theirAddr.equals(theirAddr) &&
other.relayTxesBeforeFilter == relayTxesBeforeFilter;
}
@Override
public int hashCode() {
return (int) bestHeight ^ clientVersion ^ (int) localServices ^ (int) time ^ subVer.hashCode() ^ myAddr.hashCode()
^ theirAddr.hashCode() * (relayTxesBeforeFilter ? 1 : 2);
}
/**
* VersionMessage does not handle cached byte array so should not have a cached checksum.
*/
@Override
byte[] getChecksum() {
throw new UnsupportedOperationException();
}
/**
* VersionMessage does not handle cached byte array so should not have a cached checksum.
*/
@Override
void setChecksum(byte[] checksum) {
throw new UnsupportedOperationException();
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("\n");
sb.append("client version: ").append(clientVersion).append("\n");
sb.append("local services: ").append(localServices).append("\n");
sb.append("time: ").append(time).append("\n");
sb.append("my addr: ").append(myAddr).append("\n");
sb.append("their addr: ").append(theirAddr).append("\n");
sb.append("sub version: ").append(subVer).append("\n");
sb.append("best height: ").append(bestHeight).append("\n");
sb.append("delay tx relay: ").append(!relayTxesBeforeFilter).append("\n");
return sb.toString();
}
public VersionMessage duplicate() {
VersionMessage v = new VersionMessage(params, (int) bestHeight);
v.clientVersion = clientVersion;
v.localServices = localServices;
v.time = time;
v.myAddr = myAddr;
v.theirAddr = theirAddr;
v.subVer = subVer;
v.relayTxesBeforeFilter = relayTxesBeforeFilter;
return v;
}
/**
* Appends the given user-agent information to the subVer field. The subVer is composed of a series of
* name:version pairs separated by slashes in the form of a path. For example a typical subVer field for BitCoinJ
* users might look like "/BitCoinJ:0.4-SNAPSHOT/MultiBit:1.2/" where libraries come further to the left.<p>
*
* There can be as many components as you feel a need for, and the version string can be anything, but it is
* recommended to use A.B.C where A = major, B = minor and C = revision for software releases, and dates for
* auto-generated source repository snapshots. A valid subVer begins and ends with a slash, therefore name
* and version are not allowed to contain such characters. <p>
*
* Anything put in the "comments" field will appear in brackets and may be used for platform info, or anything
* else. For example, calling <tt>appendToSubVer("MultiBit", "1.0", "Windows")</tt> will result in a subVer being
* set of "/BitCoinJ:1.0/MultiBit:1.0(Windows)/". Therefore the / ( and ) characters are reserved in all these
* components. If you don't want to add a comment (recommended), pass null.<p>
*
* See <a href="https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki">BIP 14</a> for more information.
*
* @param comments Optional (can be null) platform or other node specific information.
* @throws IllegalArgumentException if name, version or comments contains invalid characters.
*/
public void appendToSubVer(String name, String version, @Nullable String comments) {
checkSubVerComponent(name);
checkSubVerComponent(version);
if (comments != null) {
checkSubVerComponent(comments);
subVer = subVer.concat(String.format("%s:%s(%s)/", name, version, comments));
} else {
subVer = subVer.concat(String.format("%s:%s/", name, version));
}
}
private static void checkSubVerComponent(String component) {
if (component.contains("/") || component.contains("(") || component.contains(")"))
throw new IllegalArgumentException("name contains invalid characters");
}
/**
* Returns true if the clientVersion field is >= Pong.MIN_PROTOCOL_VERSION. If it is then ping() is usable.
*/
public boolean isPingPongSupported() {
return clientVersion >= Pong.MIN_PROTOCOL_VERSION;
}
/**
* Returns true if the clientVersion field is >= FilteredBlock.MIN_PROTOCOL_VERSION. If it is then Bloom filtering
* is available and the memory pool of the remote peer will be queried when the downloadData property is true.
*/
public boolean isBloomFilteringSupported() {
return clientVersion >= FilteredBlock.MIN_PROTOCOL_VERSION;
}
/** Returns true if the protocol version and service bits both indicate support for the getutxos message. */
public boolean isGetUTXOsSupported() {
return clientVersion >= GetUTXOsMessage.MIN_PROTOCOL_VERSION &&
(localServices & NODE_GETUTXOS) == NODE_GETUTXOS;
}
}

View File

@@ -1,120 +0,0 @@
/**
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import static com.google.common.base.Preconditions.checkArgument;
import java.io.Serializable;
import java.util.Arrays;
import com.google.common.base.Objects;
import com.google.common.primitives.UnsignedBytes;
/**
* <p>In Bitcoin the following format is often used to represent some type of key:</p>
* <p/>
* <pre>[one version byte] [data bytes] [4 checksum bytes]</pre>
* <p/>
* <p>and the result is then Base58 encoded. This format is used for addresses, and private keys exported using the
* dumpprivkey command.</p>
*/
public class VersionedChecksummedBytes implements Serializable, Cloneable, Comparable<VersionedChecksummedBytes> {
protected final int version;
protected byte[] bytes;
protected VersionedChecksummedBytes(String encoded) throws AddressFormatException {
byte[] versionAndDataBytes = Base58.decodeChecked(encoded);
byte versionByte = versionAndDataBytes[0];
version = versionByte & 0xFF;
bytes = new byte[versionAndDataBytes.length - 1];
System.arraycopy(versionAndDataBytes, 1, bytes, 0, versionAndDataBytes.length - 1);
}
protected VersionedChecksummedBytes(int version, byte[] bytes) {
checkArgument(version >= 0 && version < 256);
this.version = version;
this.bytes = bytes;
}
/**
* Returns the base-58 encoded String representation of this
* object, including version and checksum bytes.
*/
@Override
public String toString() {
// A stringified buffer is:
// 1 byte version + data bytes + 4 bytes check code (a truncated hash)
byte[] addressBytes = new byte[1 + bytes.length + 4];
addressBytes[0] = (byte) version;
System.arraycopy(bytes, 0, addressBytes, 1, bytes.length);
byte[] checksum = Utils.doubleDigest(addressBytes, 0, bytes.length + 1);
System.arraycopy(checksum, 0, addressBytes, bytes.length + 1, 4);
return Base58.encode(addressBytes);
}
@Override
public int hashCode() {
return Objects.hashCode(version, Arrays.hashCode(bytes));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
VersionedChecksummedBytes other = (VersionedChecksummedBytes) o;
return this.version == other.version
&& Arrays.equals(this.bytes, other.bytes);
}
/**
* {@inheritDoc}
*
* This implementation narrows the return type to <code>VersionedChecksummedBytes</code>
* and allows subclasses to throw <code>CloneNotSupportedException</code> even though it
* is never thrown by this implementation.
*/
@Override
public VersionedChecksummedBytes clone() throws CloneNotSupportedException {
return (VersionedChecksummedBytes) super.clone();
}
/**
* {@inheritDoc}
*
* This implementation uses an optimized Google Guava method to compare <code>bytes</code>.
*/
@Override
public int compareTo(VersionedChecksummedBytes o) {
int versionCompare = Integer.valueOf(this.version).compareTo(Integer.valueOf(o.version)); // JDK 6 way
if (versionCompare == 0) {
// Would there be a performance benefit to caching the comparator?
return UnsignedBytes.lexicographicalComparator().compare(this.bytes, o.bytes);
} else {
return versionCompare;
}
}
/**
* Returns the "version" or "header" byte: the first byte of the data. This is used to disambiguate what the
* contents apply to, for example, which network the key or address is valid on.
*
* @return A positive number between 0 and 255.
*/
public int getVersion() {
return version;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,126 +0,0 @@
/**
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import org.bitcoinj.script.Script;
import org.bitcoinj.wallet.KeyChainEventListener;
import java.util.List;
/**
* <p>Implementors are called when the contents of the wallet changes, for instance due to receiving/sending money
* or a block chain re-organize. It may be convenient to derive from {@link AbstractWalletEventListener} instead.</p>
*/
public interface WalletEventListener extends KeyChainEventListener {
/**
* This is called when a transaction is seen that sends coins <b>to</b> this wallet, either because it
* was broadcast across the network or because a block was received. If a transaction is seen when it was broadcast,
* onCoinsReceived won't be called again when a block containing it is received. If you want to know when such a
* transaction receives its first confirmation, register a {@link TransactionConfidence} event listener using
* the object retrieved via {@link org.bitcoinj.core.Transaction#getConfidence()}. It's safe to modify the
* wallet in this callback, for example, by spending the transaction just received.
*
* @param wallet The wallet object that received the coins
* @param tx The transaction which sent us the coins.
* @param prevBalance Balance before the coins were received.
* @param newBalance Current balance of the wallet. This is the 'estimated' balance.
*/
void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
/**
* This is called when a transaction is seen that sends coins <b>from</b> this wallet, either
* because it was broadcast across the network or because a block was received. This may at first glance seem
* useless, because in the common case you already know about such transactions because you created them with
* the Wallets createSend/sendCoins methods. However when you have a wallet containing only keys, and you wish
* to replay the block chain to fill it with transactions, it's useful to find out when a transaction is discovered
* that sends coins from the wallet.<p>
*
* It's safe to modify the wallet from inside this callback, but if you're replaying the block chain you should
* be careful to avoid such modifications. Otherwise your changes may be overridden by new data from the chain.
*
* @param wallet The wallet object that this callback relates to (that sent the coins).
* @param tx The transaction that sent the coins to someone else.
* @param prevBalance The wallets balance before this transaction was seen.
* @param newBalance The wallets balance after this transaction was seen. This is the 'estimated' balance.
*/
void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
// TODO: Finish onReorganize to be more useful.
/**
* <p>This is called when a block is received that triggers a block chain re-organization.</p>
*
* <p>A re-organize means that the consensus (chain) of the network has diverged and now changed from what we
* believed it was previously. Usually this won't matter because the new consensus will include all our old
* transactions assuming we are playing by the rules. However it's theoretically possible for our balance to
* change in arbitrary ways, most likely, we could lose some money we thought we had.</p>
*
* <p>It is safe to use methods of wallet whilst inside this callback.</p>
*/
void onReorganize(Wallet wallet);
/**
* <p>Called when a transaction changes its confidence level. You can also attach event listeners to
* the individual transactions, if you don't care about all of them. Usually you would save the wallet to disk after
* receiving this callback unless you already set up autosaving.</p>
*
* <p>You should pay attention to this callback in case a transaction becomes <i>dead</i>, that is, a transaction
* you believed to be active (send or receive) becomes overridden by the network. This can happen if</p>
*
* <ol>
* <li>You are sharing keys between wallets and accidentally create/broadcast a double spend.</li>
* <li>Somebody is attacking the network and reversing transactions, ie, the user is a victim of fraud.</li>
* <li>A bug: for example you create a transaction, broadcast it but fail to commit it. The {@link Wallet}
* will then re-use the same outputs when creating the next spend.</li>
* </ol><p>
*
* <p>To find if the transaction is dead, you can use <tt>tx.getConfidence().getConfidenceType() ==
* TransactionConfidence.ConfidenceType.DEAD</tt>. If it is, you should notify the user
* in some way so they know the thing they bought may not arrive/the thing they sold should not be dispatched.</p>
*
* <p>Note that this callback will be invoked for every transaction in the wallet, for every new block that is
* received (because the depth has changed). <b>If you want to update a UI view from the contents of the wallet
* it is more efficient to use onWalletChanged instead.</b></p>
*/
void onTransactionConfidenceChanged(Wallet wallet, Transaction tx);
/**
* <p>Designed for GUI applications to refresh their transaction lists. This callback is invoked in the following
* situations:</p>
*
* <ol>
* <li>A new block is received (and thus building transactions got more confidence)</li>
* <li>A pending transaction is received</li>
* <li>A pending transaction changes confidence due to some non-new-block related event, such as being
* announced by more peers or by a double-spend conflict being observed.</li>
* <li>A re-organize occurs. Call occurs only if the re-org modified any of our transactions.</li>
* <li>A new spend is committed to the wallet.</li>
* <li>The wallet is reset and all transactions removed.<li>
* </ol>
*
* <p>When this is called you can refresh the UI contents from the wallet contents. It's more efficient to use
* this rather than onTransactionConfidenceChanged() + onReorganize() because you only get one callback per block
* rather than one per transaction per block. Note that this is <b>not</b> called when a key is added. </p>
*/
void onWalletChanged(Wallet wallet);
/**
* Called whenever a new watched script is added to the wallet.
*
* @param isAddingScripts will be true if added scripts, false if removed scripts.
*/
void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts);
}

View File

@@ -1,44 +0,0 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
/**
* <p>An object implementing this interface can be added to a {@link Wallet} and provide arbitrary byte arrays that will
* be serialized alongside the wallet. Extensions can be mandatory, in which case applications that don't know how to
* read the given data will refuse to load the wallet at all. Extensions identify themselves with a string ID that
* should use a Java-style reverse DNS identifier to avoid being mixed up with other kinds of extension. To use an
* extension, add an object that implements this interface to the wallet using {@link Wallet#addExtension(WalletExtension)}
* before you load it (to read existing data) and ensure it's present when the wallet is save (to write the data).</p>
*
* <p>Note that extensions are singletons - you cannot add two objects that provide the same ID to the same wallet.</p>
*/
public interface WalletExtension {
/** Returns a Java package/class style name used to disambiguate this extension from others. */
public String getWalletExtensionID();
/**
* If this returns true, the mandatory flag is set when the wallet is serialized and attempts to load it without
* the extension being in the wallet will throw an exception. This method should not change its result during
* the objects lifetime.
*/
public boolean isWalletExtensionMandatory();
/** Returns bytes that will be saved in the wallet. */
public byte[] serializeWalletExtension();
/** Loads the contents of this object from the wallet. */
public void deserializeWalletExtension(Wallet containingWallet, byte[] data) throws Exception;
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.core;
import java.util.Arrays;
/**
* This exception is thrown by the Address class when you try and decode an address with a version code that isn't
* used by that network. You shouldn't allow the user to proceed in this case as they are trying to send money across
* different chains, an operation that is guaranteed to destroy the money.
*/
public class WrongNetworkException extends AddressFormatException {
/** The version code that was provided in the address. */
public int verCode;
/** The list of acceptable versions that were expected given the addresses network parameters. */
public int[] acceptableVersions;
public WrongNetworkException(int verCode, int[] acceptableVersions) {
super("Version code of address did not match acceptable versions for network: " + verCode + " not in " +
Arrays.toString(acceptableVersions));
this.verCode = verCode;
this.acceptableVersions = acceptableVersions;
}
}

View File

@@ -1,8 +0,0 @@
/**
* The core package contains classes for network messages like {@link org.bitcoinj.core.Block} and
* {@link org.bitcoinj.core.Transaction}, peer connectivity via {@link org.bitcoinj.core.PeerGroup},
* block chain management and the {@link org.bitcoinj.core.Wallet} class.
* If what you're doing can be described as basic bitcoin tasks, the code is probably found here.
* To learn more please consult the documentation on the website.
*/
package org.bitcoinj.core;

View File

@@ -1,178 +0,0 @@
/*
* Copyright 2014 Andreas Schildbach
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bitcoinj.crypto;
import org.bitcoinj.core.*;
import com.google.common.base.Charsets;
import com.google.common.base.Objects;
import com.google.common.primitives.Bytes;
import com.lambdaworks.crypto.SCrypt;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.text.Normalizer;
import java.util.Arrays;
import static com.google.common.base.Preconditions.checkState;
/**
* Implementation of <a href="https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki">BIP 38</a>
* passphrase-protected private keys. Currently, only decryption is supported.
*/
public class BIP38PrivateKey extends VersionedChecksummedBytes {
public final NetworkParameters params;
public final boolean ecMultiply;
public final boolean compressed;
public final boolean hasLotAndSequence;
public final byte[] addressHash;
public final byte[] content;
public static final class BadPassphraseException extends Exception {
}
public BIP38PrivateKey(NetworkParameters params, String encoded) throws AddressFormatException {
super(encoded);
this.params = params;
if (version != 0x01)
throw new AddressFormatException("Mismatched version number: " + version);
if (bytes.length != 38)
throw new AddressFormatException("Wrong number of bytes, excluding version byte: " + bytes.length);
hasLotAndSequence = (bytes[1] & 0x04) != 0; // bit 2
compressed = (bytes[1] & 0x20) != 0; // bit 5
if ((bytes[1] & 0x01) != 0) // bit 0
throw new AddressFormatException("Bit 0x01 reserved for future use.");
if ((bytes[1] & 0x02) != 0) // bit 1
throw new AddressFormatException("Bit 0x02 reserved for future use.");
if ((bytes[1] & 0x08) != 0) // bit 3
throw new AddressFormatException("Bit 0x08 reserved for future use.");
if ((bytes[1] & 0x10) != 0) // bit 4
throw new AddressFormatException("Bit 0x10 reserved for future use.");
final int byte0 = bytes[0] & 0xff;
if (byte0 == 0x42) {
// Non-EC-multiplied key
if ((bytes[1] & 0xc0) != 0xc0) // bits 6+7
throw new AddressFormatException("Bits 0x40 and 0x80 must be set for non-EC-multiplied keys.");
ecMultiply = false;
if (hasLotAndSequence)
throw new AddressFormatException("Non-EC-multiplied keys cannot have lot/sequence.");
} else if (byte0 == 0x43) {
// EC-multiplied key
if ((bytes[1] & 0xc0) != 0x00) // bits 6+7
throw new AddressFormatException("Bits 0x40 and 0x80 must be cleared for EC-multiplied keys.");
ecMultiply = true;
} else {
throw new AddressFormatException("Second byte must by 0x42 or 0x43.");
}
addressHash = Arrays.copyOfRange(bytes, 2, 6);
content = Arrays.copyOfRange(bytes, 6, 38);
}
public ECKey decrypt(String passphrase) throws BadPassphraseException {
String normalizedPassphrase = Normalizer.normalize(passphrase, Normalizer.Form.NFC);
ECKey key = ecMultiply ? decryptEC(normalizedPassphrase) : decryptNoEC(normalizedPassphrase);
Sha256Hash hash = Sha256Hash.createDouble(key.toAddress(params).toString().getBytes(Charsets.US_ASCII));
byte[] actualAddressHash = Arrays.copyOfRange(hash.getBytes(), 0, 4);
if (!Arrays.equals(actualAddressHash, addressHash))
throw new BadPassphraseException();
return key;
}
private ECKey decryptNoEC(String normalizedPassphrase) {
try {
byte[] derived = SCrypt.scrypt(normalizedPassphrase.getBytes(Charsets.UTF_8), addressHash, 16384, 8, 8, 64);
byte[] key = Arrays.copyOfRange(derived, 32, 64);
SecretKeySpec keyspec = new SecretKeySpec(key, "AES");
DRMWorkaround.maybeDisableExportControls();
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keyspec);
byte[] decrypted = cipher.doFinal(content, 0, 32);
for (int i = 0; i < 32; i++)
decrypted[i] ^= derived[i];
return ECKey.fromPrivate(decrypted, compressed);
} catch (GeneralSecurityException x) {
throw new RuntimeException(x);
}
}
private ECKey decryptEC(String normalizedPassphrase) {
try {
byte[] ownerEntropy = Arrays.copyOfRange(content, 0, 8);
byte[] ownerSalt = hasLotAndSequence ? Arrays.copyOfRange(ownerEntropy, 0, 4) : ownerEntropy;
byte[] passFactorBytes = SCrypt.scrypt(normalizedPassphrase.getBytes(Charsets.UTF_8), ownerSalt, 16384, 8, 8, 32);
if (hasLotAndSequence) {
byte[] hashBytes = Bytes.concat(passFactorBytes, ownerEntropy);
checkState(hashBytes.length == 40);
passFactorBytes = Sha256Hash.createDouble(hashBytes).getBytes();
}
BigInteger passFactor = new BigInteger(1, passFactorBytes);
ECKey k = ECKey.fromPrivate(passFactor, true);
byte[] salt = Bytes.concat(addressHash, ownerEntropy);
checkState(salt.length == 12);
byte[] derived = SCrypt.scrypt(k.getPubKey(), salt, 1024, 1, 1, 64);
byte[] aeskey = Arrays.copyOfRange(derived, 32, 64);
SecretKeySpec keyspec = new SecretKeySpec(aeskey, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keyspec);
byte[] encrypted2 = Arrays.copyOfRange(content, 16, 32);
byte[] decrypted2 = cipher.doFinal(encrypted2);
checkState(decrypted2.length == 16);
for (int i = 0; i < 16; i++)
decrypted2[i] ^= derived[i + 16];
byte[] encrypted1 = Bytes.concat(Arrays.copyOfRange(content, 8, 16), Arrays.copyOfRange(decrypted2, 0, 8));
byte[] decrypted1 = cipher.doFinal(encrypted1);
checkState(decrypted1.length == 16);
for (int i = 0; i < 16; i++)
decrypted1[i] ^= derived[i];
byte[] seed = Bytes.concat(decrypted1, Arrays.copyOfRange(decrypted2, 8, 16));
checkState(seed.length == 24);
BigInteger seedFactor = new BigInteger(1, Sha256Hash.createDouble(seed).getBytes());
checkState(passFactor.signum() >= 0);
checkState(seedFactor.signum() >= 0);
BigInteger priv = passFactor.multiply(seedFactor).mod(ECKey.CURVE.getN());
return ECKey.fromPrivate(priv, compressed);
} catch (GeneralSecurityException x) {
throw new RuntimeException(x);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BIP38PrivateKey other = (BIP38PrivateKey) o;
return super.equals(other)
&& Objects.equal(this.params, other.params);
}
@Override
public int hashCode() {
return Objects.hashCode(super.hashCode(), params);
}
}

Some files were not shown because too many files have changed in this diff Show More