diff --git a/.gitignore b/.gitignore index 6522dc396..85af96b87 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,5 @@ checkpoints.txt *.db core/2.0.32_pivx-wallet-backup_org.pivx.production-2017-11-20 *build/ -*.DS_Store \ No newline at end of file +*.DS_Store +*out/ \ No newline at end of file diff --git a/core/out/production/classes/host/furszy/zerocoinj/protocol/GenWitMessage.class b/core/out/production/classes/host/furszy/zerocoinj/protocol/GenWitMessage.class index 90b0651ba..7ad074138 100644 Binary files a/core/out/production/classes/host/furszy/zerocoinj/protocol/GenWitMessage.class and b/core/out/production/classes/host/furszy/zerocoinj/protocol/GenWitMessage.class differ diff --git a/core/out/production/classes/host/furszy/zerocoinj/protocol/PubcoinsMessage.class b/core/out/production/classes/host/furszy/zerocoinj/protocol/PubcoinsMessage.class index a05239d07..26c705195 100644 Binary files a/core/out/production/classes/host/furszy/zerocoinj/protocol/PubcoinsMessage.class and b/core/out/production/classes/host/furszy/zerocoinj/protocol/PubcoinsMessage.class differ diff --git a/core/out/production/classes/host/furszy/zerocoinj/wallet/MultiWallet.class b/core/out/production/classes/host/furszy/zerocoinj/wallet/MultiWallet.class index 1b5222fa8..367894529 100644 Binary files a/core/out/production/classes/host/furszy/zerocoinj/wallet/MultiWallet.class and b/core/out/production/classes/host/furszy/zerocoinj/wallet/MultiWallet.class differ diff --git a/core/out/production/classes/host/furszy/zerocoinj/wallet/ZWallet.class b/core/out/production/classes/host/furszy/zerocoinj/wallet/ZWallet.class index 16f494e5e..f73968ac0 100644 Binary files a/core/out/production/classes/host/furszy/zerocoinj/wallet/ZWallet.class and b/core/out/production/classes/host/furszy/zerocoinj/wallet/ZWallet.class differ diff --git a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$1.class b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$1.class index 87afc2bf5..82443d647 100644 Binary files a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$1.class and b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$1.class differ diff --git a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$2.class b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$2.class index 2ba0b9db3..850595569 100644 Binary files a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$2.class and b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$2.class differ diff --git a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$3.class b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$3.class index 9b777c4e9..38f53b898 100644 Binary files a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$3.class and b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$3.class differ diff --git a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$4.class b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$4.class index 9cd1a863f..ff2c4ac08 100644 Binary files a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$4.class and b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$4.class differ diff --git a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$NewBlockType.class b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$NewBlockType.class index e51a2ca75..67f6f1ec2 100644 Binary files a/core/out/production/classes/org/pivxj/core/AbstractBlockChain$NewBlockType.class and b/core/out/production/classes/org/pivxj/core/AbstractBlockChain$NewBlockType.class differ diff --git a/core/out/production/classes/org/pivxj/core/AbstractBlockChain.class b/core/out/production/classes/org/pivxj/core/AbstractBlockChain.class index 3258e8641..005cd15a8 100644 Binary files a/core/out/production/classes/org/pivxj/core/AbstractBlockChain.class and b/core/out/production/classes/org/pivxj/core/AbstractBlockChain.class differ diff --git a/core/out/production/classes/org/pivxj/core/BitcoinSerializer$BitcoinPacketHeader.class b/core/out/production/classes/org/pivxj/core/BitcoinSerializer$BitcoinPacketHeader.class index 82578a2ad..5fa852cca 100644 Binary files a/core/out/production/classes/org/pivxj/core/BitcoinSerializer$BitcoinPacketHeader.class and b/core/out/production/classes/org/pivxj/core/BitcoinSerializer$BitcoinPacketHeader.class differ diff --git a/core/out/production/classes/org/pivxj/core/BitcoinSerializer.class b/core/out/production/classes/org/pivxj/core/BitcoinSerializer.class index 05fad264b..b66d485b1 100644 Binary files a/core/out/production/classes/org/pivxj/core/BitcoinSerializer.class and b/core/out/production/classes/org/pivxj/core/BitcoinSerializer.class differ diff --git a/core/out/production/classes/org/pivxj/core/BloomFilter.class b/core/out/production/classes/org/pivxj/core/BloomFilter.class index faa1e9cbe..6e913ae59 100644 Binary files a/core/out/production/classes/org/pivxj/core/BloomFilter.class and b/core/out/production/classes/org/pivxj/core/BloomFilter.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionBag.class b/core/out/production/classes/org/pivxj/core/TransactionBag.class index 1a5d10bcc..b7b6fa5fa 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionBag.class and b/core/out/production/classes/org/pivxj/core/TransactionBag.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionConfidence$1.class b/core/out/production/classes/org/pivxj/core/TransactionConfidence$1.class index ba8f6e3c6..e39c46473 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionConfidence$1.class and b/core/out/production/classes/org/pivxj/core/TransactionConfidence$1.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionConfidence$2.class b/core/out/production/classes/org/pivxj/core/TransactionConfidence$2.class index 8d89f2ef4..8f9c5445f 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionConfidence$2.class and b/core/out/production/classes/org/pivxj/core/TransactionConfidence$2.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionConfidence$3.class b/core/out/production/classes/org/pivxj/core/TransactionConfidence$3.class index cb3b40a76..7ef07689e 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionConfidence$3.class and b/core/out/production/classes/org/pivxj/core/TransactionConfidence$3.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionConfidence$ConfidenceType.class b/core/out/production/classes/org/pivxj/core/TransactionConfidence$ConfidenceType.class index 1f040013d..e5ef47960 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionConfidence$ConfidenceType.class and b/core/out/production/classes/org/pivxj/core/TransactionConfidence$ConfidenceType.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionConfidence$IXType.class b/core/out/production/classes/org/pivxj/core/TransactionConfidence$IXType.class index d424531ac..e7a4c305a 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionConfidence$IXType.class and b/core/out/production/classes/org/pivxj/core/TransactionConfidence$IXType.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionConfidence$Listener$ChangeReason.class b/core/out/production/classes/org/pivxj/core/TransactionConfidence$Listener$ChangeReason.class index bc69d788e..60d55ce53 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionConfidence$Listener$ChangeReason.class and b/core/out/production/classes/org/pivxj/core/TransactionConfidence$Listener$ChangeReason.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionConfidence$Source.class b/core/out/production/classes/org/pivxj/core/TransactionConfidence$Source.class index 26422cc3e..24cbc1ef6 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionConfidence$Source.class and b/core/out/production/classes/org/pivxj/core/TransactionConfidence$Source.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionConfidence.class b/core/out/production/classes/org/pivxj/core/TransactionConfidence.class index 3d1eb5d53..6b85911f4 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionConfidence.class and b/core/out/production/classes/org/pivxj/core/TransactionConfidence.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionInput$ConnectMode.class b/core/out/production/classes/org/pivxj/core/TransactionInput$ConnectMode.class index 5e879d1c0..2d69f03c0 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionInput$ConnectMode.class and b/core/out/production/classes/org/pivxj/core/TransactionInput$ConnectMode.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionInput$ConnectionResult.class b/core/out/production/classes/org/pivxj/core/TransactionInput$ConnectionResult.class index 30850e5a4..5aacc1f74 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionInput$ConnectionResult.class and b/core/out/production/classes/org/pivxj/core/TransactionInput$ConnectionResult.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionInput.class b/core/out/production/classes/org/pivxj/core/TransactionInput.class index a1927e7ea..38006d289 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionInput.class and b/core/out/production/classes/org/pivxj/core/TransactionInput.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionOutPoint.class b/core/out/production/classes/org/pivxj/core/TransactionOutPoint.class index 19012000a..038c1d3b7 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionOutPoint.class and b/core/out/production/classes/org/pivxj/core/TransactionOutPoint.class differ diff --git a/core/out/production/classes/org/pivxj/core/TransactionOutput.class b/core/out/production/classes/org/pivxj/core/TransactionOutput.class index 7dfdceea1..d1cdaffda 100644 Binary files a/core/out/production/classes/org/pivxj/core/TransactionOutput.class and b/core/out/production/classes/org/pivxj/core/TransactionOutput.class differ diff --git a/core/out/production/classes/org/pivxj/core/VarInt.class b/core/out/production/classes/org/pivxj/core/VarInt.class index 10973eecc..5065c74c4 100644 Binary files a/core/out/production/classes/org/pivxj/core/VarInt.class and b/core/out/production/classes/org/pivxj/core/VarInt.class differ diff --git a/core/out/production/classes/org/pivxj/script/Script$ScriptType.class b/core/out/production/classes/org/pivxj/script/Script$ScriptType.class index e77362c3d..acc1346e4 100644 Binary files a/core/out/production/classes/org/pivxj/script/Script$ScriptType.class and b/core/out/production/classes/org/pivxj/script/Script$ScriptType.class differ diff --git a/core/out/production/classes/org/pivxj/script/Script$VerifyFlag.class b/core/out/production/classes/org/pivxj/script/Script$VerifyFlag.class index c8926ee7d..1bf4be486 100644 Binary files a/core/out/production/classes/org/pivxj/script/Script$VerifyFlag.class and b/core/out/production/classes/org/pivxj/script/Script$VerifyFlag.class differ diff --git a/core/out/production/classes/org/pivxj/script/Script.class b/core/out/production/classes/org/pivxj/script/Script.class index 69844ea24..7b6fd733d 100644 Binary files a/core/out/production/classes/org/pivxj/script/Script.class and b/core/out/production/classes/org/pivxj/script/Script.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/DefaultRiskAnalysis$Analyzer.class b/core/out/production/classes/org/pivxj/wallet/DefaultRiskAnalysis$Analyzer.class index 64d2fa4c2..90bee1950 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/DefaultRiskAnalysis$Analyzer.class and b/core/out/production/classes/org/pivxj/wallet/DefaultRiskAnalysis$Analyzer.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/DefaultRiskAnalysis.class b/core/out/production/classes/org/pivxj/wallet/DefaultRiskAnalysis.class index fcd55839c..5ef20b518 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/DefaultRiskAnalysis.class and b/core/out/production/classes/org/pivxj/wallet/DefaultRiskAnalysis.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$1.class b/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$1.class index 4f90e09b7..2a6546d1d 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$1.class and b/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$Builder.class b/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$Builder.class index 39d003ed8..39c8b86bc 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$Builder.class and b/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$KeyChainType.class b/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$KeyChainType.class index 1e02b6fed..b6eb60443 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$KeyChainType.class and b/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain$KeyChainType.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain.class b/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain.class index 49996d909..1d655af10 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain.class and b/core/out/production/classes/org/pivxj/wallet/DeterministicKeyChain.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/KeyChainGroup.class b/core/out/production/classes/org/pivxj/wallet/KeyChainGroup.class index 3535942c2..45d8abe58 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/KeyChainGroup.class and b/core/out/production/classes/org/pivxj/wallet/KeyChainGroup.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$1.class index 26c4e9fb4..5ac1d2931 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate$1.class index e5e7599e8..b6c1b7fdb 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate$Builder.class index 8ff1595c0..a93c66191 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate.class b/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate.class index 4d50d0e04..b0a561ab1 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate.class and b/core/out/production/classes/org/pivxj/wallet/Protos$ExchangeRate.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Extension$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Extension$1.class index 783ebdc53..2bdc2f9cd 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Extension$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Extension$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Extension$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$Extension$Builder.class index 7e6eb9c16..79277daf7 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Extension$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Extension$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Extension.class b/core/out/production/classes/org/pivxj/wallet/Protos$Extension.class index 52c9d7dd2..c3ea9f117 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Extension.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Extension.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Key$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Key$1.class index ec070b4a3..184b690ba 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Key$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Key$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Key$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$Key$Builder.class index 1804932af..7a7c13dba 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Key$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Key$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Key$Type$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Key$Type$1.class index c44a0e3c4..6c1878b2d 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Key$Type$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Key$Type$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Key$Type.class b/core/out/production/classes/org/pivxj/wallet/Protos$Key$Type.class index 7f636f8b3..cc7215d06 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Key$Type.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Key$Type.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Key.class b/core/out/production/classes/org/pivxj/wallet/Protos$Key.class index dea7a603e..acc8f808b 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Key.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Key.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Script$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Script$1.class index 8af28006c..2314f16c2 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Script$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Script$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Script$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$Script$Builder.class index 72225bd8d..4ff67c82c 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Script$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Script$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Script.class b/core/out/production/classes/org/pivxj/wallet/Protos$Script.class index bb0e73bff..ce678b1be 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Script.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Script.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters$1.class index 243a02e7b..c4ac03fd5 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters$Builder.class index 9118190f4..a7fb1495c 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters.class b/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters.class index 7e048dc46..099094850 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters.class and b/core/out/production/classes/org/pivxj/wallet/Protos$ScryptParameters.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Tag$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Tag$1.class index 14b4c0c24..cbd47af72 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Tag$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Tag$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Tag$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$Tag$Builder.class index 2914e97ab..d187c7ed2 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Tag$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Tag$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Tag.class b/core/out/production/classes/org/pivxj/wallet/Protos$Tag.class index b35d6404f..4b31e6059 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Tag.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Tag.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$1.class index 7a064031f..0bc71c5d2 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Builder.class index af3f6a0df..f4b238f6c 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Pool$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Pool$1.class index 70b91c353..f78c2187f 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Pool$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Pool$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Pool.class b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Pool.class index ae81f2b55..5a985436a 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Pool.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Pool.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Purpose$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Purpose$1.class index f9571de9c..93d4ce1e0 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Purpose$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Purpose$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Purpose.class b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Purpose.class index 27a3a8a62..609502e9d 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Purpose.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction$Purpose.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction.class b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction.class index 11ab3df1d..eb49459ab 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Transaction.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Transaction.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$1.class index b9dd9d962..3ab8abc81 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Builder.class index 9310f902b..c22b4a492 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$IXType$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$IXType$1.class index 4aa99171a..32258cd09 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$IXType$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$IXType$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$IXType.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$IXType.class index f82846b0d..6068e843c 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$IXType.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$IXType.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Source$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Source$1.class index 4f3fd6e7a..d4fb7dbfe 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Source$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Source$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Source.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Source.class index 1febf36da..1a65df0e2 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Source.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Source.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Type$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Type$1.class index 306ebfbb7..4c177c8ec 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Type$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Type$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Type.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Type.class index c6834f23b..641be8b1d 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Type.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence$Type.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence.class index 509fd1c15..70c8b7483 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionConfidence.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput$1.class index 1137cac68..b1de1d788 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput$Builder.class index a9d4ad1d7..a7c01f54d 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput.class index e311ce5f3..9c9a5ae6b 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInput.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInputOrBuilder.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInputOrBuilder.class index 602edbb12..211e3a759 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInputOrBuilder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionInputOrBuilder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput$1.class index f4dedf44f..5659b2b91 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput$Builder.class index 136a8387b..1b4faf0af 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput.class index 64c5c95fd..cdae7a5fd 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionOutput.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner$1.class index 4a115b684..469e30203 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner$Builder.class index 52824accd..d841b5b70 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner.class b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner.class index 9fb93aefd..9c4b75da9 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner.class and b/core/out/production/classes/org/pivxj/wallet/Protos$TransactionSigner.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$1.class index 60c56597c..467b34638 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$Builder.class b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$Builder.class index 9aab53486..ff5a5af45 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$Builder.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$Builder.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$EncryptionType$1.class b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$EncryptionType$1.class index 61230e269..5c4e1520d 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$EncryptionType$1.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$EncryptionType$1.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$EncryptionType.class b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$EncryptionType.class index fd95a2a70..5e84e4f99 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$EncryptionType.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet$EncryptionType.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet.class b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet.class index f597f885f..18a96045c 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos$Wallet.class and b/core/out/production/classes/org/pivxj/wallet/Protos$Wallet.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Protos.class b/core/out/production/classes/org/pivxj/wallet/Protos.class index 9ac1cca02..ab80aa6b3 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Protos.class and b/core/out/production/classes/org/pivxj/wallet/Protos.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$10.class b/core/out/production/classes/org/pivxj/wallet/Wallet$10.class index d026fd06a..e888bcb6a 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$10.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$10.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$11.class b/core/out/production/classes/org/pivxj/wallet/Wallet$11.class index 64ce2abae..7dbd22a7d 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$11.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$11.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$3.class b/core/out/production/classes/org/pivxj/wallet/Wallet$3.class index 6d482ba14..def9a5464 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$3.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$3.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$4.class b/core/out/production/classes/org/pivxj/wallet/Wallet$4.class index 3ffcee741..ad39562a3 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$4.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$4.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$5.class b/core/out/production/classes/org/pivxj/wallet/Wallet$5.class index b47af5c51..e276b74ad 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$5.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$5.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$6.class b/core/out/production/classes/org/pivxj/wallet/Wallet$6.class index 167387c6f..76ea28046 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$6.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$6.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$7.class b/core/out/production/classes/org/pivxj/wallet/Wallet$7.class index b24f02e9a..35fa68fef 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$7.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$7.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$8.class b/core/out/production/classes/org/pivxj/wallet/Wallet$8.class index 1b30e61b1..6388610bd 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$8.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$8.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$9.class b/core/out/production/classes/org/pivxj/wallet/Wallet$9.class index f782fa78c..2d9063ea0 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$9.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$9.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$BalanceFutureRequest.class b/core/out/production/classes/org/pivxj/wallet/Wallet$BalanceFutureRequest.class index 0f0d2125b..c0f9bffad 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$BalanceFutureRequest.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$BalanceFutureRequest.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$BalanceType.class b/core/out/production/classes/org/pivxj/wallet/Wallet$BalanceType.class index 954728f30..577683b75 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$BalanceType.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$BalanceType.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$CompletionException.class b/core/out/production/classes/org/pivxj/wallet/Wallet$CompletionException.class index caaa79a5a..608d2bc6a 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$CompletionException.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$CompletionException.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$CouldNotAdjustDownwards.class b/core/out/production/classes/org/pivxj/wallet/Wallet$CouldNotAdjustDownwards.class index 073817f0f..5f8d7be3f 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$CouldNotAdjustDownwards.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$CouldNotAdjustDownwards.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$DustySendRequested.class b/core/out/production/classes/org/pivxj/wallet/Wallet$DustySendRequested.class index 7616da5d3..0bd1398a1 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$DustySendRequested.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$DustySendRequested.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$ExceededMaxTransactionSize.class b/core/out/production/classes/org/pivxj/wallet/Wallet$ExceededMaxTransactionSize.class index 5af7c532c..5cf0ad41c 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$ExceededMaxTransactionSize.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$ExceededMaxTransactionSize.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$FeeCalculation.class b/core/out/production/classes/org/pivxj/wallet/Wallet$FeeCalculation.class index 4685bbdd3..d0841753d 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$FeeCalculation.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$FeeCalculation.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$FreeStandingTransactionOutput.class b/core/out/production/classes/org/pivxj/wallet/Wallet$FreeStandingTransactionOutput.class index df392eaeb..19f932487 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$FreeStandingTransactionOutput.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$FreeStandingTransactionOutput.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$MissingSigsMode.class b/core/out/production/classes/org/pivxj/wallet/Wallet$MissingSigsMode.class index 6361bab62..215003408 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$MissingSigsMode.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$MissingSigsMode.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$MultipleOpReturnRequested.class b/core/out/production/classes/org/pivxj/wallet/Wallet$MultipleOpReturnRequested.class index cdaf01374..6349fcb52 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$MultipleOpReturnRequested.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$MultipleOpReturnRequested.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$SendResult.class b/core/out/production/classes/org/pivxj/wallet/Wallet$SendResult.class index 3133b2d19..df59f8dbc 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$SendResult.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$SendResult.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet$TxOffsetPair.class b/core/out/production/classes/org/pivxj/wallet/Wallet$TxOffsetPair.class index b3b187eb7..2ae87d3dd 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet$TxOffsetPair.class and b/core/out/production/classes/org/pivxj/wallet/Wallet$TxOffsetPair.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/Wallet.class b/core/out/production/classes/org/pivxj/wallet/Wallet.class index ddfd0d14f..1e45d9784 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/Wallet.class and b/core/out/production/classes/org/pivxj/wallet/Wallet.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/WalletProtobufSerializer$2.class b/core/out/production/classes/org/pivxj/wallet/WalletProtobufSerializer$2.class index a8ae6f391..4e69d34db 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/WalletProtobufSerializer$2.class and b/core/out/production/classes/org/pivxj/wallet/WalletProtobufSerializer$2.class differ diff --git a/core/out/production/classes/org/pivxj/wallet/WalletProtobufSerializer.class b/core/out/production/classes/org/pivxj/wallet/WalletProtobufSerializer.class index 5d68c44d2..791bbd5de 100644 Binary files a/core/out/production/classes/org/pivxj/wallet/WalletProtobufSerializer.class and b/core/out/production/classes/org/pivxj/wallet/WalletProtobufSerializer.class differ diff --git a/core/out/test/classes/org/pivxj/wallet/MultiWalletTest.class b/core/out/test/classes/org/pivxj/wallet/MultiWalletTest.class index eb9b2564e..ebadd56f7 100644 Binary files a/core/out/test/classes/org/pivxj/wallet/MultiWalletTest.class and b/core/out/test/classes/org/pivxj/wallet/MultiWalletTest.class differ diff --git a/core/src/main/java/host/furszy/zerocoinj/protocol/GenWitMessage.java b/core/src/main/java/host/furszy/zerocoinj/protocol/GenWitMessage.java index e4499dbe1..1ae68e6f1 100644 --- a/core/src/main/java/host/furszy/zerocoinj/protocol/GenWitMessage.java +++ b/core/src/main/java/host/furszy/zerocoinj/protocol/GenWitMessage.java @@ -7,9 +7,12 @@ import java.io.IOException; import java.math.BigInteger; import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; public class GenWitMessage extends Message { + public static final AtomicInteger requestNumInd = new AtomicInteger(0); + private BloomFilter bloomFilter; private int startHeight; private CoinDenomination den; @@ -28,16 +31,35 @@ public GenWitMessage( long randomNonce ) { super(params); - this.requestNum = 10; this.startHeight = startHeight; this.den = den; - this.bloomFilter = new BloomFilter(elements, falsePositiveRate, randomNonce); + this.bloomFilter = new BloomFilter(elements, falsePositiveRate, randomNonce,2); + } + + public void complete(){ + this.requestNum = requestNumInd.incrementAndGet(); + } + + public void setStartHeight(int startHeight) { + this.startHeight = startHeight; } public Integer getRequestNum() { return requestNum; } + public BloomFilter getFilter() { + return bloomFilter; + } + + public int getStartHeight() { + return startHeight; + } + + public CoinDenomination getDen() { + return den; + } + public void insert(BigInteger data){ this.bloomFilter.insert(Utils.serializeBigInteger(data)); } diff --git a/core/src/main/java/host/furszy/zerocoinj/protocol/PubcoinsMessage.java b/core/src/main/java/host/furszy/zerocoinj/protocol/PubcoinsMessage.java index c4334428a..7a959e8e7 100644 --- a/core/src/main/java/host/furszy/zerocoinj/protocol/PubcoinsMessage.java +++ b/core/src/main/java/host/furszy/zerocoinj/protocol/PubcoinsMessage.java @@ -14,6 +14,7 @@ public class PubcoinsMessage extends Message { private BigInteger accWitnessValue; private List list; private long requestNum; + private boolean hasRequestFailed; public PubcoinsMessage(NetworkParameters params, byte[] payload, int offset, int lenght) throws ProtocolException { super( @@ -40,12 +41,15 @@ public PubcoinsMessage(NetworkParameters params, BigInteger accValue, BigInteger protected void parse() throws ProtocolException { list = new ArrayList<>(); requestNum = readUint32(); - accValue = readBignum(); - accWitnessValue = readBignum(); - long size = readUint32(); - for (int i = 0; i < size; i++) { - list.add(readBignum()); - } + if (hasMoreBytes()) { + accValue = readBignum(); + accWitnessValue = readBignum(); + long size = readUint32(); + for (int i = 0; i < size; i++) { + list.add(readBignum()); + } + }else + hasRequestFailed = true; length = cursor; } @@ -65,6 +69,10 @@ public byte[] bitcoinSerialize() { } } + public boolean isHasRequestFailed() { + return hasRequestFailed; + } + public List getList() { return list; } diff --git a/core/src/main/java/host/furszy/zerocoinj/wallet/CannotSpendCoinsException.java b/core/src/main/java/host/furszy/zerocoinj/wallet/CannotSpendCoinsException.java new file mode 100644 index 000000000..8ed7cd3cf --- /dev/null +++ b/core/src/main/java/host/furszy/zerocoinj/wallet/CannotSpendCoinsException.java @@ -0,0 +1,18 @@ +package host.furszy.zerocoinj.wallet; + +public class CannotSpendCoinsException extends Exception { + public CannotSpendCoinsException() { + } + + public CannotSpendCoinsException(String message) { + super(message); + } + + public CannotSpendCoinsException(String message, Throwable cause) { + super(message, cause); + } + + public CannotSpendCoinsException(Throwable cause) { + super(cause); + } +} diff --git a/core/src/main/java/host/furszy/zerocoinj/wallet/InvalidSpendException.java b/core/src/main/java/host/furszy/zerocoinj/wallet/InvalidSpendException.java new file mode 100644 index 000000000..cd3f8d9a5 --- /dev/null +++ b/core/src/main/java/host/furszy/zerocoinj/wallet/InvalidSpendException.java @@ -0,0 +1,11 @@ +package host.furszy.zerocoinj.wallet; + +public class InvalidSpendException extends Exception { + public InvalidSpendException(String s) { + super(s); + } + + public InvalidSpendException(Throwable cause) { + super(cause); + } +} diff --git a/core/src/main/java/host/furszy/zerocoinj/wallet/MultiWallet.java b/core/src/main/java/host/furszy/zerocoinj/wallet/MultiWallet.java index 35a068429..2c99221ce 100644 --- a/core/src/main/java/host/furszy/zerocoinj/wallet/MultiWallet.java +++ b/core/src/main/java/host/furszy/zerocoinj/wallet/MultiWallet.java @@ -1,6 +1,8 @@ package host.furszy.zerocoinj.wallet; +import com.zerocoinj.core.ZCoin; import com.zerocoinj.core.context.ZerocoinContext; +import com.zerocoinj.utils.JniBridgeWrapper; import host.furszy.zerocoinj.MultiWalletFiles; import host.furszy.zerocoinj.WalletFilesInterface; import host.furszy.zerocoinj.wallet.files.Listener; @@ -20,6 +22,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.math.BigInteger; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Set; @@ -42,11 +46,22 @@ public class MultiWallet{ protected final ReentrantLock lock; + public enum WalletType{ + PIV, ZPIV, ALL + } + public MultiWallet(NetworkParameters params, ZerocoinContext zContext, DeterministicSeed seed){ + this(params,zContext,seed,-1); + } + + public MultiWallet(NetworkParameters params, ZerocoinContext zContext, DeterministicSeed seed, int lookaheadSize){ this.lock = Threading.lock("MultiWallet_1"); this.seed = seed; - this.pivWallet = new Wallet(params,new KeyChainGroup(params, seed, BIP44_PIV)); - this.zWallet = new ZWallet(params, zContext, seed); + KeyChainGroup keyChainGroup = new KeyChainGroup(params, seed, BIP44_PIV); + if (lookaheadSize > 0) + keyChainGroup.setLookaheadSize(lookaheadSize); + this.pivWallet = new Wallet(params,keyChainGroup); + this.zWallet = new ZWallet(params, zContext, seed, lookaheadSize); } public MultiWallet(DeterministicSeed seed, List wallets) { @@ -94,6 +109,18 @@ public void addWalletFrom(BlockChain blockChain) { zWallet.addWalletFrom(blockChain); } + public boolean isEveryOutputSpent(Transaction tx, WalletType walletType){ + if (walletType == WalletType.PIV){ + return tx.isEveryOwnedOutputSpent(pivWallet); + }else if (walletType == WalletType.ZPIV){ + return tx.isEveryOwnedOutputSpent(getZpivWallet()); + }else { + boolean isSpent = tx.isEveryOwnedOutputSpent(pivWallet); + if (!isSpent) return false; + return tx.isEveryOwnedOutputSpent(getZpivWallet()); + } + } + public void commitTx(Transaction tx) { boolean isZcMint = false; for (TransactionOutput output : tx.getOutputs()) { @@ -141,6 +168,21 @@ public Set listTransactions(){ return list; } + public Collection listPendingTransactions(){ + Collection list = pivWallet.getPendingTransactions(); + for (Transaction transaction : zWallet.getPendingTransactions()) { + if (!list.contains(transaction)){ + list.add(transaction); + } + } + return list; + } + + public void setKeyChainGroupLookaheadThreshold(int n) { + pivWallet.setKeyChainGroupLookaheadThreshold(n); + zWallet.getWallet().setKeyChainGroupLookaheadThreshold(n); + } + public void cleanup(){ pivWallet.cleanup(); zWallet.cleanup(); @@ -225,6 +267,10 @@ public List listUnspent() { return pivWallet.getUnspents(); } + public List listZpivUnspent() { + return zWallet.getUnspents(); + } + public boolean isAddressMine(Address address) { return pivWallet.isPubKeyHashMine(address.getHash160()); } @@ -260,6 +306,50 @@ public Coin getZpivUnspensableBalance() { return zWallet.getUnspendableBalance(); } + public ZCoin getZcoinAssociated(BigInteger commitmentValue){ + return zWallet.getZcoinAssociated(commitmentValue); + } + + public ZCoin getZcoinAssociatedToSerial(BigInteger serial){ + return zWallet.getZcoinAssociatedToSerial(serial); + } + + public List freshZcoins(int n) { + return zWallet.freshZcoins(n); + } + + public TransactionOutput getMintTransaction(BigInteger serial, WalletType walletType){ + ZCoin coin = zWallet.getZcoinAssociatedToSerial(serial); + if (coin == null) return null; + if (walletType == WalletType.ZPIV){ + return getMintTransaction(zWallet.getWallet(), coin); + }else if (walletType == WalletType.PIV){ + return getMintTransaction(pivWallet, coin); + }else { + TransactionOutput output = getMintTransaction(zWallet.getWallet(), coin); + if (output != null) return output; + return getMintTransaction(pivWallet, coin); + } + } + + private TransactionOutput getMintTransaction(Wallet wallet, ZCoin coin){ + for (Transaction transaction : wallet.getTransactions(true)) { + for (TransactionOutput output : transaction.getOutputs()) { + if (output.isZcMint() && Utils.areBigIntegersEqual(output.getScriptPubKey().getCommitmentValue(), coin.getCommitment().getCommitmentValue())){ + return output; + } + } + } + return null; + } + + public boolean addTx(Transaction tx, WalletType walletType){ + if (walletType == WalletType.ZPIV){ + return zWallet.getWallet().maybeCommitTx(tx); + } + return false; + } + /** * TODO: Add fee here... * @param amount @@ -276,11 +366,14 @@ public SendRequest createMintRequest(Coin amount) throws InsufficientMoneyExcept public SendRequest createSpendRequest(Address to, Coin amount) throws InsufficientMoneyException { Transaction tx = zWallet.createSpend(amount); tx.addOutput(amount, to); - return SendRequest.forTx(tx); + SendRequest sendRequest = SendRequest.forTx(tx); + // TODO: check if change this for a new zpiv mint is a good idea.. + sendRequest.changeAddress = pivWallet.freshReceiveAddress(); + return sendRequest; } - public void spendZpiv(SendRequest request, PeerGroup peerGroup, ExecutorService executor) throws InsufficientMoneyException{ - zWallet.completeSendRequestAndWaitSync(request,peerGroup,executor); + public Transaction spendZpiv(SendRequest request, PeerGroup peerGroup, ExecutorService executor, JniBridgeWrapper wrapper) throws InsufficientMoneyException, CannotSpendCoinsException { + return zWallet.completeSendRequestAndWaitSync(wrapper,request,peerGroup,executor); } diff --git a/core/src/main/java/host/furszy/zerocoinj/wallet/ZCSpendRequest.java b/core/src/main/java/host/furszy/zerocoinj/wallet/ZCSpendRequest.java index f61edbba9..8d87ac1b9 100644 --- a/core/src/main/java/host/furszy/zerocoinj/wallet/ZCSpendRequest.java +++ b/core/src/main/java/host/furszy/zerocoinj/wallet/ZCSpendRequest.java @@ -1,5 +1,6 @@ package host.furszy.zerocoinj.wallet; +import com.google.common.collect.Lists; import com.zerocoinj.core.CoinDenomination; import com.zerocoinj.core.CoinSpend; import com.zerocoinj.core.SpendType; @@ -17,17 +18,19 @@ import org.pivxj.script.ScriptOpCodes; import org.pivxj.utils.Pair; import org.pivxj.wallet.SendRequest; +import org.pivxj.wallet.exceptions.RequestFailedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.util.encoders.Hex; import java.math.BigInteger; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.*; + +import static com.google.common.primitives.Ints.min; public class ZCSpendRequest implements Callable,OnGetDataResponseEventListener { @@ -36,15 +39,22 @@ public class ZCSpendRequest implements Callable,OnGetDataResponseEv private SendRequest sendRequest; private PeerGroup peerGroup; private ZerocoinContext zerocoinContext; - private ConcurrentHashMap> waitingRequests = new ConcurrentHashMap<>(); + private List> waitingRequests = new ArrayList<>(); + private ConcurrentHashMap,GenWitMessage>> requests; + private LinkedBlockingQueue messagesQueue = new LinkedBlockingQueue<>(); private Transaction transaction; - private final Object lock; + private Sha256Hash txHashOutput; public ZCSpendRequest(SendRequest sendRequest, PeerGroup peerGroup) { this.sendRequest = sendRequest; + this.transaction = sendRequest.tx; + Transaction temp = new Transaction(this.transaction.getParams()); + for (TransactionOutput output : this.transaction.getOutputs()) { + temp.addOutput(output); + } + this.txHashOutput = temp.getHash(); this.peerGroup = peerGroup; this.zerocoinContext = Context.get().zerocoinContext; - this.lock = new ReentrantLock(); } public SendRequest getSendRequest() { @@ -56,27 +66,59 @@ public PeerGroup getPeerGroup() { } public void addWaitingRequest(GenWitMessage genWitMessage, ZCoin zCoin){ - if (waitingRequests.containsKey(genWitMessage.getRequestNum())) throw new IllegalArgumentException("Duplicated request num"); - waitingRequests.put(genWitMessage.getRequestNum(), new Pair<>(zCoin, genWitMessage)); + if (zCoin.getCoinDenomination() == CoinDenomination.ZQ_ERROR) throw new IllegalArgumentException("Invalid denomination"); + waitingRequests.add(new Pair<>(zCoin, genWitMessage)); } @Override public Transaction call() throws Exception { if (this.peerGroup.getConnectedPeers().isEmpty()) throw new IllegalStateException("No peers online"); + Map,GenWitMessage>> genWitByDenomination = new HashMap<>(); + + for (Pair entry : waitingRequests) { + GenWitMessage genWitMessage = entry.getSecond(); + if (genWitByDenomination.containsKey(genWitMessage.getDen())){ + Pair,GenWitMessage> pair = genWitByDenomination.get(genWitMessage.getDen()); + GenWitMessage currentGenWit = pair.getSecond(); + // merge the current one + currentGenWit.getFilter().merge(genWitMessage.getFilter()); + // start height must be the minimum + currentGenWit.setStartHeight(min(currentGenWit.getStartHeight(), genWitMessage.getStartHeight())); + pair.getFirst().add(entry.getFirst()); + }else { + // create a new one + Pair, GenWitMessage> pair = new Pair<>(Lists.newArrayList(entry.getFirst()),genWitMessage); + genWitByDenomination.put(genWitMessage.getDen(), pair); + genWitMessage.complete(); + } + } + + requests = new ConcurrentHashMap<>(); + for (Map.Entry, GenWitMessage>> entry : genWitByDenomination.entrySet()) { + requests.put(entry.getValue().getSecond().getRequestNum(), entry.getValue()); + } + // TODO: send this to several peers and not just one Peer peer0 = this.peerGroup.getConnectedPeers().get(0); peer0.addOnGetDataResponseEventListener(this); - - for (Map.Entry> entry : waitingRequests.entrySet()) { + for (Map.Entry, GenWitMessage>> entry : genWitByDenomination.entrySet()) { peer0.sendMessage(entry.getValue().getSecond()); } log.info("Waiting for node response.."); // Now wait for the completeness.. - synchronized (lock){ - lock.wait(); + while (true){ + // Now spend it if all of the inputs are completed + if (requests.size() == 0) { + break; + } + + PubcoinsMessage message = messagesQueue.take(); + onPubcoinReceived(message); + requests.remove((int) message.getRequestNum()); } + log.info("Transaction ready!"); for (Peer peer : peerGroup.getConnectedPeers()) { // Remove this listener now @@ -85,98 +127,123 @@ public Transaction call() throws Exception { return transaction; } - @Override - public void onResponseReceived(PubcoinsMessage pubcoinsMessage) { - log.info("onResponseReceived: " + pubcoinsMessage.toString()); - if (! waitingRequests.containsKey((int) pubcoinsMessage.getRequestNum())) return; - Pair pair = waitingRequests.get((int) pubcoinsMessage.getRequestNum()); - GenWitMessage request = pair.getSecond(); - ZCoin coinToSpend = pair.getFirst(); - if (request != null){ - List list = pubcoinsMessage.getList(); - System.out.println("amount of data received: " + list.size()); - // Create accumulator: - - // First check that my commitment is in the filtered list - if (!list.contains(coinToSpend.getCommitment().getCommitmentValue())) { - // TODO: Notify fail here.. - log.error("Pubcoins response list doesn't contains our commitment value.., check core sources"); - return; - } - - // Accumulator - Accumulator acc = new Accumulator( - zerocoinContext.accumulatorParams, - CoinDenomination.ZQ_ONE, - pubcoinsMessage.getAccValue() - ); - - // Now accumulate the pubcoins to the result to obtain the same witness that is created by the rpc method. - Accumulator accWit = new Accumulator( - zerocoinContext.accumulatorParams, - CoinDenomination.ZQ_ONE, - pubcoinsMessage.getAccWitnessValue() - - ); - AccumulatorWitness witness = new AccumulatorWitness(accWit, coinToSpend); - - int i = 0; - for (BigInteger bigInteger : list) { - witness.addElementUnchecked(bigInteger); - if (i % 100 == 0) - log.info("coin incremented: " + i); - i++; - } - - log.info("Witness: " + witness.getValue()); - if (!witness.verifyWitness(acc,coinToSpend)){ - log.error("Verify witness failed"); - return; - // Assert.assertTrue("Verify failed", witness.verifyWitness(acc, mintedCoin)); - } - log.info("Valid accumulator"); - + public void onPubcoinReceived(PubcoinsMessage pubcoinsMessage) throws InvalidSpendException { - // 3) Complete the tx - Transaction transaction = sendRequest.tx; - - // Accumulator checksum - BigInteger accChecksum = BigInteger.valueOf( - Accumulators.getChecksum(acc.getValue()) - ); - - CoinSpend coinSpend = new CoinSpend( - zerocoinContext, - coinToSpend, - acc, - accChecksum, - witness, - transaction.getHash(), - SpendType.SPEND, - null - ); - - - if (!coinSpend.verify(acc)){ - log.error("CoinSpend not valid"); - return; - // Assert.assertTrue("CoinSpend not valid",coinSpend.verify(acc)); - } - - transaction = add(transaction, coinSpend, coinToSpend.getCommitment().getCommitmentValue()); - - // Now spend it if all of the inputs are completed - waitingRequests.remove((int) pubcoinsMessage.getRequestNum()); - if (waitingRequests.size() == 0){ - synchronized (lock) { - this.transaction = transaction; - lock.notify(); + Pair,GenWitMessage> pair = requests.get((int) pubcoinsMessage.getRequestNum()); + GenWitMessage request = pair.getSecond(); + ArrayList coins = pair.getFirst(); + + if (request != null) { + for (ZCoin coinToSpend : coins) { + + try { + if (pubcoinsMessage.isHasRequestFailed()) { + log.info("Request have failed for {}", pair); + throw new RequestFailedException(); + } + List list = pubcoinsMessage.getList(); + System.out.println("amount of data received: " + list.size()); + // Create accumulator: + + // First check that my commitment is in the filtered list + if (!list.contains(coinToSpend.getCommitment().getCommitmentValue())) { + // TODO: Notify fail here.. + log.error("Pubcoins response list doesn't contains our commitment value.."); + throw new InvalidSpendException("Pubcoins response list doesn't contains our commitment value.., check core sources"); + } + + // Accumulator + Accumulator acc = new Accumulator( + zerocoinContext.accumulatorParams, + coinToSpend.getCoinDenomination(), + pubcoinsMessage.getAccValue() + ); + + // Now accumulate the pubcoins to the result to obtain the same witness that is created by the rpc method. + Accumulator accWit = new Accumulator( + zerocoinContext.accumulatorParams, + coinToSpend.getCoinDenomination(), + pubcoinsMessage.getAccWitnessValue() + + ); + AccumulatorWitness witness = new AccumulatorWitness(accWit, coinToSpend); + + int i = 0; + for (BigInteger bigInteger : list) { + witness.addElementUnchecked(bigInteger); + if (i % 100 == 0) + log.info("coin incremented: " + i); + i++; + } + + log.info("Witness: " + witness.getValue()); + if (!witness.verifyWitness(acc, coinToSpend)) { + log.error("Verify witness failed"); + throw new InvalidSpendException("Verify witness failed"); + } + log.info("Valid accumulator"); + + log.info("accumulator: " + acc.getValue()); + log.info("witness: " + witness.getValue()); + + + // 3) Complete the tx + + // Accumulator checksum + BigInteger accChecksum = BigInteger.valueOf( + Accumulators.getChecksum(acc.getValue()) + ); + + CoinSpend coinSpend = new CoinSpend( + zerocoinContext, + coinToSpend, + acc, + accChecksum, + witness, + txHashOutput, + SpendType.SPEND, + null + ); + + + if (!coinSpend.verify(acc)) { + log.error("CoinSpend not valid"); + throw new InvalidSpendException("CoinSpend verify failed"); + } + + if (!coinSpend.hasValidSignature()) { + log.error(String.format("CoinSpend signature invalid, coinSpend: %s", coinSpend)); + //throw new InvalidSpendException("CoinSpend signature invalid"); + } + + System.out.println("coin randomness: " + coinToSpend); + System.out.println("coin spend: " + coinSpend); + System.out.println("private key: " + coinSpend.getPubKey().getPrivateKeyAsHex()); + + add(coinSpend, coinToSpend.getCommitment().getCommitmentValue()); + + } catch (InvalidSpendException e) { + log.info("InvalidSpendException", e); + throw e; + } catch (Exception e) { + log.info("Exception creating a spend", e); + throw new InvalidSpendException(e); } } + }else { + log.warn("Request returned null for {}" + pubcoinsMessage); } + } - private Transaction add(Transaction transaction, CoinSpend coinSpend, BigInteger commitmentValue){ + @Override + public void onResponseReceived(final PubcoinsMessage pubcoinsMessage) { + log.info("onResponseReceived: " + pubcoinsMessage.toString()); + if (! requests.containsKey((int) pubcoinsMessage.getRequestNum())) return; + messagesQueue.offer(pubcoinsMessage); + } + + private synchronized void add(CoinSpend coinSpend, BigInteger commitmentValue){ // zc_spend input byte[] coinSpendBytes = coinSpend.bitcoinSerialize(); log.info("Coin spend bytes length: " + coinSpendBytes.length); @@ -195,6 +262,7 @@ private Transaction add(Transaction transaction, CoinSpend coinSpend, BigInteger log.info("program: " + Hex.toHexString(program)); TransactionInput transactionInput = new TransactionInput(transaction.getParams(), transaction, program); + //use nSequence as a shorthand lookup of denomination //NOTE that this should never be used in place of checking the value in the final blockchain acceptance/verification //of the transaction @@ -205,7 +273,13 @@ private Transaction add(Transaction transaction, CoinSpend coinSpend, BigInteger List realInputs = new ArrayList<>(); for (TransactionInput input : inputs) { - if (input.getConnectedOutput().isZcMint() && + if (input.getConnectedOutput() == null){ + log.info("Not connected input.. should be one of the new ones.."); + realInputs.add(input); + continue; + } + boolean isZcMint = input.getConnectedOutput().isZcMint(); + if (isZcMint && !( Utils.areBigIntegersEqual(input.getConnectedOutput().getScriptPubKey().getCommitmentValue(), commitmentValue)) ){ realInputs.add(input); } @@ -220,7 +294,5 @@ private Transaction add(Transaction transaction, CoinSpend coinSpend, BigInteger System.out.println(transaction); System.out.println("Coin spend inputs program: " + Hex.toHexString(transaction.getInput(0).getScriptBytes())); - - return transaction; } } diff --git a/core/src/main/java/host/furszy/zerocoinj/wallet/ZWallet.java b/core/src/main/java/host/furszy/zerocoinj/wallet/ZWallet.java index addccda54..903dbdbc4 100644 --- a/core/src/main/java/host/furszy/zerocoinj/wallet/ZWallet.java +++ b/core/src/main/java/host/furszy/zerocoinj/wallet/ZWallet.java @@ -5,6 +5,7 @@ import com.zerocoinj.core.ZCoin; import com.zerocoinj.core.context.ZerocoinContext; import com.zerocoinj.core.exceptions.InvalidSerialException; +import com.zerocoinj.utils.JniBridgeWrapper; import host.furszy.zerocoinj.MultiWalletFiles; import host.furszy.zerocoinj.WalletFilesInterface; import host.furszy.zerocoinj.wallet.files.Listener; @@ -34,10 +35,12 @@ public class ZWallet { private NetworkParameters params; private Wallet zPivWallet; - public ZWallet(NetworkParameters params, ZerocoinContext zContext, DeterministicSeed seed) { + public ZWallet(NetworkParameters params, ZerocoinContext zContext, DeterministicSeed seed, int lookaheadSize) { this.params = params; this.zContext = zContext; KeyChainGroup keyChainGroupZpiv = new KeyChainGroup(params, seed, BIP44_ZPIV); + if (lookaheadSize > 0) + keyChainGroupZpiv.setLookaheadSize(lookaheadSize); zPivWallet = new Wallet(params,keyChainGroupZpiv); } @@ -107,7 +110,7 @@ public Transaction createSpend(Coin amount) throws InsufficientMoneyException { // Now start, start from the bigger den and decrease it until the value is completed Coin temp = Coin.valueOf(amount.value); for (CoinDenomination coinDenomination : CoinDenomination.invertedValues()) { - if (!orderedUnspents.containsKey(coinDenomination))continue; + if (!orderedUnspents.containsKey(coinDenomination)) continue; List outputs = orderedUnspents.get(coinDenomination); if (temp.isZero()) break; Coin denValue = Coin.valueOf(coinDenomination.getDenomination(),0); @@ -118,7 +121,9 @@ public Transaction createSpend(Coin amount) throws InsufficientMoneyException { long amountOfThisDenom = divisibleForDenomination.divide(denValue); for (int i = 0; i < amountOfThisDenom; i++) { // todo: I should get the old one here.. - tx.addInput(outputs.get(i)); + TransactionOutput out = outputs.get(i); + if (out.getParentTransaction().getConfidence().getDepthInBlocks() >= CoinDefinition.MINT_REQUIRED_CONFIRMATIONS) + tx.addInput(outputs.get(i)); } temp = Coin.valueOf(mod); } @@ -172,22 +177,20 @@ public void addWalletFrom(BlockChain blockChain) { blockChain.addWallet(zPivWallet); } - public void completeSendRequestAndWaitSync(SendRequest request, PeerGroup peerGroup, ExecutorService executor) { + public Transaction completeSendRequestAndWaitSync(JniBridgeWrapper jniBridgeWrapper, SendRequest request, PeerGroup peerGroup, ExecutorService executor) throws CannotSpendCoinsException { try { + Context.get().zerocoinContext.jniBridge = jniBridgeWrapper; + if (request.tx.getOutputs().isEmpty()) throw new IllegalArgumentException("SendRequest transactions outputs cannot be null, add the outputs values before call this method"); ZCSpendRequest spendRequest = new ZCSpendRequest(request, peerGroup); zPivWallet.completeSendRequest(spendRequest); - Transaction tx = executor.submit(spendRequest).get(5, TimeUnit.MINUTES); + Transaction tx = executor.submit(spendRequest).get(15, TimeUnit.MINUTES); logger.info("Tx created!, " + tx); - peerGroup.broadcastTransaction(tx,1,false).future().get(1, TimeUnit.MINUTES); + tx = peerGroup.broadcastTransaction(tx,1,false).broadcast().get(1, TimeUnit.MINUTES); logger.info("Tx broadcasted!, " + tx); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } catch (TimeoutException e) { - e.printStackTrace(); + return tx; } catch (Exception e){ - e.printStackTrace(); + logger.info("Exception in completeSendRequestAndWaitSync", e); + throw new CannotSpendCoinsException(e); } } @@ -239,4 +242,24 @@ public Coin getUnspendableBalance() { public Coin getBalance(Wallet.BalanceType type) { return zPivWallet.getBalance(type); } + + public Collection getPendingTransactions() { + return zPivWallet.getPendingTransactions(); + } + + public List getUnspents() { + return zPivWallet.getUnspents(); + } + + public ZCoin getZcoinAssociated(BigInteger commitmentValue) { + return zPivWallet.getActiveKeyChain().getZcoinsAssociated(commitmentValue); + } + + public ZCoin getZcoinAssociatedToSerial(BigInteger serial) { + return zPivWallet.getActiveKeyChain().getZcoinsAssociatedToSerial(serial); + } + + public List freshZcoins(int n) { + return zPivWallet.freshZcoins(KeyChain.KeyPurpose.RECEIVE_FUNDS,n); + } } diff --git a/core/src/main/java/org/pivxj/core/AbstractBlockChain.java b/core/src/main/java/org/pivxj/core/AbstractBlockChain.java index ff0342505..79ca1c18a 100644 --- a/core/src/main/java/org/pivxj/core/AbstractBlockChain.java +++ b/core/src/main/java/org/pivxj/core/AbstractBlockChain.java @@ -459,18 +459,14 @@ private boolean add(Block block, boolean tryConnecting, // article here for more details: https://bitcoinj.github.io/security-model try { block.verifyHeader(); - //System.out.println("New block previous hash: "+block.getPrevBlockHash()); storedPrev = getStoredBlockInCurrentScope(block.getPrevBlockHash()); - if (storedPrev!=null) { - //System.out.println("New block, previous stored block from db: " + storedPrev.getHeader().getHashAsString()); + if (storedPrev != null) { checkArgument(block.getPrevBlockHash().equals(storedPrev.getHeader().getHash()), "Database saving shit.. prev hash block: " + block.getPrevBlockHash() + ", db prev hash: " + storedPrev.getHeader().getHashAsString()); } if (storedPrev != null) { height = storedPrev.getHeight() + 1; - //System.out.println("Adding Block: "+height+" hash "+block.getHashAsString()+", Prev block "+storedPrev.getHeight()+" hash: "+block.getPrevBlockHash().toString()); } else { - //System.out.println("block height unknown"); height = Block.BLOCK_HEIGHT_UNKNOWN; } flags = params.getBlockVerificationFlags(block, versionTally, height); @@ -496,10 +492,7 @@ private boolean add(Block block, boolean tryConnecting, checkState(lock.isHeldByCurrentThread()); // It connects to somewhere on the chain. Not necessarily the top of the best known chain. //context.checkDifficultyTransitions(storedPrev, block, blockStore); - //todo furszy: i'm not checking the difficulty yet - //todo: this should be checked on a MN wallet service. //checkDifficultyTransitions(storedPrev, block); - //System.out.println("going to connect block with accumulator: "+block.getAccumulator().toString()); connectBlock(block, storedPrev, shouldVerifyTransactions(), filteredTxHashList, filteredTxn); } @@ -547,9 +540,6 @@ private void connectBlock(final Block block, StoredBlock storedPrev, boolean exp } StoredBlock head = getChainHead(); - // System.out.println("New block: "+block.toString()); - //System.out.println("Head height: "+head.getHeight() + " hash: "+head.getHeader().getHashAsString() - // + " Previous block stored height: "+storedPrev.getHeight()); if (storedPrev.equals(head)) { if (filtered && filteredTxn.size() > 0) { log.debug("Block {} connects to top of best chain with {} transaction(s) of which we were sent {}", @@ -584,12 +574,6 @@ private void connectBlock(final Block block, StoredBlock storedPrev, boolean exp log.debug("Chain is now {} blocks high, running listeners", newStoredBlock.getHeight()); informListenersForNewBlock(block, NewBlockType.BEST_CHAIN, filteredTxHashList, filteredTxn, newStoredBlock); } else { - //System.out.println("#####################"); - //System.out.println("block not connect to the blockchain heads.."); - //System.out.println("head chain: "+head.getHeader().getHashAsString()); - //System.out.println("Stored block: "+storedPrev.getHeader().getHashAsString()); - //System.out.println("New block work: "+block.getHashAsString()); - //System.out.println("#####################"); // This block connects to somewhere other than the top of the best known chain. We treat these differently. // // Note that we send the transactions to the wallet FIRST, even if we're about to re-organize this block diff --git a/core/src/main/java/org/pivxj/core/BitcoinSerializer.java b/core/src/main/java/org/pivxj/core/BitcoinSerializer.java index aa80f15e0..20910c551 100644 --- a/core/src/main/java/org/pivxj/core/BitcoinSerializer.java +++ b/core/src/main/java/org/pivxj/core/BitcoinSerializer.java @@ -272,6 +272,9 @@ private Message makeMessage(String command, int length, byte[] payloadBytes, byt return new MasternodeBroadcast(params, payloadBytes); } else if( command.equals("mnp")) { return new MasternodePing(params, payloadBytes); + } else if (command.equals("mnget")){ + log.warn("mnget message arrived"); + return null; } else if (command.equals("spork")) { return new SporkMessage(params, payloadBytes, 0); } else if(command.equals("ssc")) { diff --git a/core/src/main/java/org/pivxj/core/BloomFilter.java b/core/src/main/java/org/pivxj/core/BloomFilter.java index 1ae89c202..4baf598c7 100644 --- a/core/src/main/java/org/pivxj/core/BloomFilter.java +++ b/core/src/main/java/org/pivxj/core/BloomFilter.java @@ -119,7 +119,18 @@ public BloomFilter(int elements, double falsePositiveRate, long randomNonce, Blo this.nTweak = randomNonce; this.nFlags = (byte)(0xff & updateFlag.ordinal()); } - + + public BloomFilter(int elements, double falsePositiveRate, long randomNonce, int hashFuncs) { + // 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]; + this.hashFuncs = hashFuncs; + this.nTweak = randomNonce; + this.nFlags = (byte)(0xff & BloomUpdate.UPDATE_ALL.ordinal()); + } + /** * Returns the theoretical false positive rate of this filter if were to contain the given number of elements. */ diff --git a/core/src/main/java/org/pivxj/core/TransactionBag.java b/core/src/main/java/org/pivxj/core/TransactionBag.java index 128af84eb..1ad44338b 100644 --- a/core/src/main/java/org/pivxj/core/TransactionBag.java +++ b/core/src/main/java/org/pivxj/core/TransactionBag.java @@ -32,7 +32,7 @@ public interface TransactionBag { boolean isWatchedScript(Script script); /** Returns true if this wallet is watching transactions for outputs with the zc commitment value. */ - boolean isZcOutputMine(Script script); + boolean isZcScriptMine(Script script); /** Returns true if this wallet contains a keypair with the given public key. */ boolean isPubKeyMine(byte[] pubkey); diff --git a/core/src/main/java/org/pivxj/core/TransactionConfidence.java b/core/src/main/java/org/pivxj/core/TransactionConfidence.java index ad9bc8176..28840abed 100644 --- a/core/src/main/java/org/pivxj/core/TransactionConfidence.java +++ b/core/src/main/java/org/pivxj/core/TransactionConfidence.java @@ -21,6 +21,8 @@ import com.google.common.util.concurrent.*; import org.pivxj.utils.*; import org.pivxj.wallet.Wallet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.*; import java.util.*; @@ -61,6 +63,8 @@ */ public class TransactionConfidence { + private static final Logger log = LoggerFactory.getLogger(TransactionConfidence.class); + /** * 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 @@ -76,6 +80,7 @@ public class TransactionConfidence { // The depth of the transaction on the best chain in blocks. An unconfirmed block has depth 0. private int depth; + private int lastBlockHeightUpdate; /** Describes the state of the transaction in general terms. Properties can be read to learn specifics. */ public enum ConfidenceType { @@ -259,6 +264,7 @@ public synchronized void setAppearedAtChainHeight(int appearedAtChainHeight) { this.appearedAtChainHeight = appearedAtChainHeight; this.depth = 1; setConfidenceType(ConfidenceType.BUILDING); + this.lastBlockHeightUpdate = appearedAtChainHeight; } /** @@ -282,6 +288,7 @@ public synchronized void setConfidenceType(ConfidenceType confidenceType) { if (confidenceType == ConfidenceType.PENDING || confidenceType == ConfidenceType.IN_CONFLICT) { depth = 0; appearedAtChainHeight = -1; + lastBlockHeightUpdate = -1; } } @@ -379,8 +386,16 @@ public synchronized String toString() { * * @return the new depth */ - public synchronized int incrementDepthInBlocks() { - return ++this.depth; + public synchronized int incrementDepthInBlocks(int seenBlockHeight) { + if (lastBlockHeightUpdate != seenBlockHeight){ + if (lastBlockHeightUpdate > seenBlockHeight){ + log.warn("trying to increase the tx depth with block with less height that the last depth update.."); + } + this.lastBlockHeightUpdate = seenBlockHeight; + return ++this.depth; + } + // This was increased already, return the current depth + return depth; } /** @@ -401,6 +416,7 @@ public synchronized int getDepthInBlocks() { * Set the depth in blocks. Having one block confirmation is a depth of one. */ public synchronized void setDepthInBlocks(int depth) { + // TODO: add block height to this method to update the lastBlockHeightUpdate.. this.depth = depth; } diff --git a/core/src/main/java/org/pivxj/core/TransactionInput.java b/core/src/main/java/org/pivxj/core/TransactionInput.java index df4b5bce6..3f1fa956a 100644 --- a/core/src/main/java/org/pivxj/core/TransactionInput.java +++ b/core/src/main/java/org/pivxj/core/TransactionInput.java @@ -18,6 +18,8 @@ package org.pivxj.core; import com.zerocoinj.core.CoinDenomination; +import com.zerocoinj.core.CoinSpend; +import com.zerocoinj.core.ZCoin; import org.pivxj.script.Script; import org.pivxj.wallet.DefaultRiskAnalysis; import org.pivxj.wallet.KeyBag; @@ -25,6 +27,9 @@ import com.google.common.base.Joiner; import com.google.common.base.Objects; +import org.pivxj.wallet.Wallet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.annotation.Nullable; import java.io.IOException; @@ -45,6 +50,9 @@ *

Instances of this class are not safe for use by multiple threads.

*/ public class TransactionInput extends ChildMessage { + + private final static Logger logger = LoggerFactory.getLogger(TransactionInput.class); + /** Magic sequence number that indicates there is no sequence number. */ public static final long NO_SEQUENCE = 0xFFFFFFFFL; private static final byte[] EMPTY_ARRAY = new byte[0]; @@ -172,8 +180,7 @@ public boolean isCoinBase() { */ public boolean isZcspend() { try { - CoinDenomination.fromValue((int) sequence); - return true; + return getScriptSig().isZcSpend(); }catch (Exception e){ // Nothing.. } @@ -319,8 +326,16 @@ public enum ConnectionResult { @Nullable TransactionOutput getConnectedOutput(Map transactions) { Transaction tx = transactions.get(outpoint.getHash()); - if (tx == null) - return null; + if (tx == null){ + if (outpoint.getPrivateHash() != null){ + tx = transactions.get(outpoint.getPrivateHash()); + } + if (tx == null && outpoint.fromTx != null){ + tx = transactions.get(outpoint.fromTx.getHash());; + } + if (tx == null) return null; + return tx.getOutputs().get((int) outpoint.getPrivateIndex()); + } return tx.getOutputs().get((int) outpoint.getIndex()); } @@ -348,12 +363,32 @@ public enum ConnectMode { * @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 transactions, ConnectMode mode) { + public ConnectionResult connect(Wallet wallet, Map transactions, ConnectMode mode) { Transaction tx = transactions.get(outpoint.getHash()); if (tx == null) { + // if the input is a zc_spend then the way of connect the input is different + if (isZcspend()){ + CoinSpend coinSpend = getScriptSig().getCoinSpend(params, Context.zerocoinContext); + ZCoin zCoin = wallet.getActiveKeyChain().getZcoinsAssociatedToSerial(coinSpend.getCoinSerialNumber()); + if (zCoin != null){ + // now i can get the tx that minted this value + for (Transaction transaction : transactions.values()) { + for (TransactionOutput output : transaction.getOutputs()) { + if (output.isZcMint() && output.getScriptPubKey().getCommitmentValue().equals(zCoin.getCommitment().getCommitmentValue())){ + tx = transaction; + break; + } + } + if (tx != null) break; + } + } + if (tx != null){ + return connect(tx, zCoin ,mode); + } + } return TransactionInput.ConnectionResult.NO_SUCH_TX; } - return connect(tx, mode); + return connect(tx, null, mode); } /** @@ -365,11 +400,26 @@ public ConnectionResult connect(Map transactions, Conne * @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()); + public ConnectionResult connect(Transaction transaction, ZCoin zCoin ,ConnectMode mode) { + TransactionOutput out = null; + long privateIndex = -1; + if (outpoint.getHash().equals(Sha256Hash.ZERO_HASH)){ + // This is a zc_spend + logger.info("Connecting zc_spend.."); + for (TransactionOutput output : transaction.getOutputs()) { + if (output.isZcMint() && output.getScriptPubKey().getCommitmentValue().equals(zCoin.getCommitment().getCommitmentValue())){ + out = output; + break; + } + } + if (out == null) return ConnectionResult.NO_SUCH_TX; + privateIndex = out.getIndex(); + }else { + if (!transaction.getHash().equals(outpoint.getHash())) + return ConnectionResult.NO_SUCH_TX; + checkElementIndex((int) outpoint.getIndex(), transaction.getOutputs().size(), "Corrupt transaction"); + out = transaction.getOutput((int) outpoint.getIndex()); + } if (!out.isAvailableForSpending()) { if (getParentTransaction().equals(outpoint.fromTx)) { // Already connected. @@ -381,7 +431,11 @@ public ConnectionResult connect(Transaction transaction, ConnectMode mode) { return TransactionInput.ConnectionResult.ALREADY_SPENT; } } - connect(out); + if (privateIndex == -1){ + connect(out); + }else { + connect(out, privateIndex, transaction.getHash()); + } return TransactionInput.ConnectionResult.SUCCESS; } @@ -392,6 +446,12 @@ public void connect(TransactionOutput out) { value = out.getValue(); } + public void connect(TransactionOutput out, long privateIndex, Sha256Hash privateParentHash){ + connect(out); + outpoint.setPrivateIndex(privateIndex); + outpoint.setPrivateHash(privateParentHash); + } + /** * If this input is connected, check the output is connected back to this input and release it if so, making * it spendable once again. @@ -519,7 +579,7 @@ public String toString() { s.append(": COINBASE"); } else { if (isZcspend()){ - s.append(" for [").append(outpoint).append("]: ").append(getScriptSig()); + s.append(" for [").append(outpoint.toPrivateString()).append("]: ").append(getScriptSig()); String flags = hasSequence() ? "sequence: " + sequence : null; if (flags != null) diff --git a/core/src/main/java/org/pivxj/core/TransactionOutPoint.java b/core/src/main/java/org/pivxj/core/TransactionOutPoint.java index 3912232ff..96df6ec4f 100644 --- a/core/src/main/java/org/pivxj/core/TransactionOutPoint.java +++ b/core/src/main/java/org/pivxj/core/TransactionOutPoint.java @@ -46,6 +46,10 @@ public class TransactionOutPoint extends ChildMessage { // The connected output. private TransactionOutput connectedOutput; + // Private data + private long privateIndex = -1; + private Sha256Hash privateHash; + public TransactionOutPoint(NetworkParameters params, long index, @Nullable Transaction fromTx) { super(params); this.index = index; @@ -111,7 +115,10 @@ protected void bitcoinSerializeToStream(OutputStream stream) throws IOException @Nullable public TransactionOutput getConnectedOutput() { if (fromTx != null) { - return fromTx.getOutputs().get((int) index); + if (index < 50) // random index value + return fromTx.getOutputs().get((int) index); + else // Then this is a zc_spend + return fromTx.getOutputs().get((int) privateIndex); } else if (connectedOutput != null) { return connectedOutput; } @@ -183,6 +190,10 @@ public String toString() { return hash + ":" + index; } + public String toPrivateString() { + return hash + ":" + index + " , Private("+privateHash+":"+privateIndex+")"; + } + public String toStringCpp() { return "COutPoint("+ hash.toString() + ", "+ index +")"; @@ -213,6 +224,22 @@ public void setIndex(long index) { this.index = index; } + public void setPrivateIndex(long index){ + this.privateIndex = index; + } + + public void setPrivateHash(Sha256Hash hash){ + this.privateHash = hash; + } + + public long getPrivateIndex() { + return privateIndex; + } + + public Sha256Hash getPrivateHash() { + return privateHash; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -225,4 +252,8 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hashCode(getIndex(), getHash()); } + + public void setParentHash(Sha256Hash parentHash) { + this.hash = parentHash; + } } diff --git a/core/src/main/java/org/pivxj/core/TransactionOutput.java b/core/src/main/java/org/pivxj/core/TransactionOutput.java index 290d085bf..63d2327ac 100644 --- a/core/src/main/java/org/pivxj/core/TransactionOutput.java +++ b/core/src/main/java/org/pivxj/core/TransactionOutput.java @@ -325,9 +325,10 @@ public boolean isMine(TransactionBag transactionBag) { return transactionBag.isPubKeyMine(pubkey); }else if (script.isPayToScriptHash()) { return transactionBag.isPayToScriptHashMine(script.getPubKeyHash()); - } else if (script.isZcMint() || script.isZcSpend()){ - // TODO: Check if this method is right or i should create a new one.. - return transactionBag.isZcOutputMine(script); + } else if (script.isZcMint()){ + return transactionBag.isZcScriptMine(script); + } else if (script.isZcSpend()){ + return transactionBag.isZcScriptMine(script); } else { byte[] pubkeyHash = script.getPubKeyHash(); return transactionBag.isPubKeyHashMine(pubkeyHash); diff --git a/core/src/main/java/org/pivxj/core/VarInt.java b/core/src/main/java/org/pivxj/core/VarInt.java index 14e0f0cea..21f5ce8a5 100644 --- a/core/src/main/java/org/pivxj/core/VarInt.java +++ b/core/src/main/java/org/pivxj/core/VarInt.java @@ -53,7 +53,6 @@ public VarInt(byte[] buf, int offset) { } else { value = Utils.readInt64(buf, offset + 1); originallyEncodedSize = 9; // 1 marker + 8 data bytes (64 bits) - System.out.println("REading varInt 64 bits"); } } diff --git a/core/src/main/java/org/pivxj/script/Script.java b/core/src/main/java/org/pivxj/script/Script.java index 7658e93a8..06f97eed9 100644 --- a/core/src/main/java/org/pivxj/script/Script.java +++ b/core/src/main/java/org/pivxj/script/Script.java @@ -18,12 +18,15 @@ package org.pivxj.script; +import com.zerocoinj.core.CoinSpend; +import com.zerocoinj.core.context.ZerocoinContext; import org.pivxj.core.*; import org.pivxj.crypto.TransactionSignature; import com.google.common.collect.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.crypto.digests.RIPEMD160Digest; +import org.spongycastle.util.encoders.Hex; import javax.annotation.Nullable; import java.io.ByteArrayInputStream; @@ -177,7 +180,7 @@ public List getChunks() { * Bitcoin Core does something similar.

*/ private void parse(byte[] program) throws ScriptException { - chunks = new ArrayList(5); // Common size. + chunks = new ArrayList<>(5); // Common size. ByteArrayInputStream bis = new ByteArrayInputStream(program); int initialSize = bis.available(); while (bis.available() > 0) { @@ -220,12 +223,6 @@ private void parse(byte[] program) throws ScriptException { if (c.equals(chunk)) chunk = c; } chunks.add(chunk); - - if (opcode == OP_ZEROCOINSPEND) { - //Zerocoinspend has no further op codes. - - break; - } } } @@ -315,12 +312,28 @@ public byte[] getPubKey() throws ScriptException { * */ public BigInteger getCommitmentValue() { + if (!isZcMint()){ + throw new ScriptException("Script is not a zc_mint"); + } if (chunks.size() != 3) { throw new ScriptException("Script not of right size, expecting 2 but got " + chunks.size()); } return Utils.unserializeBiginteger(chunks.get(2).data); } + public CoinSpend getCoinSpend(NetworkParameters params, ZerocoinContext zerocoinContext) { + if (!isZcSpend()) throw new ScriptException("Script is not a zc_spend"); + byte[] coinSpendBytes = getChunks().get(0).data; + if (coinSpendBytes == null) throw new ScriptException("Invalid zc_spend script"); + // now read the length + int size = coinSpendBytes.length - 3; + byte[] coinSpend = new byte[size]; + System.arraycopy(coinSpendBytes,3, coinSpend, 0, size); + //System.out.println(Hex.toHexString(coinSpendBytes)); + //System.out.println(Hex.toHexString(coinSpend)); + return CoinSpend.parse(params, zerocoinContext, coinSpend); + } + /** * Retrieves the sender public key from a LOCKTIMEVERIFY transaction * @return diff --git a/core/src/main/java/org/pivxj/wallet/DefaultRiskAnalysis.java b/core/src/main/java/org/pivxj/wallet/DefaultRiskAnalysis.java index 46f2e4fc1..97be6ede1 100644 --- a/core/src/main/java/org/pivxj/wallet/DefaultRiskAnalysis.java +++ b/core/src/main/java/org/pivxj/wallet/DefaultRiskAnalysis.java @@ -176,6 +176,10 @@ public static RuleViolation isOutputStandard(TransactionOutput output) { /** Checks if the given input passes some of the AreInputsStandard checks. Not complete. */ public static RuleViolation isInputStandard(TransactionInput input) { + if (input.isZcspend()){ + // TODO: add here more validations.. + return RuleViolation.NONE; + } for (ScriptChunk chunk : input.getScriptSig().getChunks()) { if (chunk.data != null && !chunk.isShortestPossiblePushData()) return RuleViolation.SHORTEST_POSSIBLE_PUSHDATA; diff --git a/core/src/main/java/org/pivxj/wallet/DeterministicKeyChain.java b/core/src/main/java/org/pivxj/wallet/DeterministicKeyChain.java index a82ab2f94..a0bb9595f 100644 --- a/core/src/main/java/org/pivxj/wallet/DeterministicKeyChain.java +++ b/core/src/main/java/org/pivxj/wallet/DeterministicKeyChain.java @@ -25,10 +25,12 @@ import com.zerocoinj.core.ZCoin; import com.zerocoinj.core.context.ZerocoinContext; import com.zerocoinj.core.exceptions.InvalidSerialException; +import com.zerocoinj.utils.ZUtils; import org.pivxj.core.*; import org.pivxj.crypto.*; import org.pivxj.script.Script; import org.pivxj.utils.Threading; +import org.pivxj.wallet.exceptions.InvalidCoinException; import org.pivxj.wallet.listeners.KeyChainEventListener; import com.google.common.base.Stopwatch; @@ -36,6 +38,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.spongycastle.crypto.params.KeyParameter; +import org.spongycastle.util.encoders.Hex; import javax.annotation.Nullable; import java.math.BigInteger; @@ -50,6 +53,7 @@ import static com.google.common.base.Preconditions.*; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.newLinkedList; +import static org.pivxj.wallet.BasicKeyChain.serializeEncryptableItem; /** *

A deterministic key chain is a {@link KeyChain} that uses the @@ -829,7 +833,7 @@ protected List serializeMyselfToProtobuf() { // data (handling encryption along the way), and letting us patch it up with the extra data we care about. LinkedList entries = newLinkedList(); if (seed != null) { - Protos.Key.Builder mnemonicEntry = BasicKeyChain.serializeEncryptableItem(seed); + Protos.Key.Builder mnemonicEntry = serializeEncryptableItem(seed); mnemonicEntry.setType(Protos.Key.Type.DETERMINISTIC_MNEMONIC); serializeSeedEncryptableItem(seed, mnemonicEntry); entries.add(mnemonicEntry.build()); @@ -884,13 +888,19 @@ private Protos.Zpiv.Builder toProto(ZCoin zCoin) { .setHeight(zCoin.getHeight()) .setSerial(ByteString.copyFrom(Utils.serializeBigInteger(zCoin.getSerial()))) .setVersion(0); + + ECKey ecKey = zCoin.getKeyPair(); + Protos.Key.Builder protoKey = serializeEncryptableItem(ecKey); + protoKey.setPublicKey(ByteString.copyFrom(ecKey.getPubKey())); + zpiv.setKey(protoKey); + if (zCoin.getParentTxId() != null){ zpiv.setParentTxId(ByteString.copyFrom(zCoin.getParentTxId().getReversedBytes())); } return zpiv; } - private static ZCoin fromProto(Protos.Zpiv zpiv, ECKey key) { + private static ZCoin fromProto(Protos.Zpiv zpiv, @Nullable KeyCrypter keyCrypter) throws UnreadableWalletException { BigInteger content = Utils.unserializeBiginteger(zpiv.getCommitment().getContent().toByteArray()); BigInteger contentValue = Utils.unserializeBiginteger(zpiv.getCommitment().getContentValue().toByteArray()); BigInteger randomness = Utils.unserializeBiginteger(zpiv.getCommitment().getRandomness().toByteArray()); @@ -898,12 +908,37 @@ private static ZCoin fromProto(Protos.Zpiv zpiv, ECKey key) { Commitment commitment = new Commitment(content, contentValue, randomness); BigInteger serial = Utils.unserializeBiginteger(zpiv.getSerial().toByteArray()); CoinDenomination den = CoinDenomination.fromValue(zpiv.getDen()); + + // key + Protos.Key key = zpiv.getKey(); + boolean encrypted = key.getType() == Protos.Key.Type.ENCRYPTED_SCRYPT_AES; + byte[] priv = key.hasSecretBytes() ? key.getSecretBytes().toByteArray() : null; + if (!key.hasPublicKey()) + throw new UnreadableWalletException("Zpiv public key missing"); + byte[] pub = key.getPublicKey().toByteArray(); + ECKey ecKey; + if (encrypted) { + checkState(keyCrypter != null, "This wallet is encrypted but encrypt() was not called prior to deserialization"); + if (!key.hasEncryptedData()) + throw new UnreadableWalletException("Encrypted private key data missing"); + Protos.EncryptedData proto = key.getEncryptedData(); + EncryptedData e = new EncryptedData(proto.getInitialisationVector().toByteArray(), + proto.getEncryptedPrivateKey().toByteArray()); + ecKey = ECKey.fromEncrypted(e, keyCrypter, pub); + } else { + if (priv != null) + ecKey = ECKey.fromPrivateAndPrecalculatedPublic(priv, pub); + else + ecKey = ECKey.fromPublicOnly(pub); + } + ecKey.setCreationTimeSeconds(key.getCreationTimestamp() / 1000); + return new ZCoin( Context.get().zerocoinContext, serial, commitment, den, - key + ecKey ); } @@ -1092,8 +1127,8 @@ public static List fromProtobuf(List keys, @N chain.basicKeyChain.importKey(detkey); if (key.hasZpiv()){ - ZCoin associatedCoin = fromProto(key.getZpiv(), detkey); - chain.putAssociatedCoin(associatedCoin); + ZCoin associatedCoin = fromProto(key.getZpiv(), crypter); + chain.putAssociatedCoin(associatedCoin, detkey); } } } @@ -1107,9 +1142,9 @@ public static List fromProtobuf(List keys, @N return chains; } - private void putAssociatedCoin(ZCoin associatedCoin) { - if (! (associatedCoin.getKeyPair() instanceof DeterministicKey)) throw new IllegalArgumentException("Trying to add a non deterministic key"); - DeterministicKey key = (DeterministicKey) associatedCoin.getKeyPair(); + private void putAssociatedCoin(ZCoin associatedCoin, ECKey associatedKey) { + if (! (associatedKey instanceof DeterministicKey)) throw new IllegalArgumentException("Trying to add a non deterministic key"); + DeterministicKey key = (DeterministicKey) associatedKey;//associatedCoin.getKeyPair(); // Check if the key exists checkNotNull(getKeyByPath(key.getPath()),"Associated key not exists"); if (zcoins.get(key) == null) @@ -1234,7 +1269,20 @@ public BloomFilter getFilter(int size, double falsePositiveRate, long tweak) { try { checkArgument(size >= numBloomFilterEntries()); maybeLookAhead(); - return basicKeyChain.getFilter(size, falsePositiveRate, tweak); + BloomFilter zcFilter = null; + if (isZerocoinPath()) { + zcFilter = new BloomFilter(size, falsePositiveRate, tweak, BloomFilter.BloomUpdate.UPDATE_ALL); + for (ZCoin zCoin : zcoins.values()) { + // for outputs + zcFilter.insert(Utils.serializeBigInteger(zCoin.getCommitment().getCommitmentValue())); + // for inputs + zcFilter.insert(Utils.serializeBigInteger(zCoin.getSerial())); + } + } + BloomFilter filter = basicKeyChain.getFilter(size, falsePositiveRate, tweak); + if (zcFilter != null) + filter.merge(zcFilter); + return filter; } finally { lock.unlock(); } @@ -1354,7 +1402,6 @@ private List maybeLookAhead(DeterministicKey parent, int issue needed, parent.getPathAsString(), issued, lookaheadSize, lookaheadThreshold, numChildren, createZcoins); List result = new ArrayList<>(needed); - ExecutorService executor = null; final Stopwatch watch = Stopwatch.createStarted(); int nextChild = numChildren; for (int i = 0; i < needed; i++) { @@ -1364,11 +1411,8 @@ private List maybeLookAhead(DeterministicKey parent, int issue result.add(key); nextChild = key.getChildNumber().num() + 1; if (createZcoins){ - try { - generateZcoin(key); - } catch (InvalidSerialException e) { - log.info("invalid serial", e); - } + generateZcoin(key); + //log.info("Valid coin created, pubkey: " + key.getPublicKeyAsHex()); } } watch.stop(); @@ -1376,12 +1420,32 @@ private List maybeLookAhead(DeterministicKey parent, int issue return result; } - private void generateZcoin(DeterministicKey key) throws InvalidSerialException { + private void generateZcoin(DeterministicKey key){ if (zcoins.get(key) != null) return; ZerocoinContext context = Context.get().zerocoinContext; Sha256Hash trimmedRandomness = Sha256Hash.twiceOf(key.getPrivKeyBytes()); // Here the core is using a Sha512.. BigInteger randomness = HashWriter.toUint256(trimmedRandomness.getReversedBytes()).mod(context.coinCommitmentGroup.getGroupOrder()); - BigInteger serial = ZCoin.generateSerial(key); + BigInteger serial = null; + // Serial + boolean isValid = false; + ECKey usedKey = key; + byte[] serialSeed = usedKey.getPrivKeyBytes(); + final Stopwatch watch = Stopwatch.createStarted(); + do { + try { + serial = ZCoin.generateSerial(usedKey); + isValid = true; + }catch (Exception e){ + // swallow.. + log.info("invalid serial creation, loop"); + // TODO: Remember to remove this serialSeed from memory.. + serialSeed = Sha256Hash.twiceOf(serialSeed).getReversedBytes(); + usedKey = ECKey.fromPrivate(serialSeed); + } + } while (!isValid); + watch.stop(); + log.info("Serial creation, took {}", watch); + Commitment commitment = new Commitment(serial, randomness, context.coinCommitmentGroup); BigInteger attempts = BigInteger.ZERO; @@ -1399,14 +1463,27 @@ private void generateZcoin(DeterministicKey key) throws InvalidSerialException { commitment = new Commitment(serial, randomness, context.coinCommitmentGroup); } - putAssociatedCoin( - ZCoin.mintCoinH( - Context.get().zerocoinContext, - key, - CoinDenomination.ZQ_ERROR, - commitment - ) + usedKey = ECKey.fromPrivate(usedKey.getPrivKeyBytes()); + ZCoin zCoin = ZCoin.mintCoinUnchecked( + Context.get().zerocoinContext, + usedKey, + CoinDenomination.ZQ_ERROR, + commitment ); + + if (!zCoin.validate()){ + throw new InvalidCoinException("Invalid zcoin"); + } + + // Double check + byte[] hashedPubKeyBites = Sha256Hash.twiceOf(zCoin.getKeyPair().getPubKey()).getReversedBytes(); + BigInteger hashedPubKey = (new BigInteger(1, hashedPubKeyBites)).shiftRight(ZCoin.V2_BITSHIFT); + BigInteger adjustedSerial = ZCoin.getAdjustedSerial(zCoin.getSerial()); + if (!ZUtils.equals(hashedPubKey, adjustedSerial)) { + throw new InvalidCoinException("Invalid zcoin, public key is not equals to the public key that generated the serial"); + } + + putAssociatedCoin(zCoin, key); } /** Housekeeping call to call when lookahead might be needed. Normally called automatically by KeychainGroup. */ @@ -1546,6 +1623,15 @@ public ZCoin getZcoinsAssociated(DeterministicKey key) { return zcoins.get(key); } + public ZCoin getZcoinsAssociatedRealKey(ECKey key) { + for (ZCoin zCoin : zcoins.values()) { + if (zCoin.getKeyPair().equals(key)){ + return zCoin; + } + } + return null; + } + public List getZcoins(int amount) { List createdZCoins = new ArrayList<>(); for (ZCoin zCoin : zcoins.values()) { @@ -1554,9 +1640,18 @@ public List getZcoins(int amount) { return createdZCoins; } + public ZCoin getZcoinsAssociatedToSerial(BigInteger serial){ + for (ZCoin zCoin : zcoins.values()) { + if (Utils.areBigIntegersEqual(zCoin.getSerial(), serial)){ + return zCoin; + } + } + return null; + } + public ZCoin getZcoinsAssociated(BigInteger commitmentToSpend) { for (ZCoin zCoin : zcoins.values()) { - if (Utils.areBigIntegersEqual(zCoin.getCommitment().getCommitmentValue(),commitmentToSpend)){ + if (Utils.areBigIntegersEqual(zCoin.getCommitment().getCommitmentValue(), commitmentToSpend)){ return zCoin; } } @@ -1572,6 +1667,15 @@ public boolean isCommitmentValueMine(BigInteger value) { return false; } + public boolean isCoinSerialMine(BigInteger serial) { + for (ZCoin zCoin : zcoins.values()) { + if (Utils.areBigIntegersEqual(zCoin.getSerial(), serial)){ + return true; + } + } + return false; + } + /** Create a new key and return the matching output script. Only applicable to married keychains. */ public Script freshOutputScript(KeyPurpose purpose) { throw new UnsupportedOperationException(); diff --git a/core/src/main/java/org/pivxj/wallet/KeyChainGroup.java b/core/src/main/java/org/pivxj/wallet/KeyChainGroup.java index a9fa56cc2..2bb2b955c 100644 --- a/core/src/main/java/org/pivxj/wallet/KeyChainGroup.java +++ b/core/src/main/java/org/pivxj/wallet/KeyChainGroup.java @@ -276,6 +276,7 @@ public final DeterministicKeyChain getActiveKeyChain() { * @return */ public ZCoin getZcoinsAssociated(DeterministicKey key) { + // TODO: Change this for: getZcoinsAssociatedRealKey return getActiveKeyChain().getZcoinsAssociated(key); } @@ -283,6 +284,10 @@ public boolean isCommitmentValuesMine(BigInteger value) { return getActiveKeyChain().isCommitmentValueMine(value); } + public boolean isCoinSerialMine(BigInteger serial) { + return getActiveKeyChain().isCoinSerialMine(serial); + } + /** * Sets the lookahead buffer size for ALL deterministic key chains as well as for following key chains if any exist, * see {@link DeterministicKeyChain#setLookaheadSize(int)} @@ -626,7 +631,12 @@ public int getBloomFilterElementCount() { } public BloomFilter getBloomFilter(int size, double falsePositiveRate, long nTweak) { - BloomFilter filter = new BloomFilter(size, falsePositiveRate, nTweak); + BloomFilter filter; + if (getActiveKeyChain().isZerocoinPath()){ + // TODO: check this.. + filter = new BloomFilter(size, falsePositiveRate, nTweak, BloomFilter.BloomUpdate.UPDATE_ALL); + }else + filter = new BloomFilter(size, falsePositiveRate, nTweak); if (basic.numKeys() > 0) filter.merge(basic.getFilter(size, falsePositiveRate, nTweak)); @@ -856,4 +866,5 @@ public int getCombinedKeyLookaheadEpochs() { return epoch; } + } diff --git a/core/src/main/java/org/pivxj/wallet/Protos.java b/core/src/main/java/org/pivxj/wallet/Protos.java index fe828440b..7977bf557 100644 --- a/core/src/main/java/org/pivxj/wallet/Protos.java +++ b/core/src/main/java/org/pivxj/wallet/Protos.java @@ -2956,6 +2956,19 @@ public interface ZpivOrBuilder extends * optional int64 height = 6; */ long getHeight(); + + /** + * required .wallet.Key key = 7; + */ + boolean hasKey(); + /** + * required .wallet.Key key = 7; + */ + org.pivxj.wallet.Protos.Key getKey(); + /** + * required .wallet.Key key = 7; + */ + org.pivxj.wallet.Protos.KeyOrBuilder getKeyOrBuilder(); } /** * Protobuf type {@code wallet.Zpiv} @@ -3052,6 +3065,19 @@ private Zpiv( height_ = input.readInt64(); break; } + case 58: { + org.pivxj.wallet.Protos.Key.Builder subBuilder = null; + if (((bitField0_ & 0x00000040) == 0x00000040)) { + subBuilder = key_.toBuilder(); + } + key_ = input.readMessage(org.pivxj.wallet.Protos.Key.PARSER, extensionRegistry); + if (subBuilder != null) { + subBuilder.mergeFrom(key_); + key_ = subBuilder.buildPartial(); + } + bitField0_ |= 0x00000040; + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -3188,6 +3214,27 @@ public long getHeight() { return height_; } + public static final int KEY_FIELD_NUMBER = 7; + private org.pivxj.wallet.Protos.Key key_; + /** + * required .wallet.Key key = 7; + */ + public boolean hasKey() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required .wallet.Key key = 7; + */ + public org.pivxj.wallet.Protos.Key getKey() { + return key_; + } + /** + * required .wallet.Key key = 7; + */ + public org.pivxj.wallet.Protos.KeyOrBuilder getKeyOrBuilder() { + return key_; + } + private void initFields() { version_ = 0; commitment_ = org.pivxj.wallet.Protos.Commitment.getDefaultInstance(); @@ -3195,6 +3242,7 @@ private void initFields() { den_ = 0; parentTxId_ = com.google.protobuf.ByteString.EMPTY; height_ = 0L; + key_ = org.pivxj.wallet.Protos.Key.getDefaultInstance(); } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -3210,10 +3258,18 @@ public final boolean isInitialized() { memoizedIsInitialized = 0; return false; } + if (!hasKey()) { + memoizedIsInitialized = 0; + return false; + } if (!getCommitment().isInitialized()) { memoizedIsInitialized = 0; return false; } + if (!getKey().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } memoizedIsInitialized = 1; return true; } @@ -3239,6 +3295,9 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (((bitField0_ & 0x00000020) == 0x00000020)) { output.writeInt64(6, height_); } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeMessage(7, key_); + } getUnknownFields().writeTo(output); } @@ -3272,6 +3331,10 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeInt64Size(6, height_); } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(7, key_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -3387,6 +3450,7 @@ private Builder( private void maybeForceBuilderInitialization() { if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { getCommitmentFieldBuilder(); + getKeyFieldBuilder(); } } private static Builder create() { @@ -3411,6 +3475,12 @@ public Builder clear() { bitField0_ = (bitField0_ & ~0x00000010); height_ = 0L; bitField0_ = (bitField0_ & ~0x00000020); + if (keyBuilder_ == null) { + key_ = org.pivxj.wallet.Protos.Key.getDefaultInstance(); + } else { + keyBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000040); return this; } @@ -3467,6 +3537,14 @@ public org.pivxj.wallet.Protos.Zpiv buildPartial() { to_bitField0_ |= 0x00000020; } result.height_ = height_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000040; + } + if (keyBuilder_ == null) { + result.key_ = key_; + } else { + result.key_ = keyBuilder_.build(); + } result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -3501,6 +3579,9 @@ public Builder mergeFrom(org.pivxj.wallet.Protos.Zpiv other) { if (other.hasHeight()) { setHeight(other.getHeight()); } + if (other.hasKey()) { + mergeKey(other.getKey()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -3514,10 +3595,18 @@ public final boolean isInitialized() { return false; } + if (!hasKey()) { + + return false; + } if (!getCommitment().isInitialized()) { return false; } + if (!getKey().isInitialized()) { + + return false; + } return true; } @@ -3822,6 +3911,122 @@ public Builder clearHeight() { return this; } + private org.pivxj.wallet.Protos.Key key_ = org.pivxj.wallet.Protos.Key.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + org.pivxj.wallet.Protos.Key, org.pivxj.wallet.Protos.Key.Builder, org.pivxj.wallet.Protos.KeyOrBuilder> keyBuilder_; + /** + * required .wallet.Key key = 7; + */ + public boolean hasKey() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * required .wallet.Key key = 7; + */ + public org.pivxj.wallet.Protos.Key getKey() { + if (keyBuilder_ == null) { + return key_; + } else { + return keyBuilder_.getMessage(); + } + } + /** + * required .wallet.Key key = 7; + */ + public Builder setKey(org.pivxj.wallet.Protos.Key value) { + if (keyBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + key_ = value; + onChanged(); + } else { + keyBuilder_.setMessage(value); + } + bitField0_ |= 0x00000040; + return this; + } + /** + * required .wallet.Key key = 7; + */ + public Builder setKey( + org.pivxj.wallet.Protos.Key.Builder builderForValue) { + if (keyBuilder_ == null) { + key_ = builderForValue.build(); + onChanged(); + } else { + keyBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000040; + return this; + } + /** + * required .wallet.Key key = 7; + */ + public Builder mergeKey(org.pivxj.wallet.Protos.Key value) { + if (keyBuilder_ == null) { + if (((bitField0_ & 0x00000040) == 0x00000040) && + key_ != org.pivxj.wallet.Protos.Key.getDefaultInstance()) { + key_ = + org.pivxj.wallet.Protos.Key.newBuilder(key_).mergeFrom(value).buildPartial(); + } else { + key_ = value; + } + onChanged(); + } else { + keyBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000040; + return this; + } + /** + * required .wallet.Key key = 7; + */ + public Builder clearKey() { + if (keyBuilder_ == null) { + key_ = org.pivxj.wallet.Protos.Key.getDefaultInstance(); + onChanged(); + } else { + keyBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000040); + return this; + } + /** + * required .wallet.Key key = 7; + */ + public org.pivxj.wallet.Protos.Key.Builder getKeyBuilder() { + bitField0_ |= 0x00000040; + onChanged(); + return getKeyFieldBuilder().getBuilder(); + } + /** + * required .wallet.Key key = 7; + */ + public org.pivxj.wallet.Protos.KeyOrBuilder getKeyOrBuilder() { + if (keyBuilder_ != null) { + return keyBuilder_.getMessageOrBuilder(); + } else { + return key_; + } + } + /** + * required .wallet.Key key = 7; + */ + private com.google.protobuf.SingleFieldBuilder< + org.pivxj.wallet.Protos.Key, org.pivxj.wallet.Protos.Key.Builder, org.pivxj.wallet.Protos.KeyOrBuilder> + getKeyFieldBuilder() { + if (keyBuilder_ == null) { + keyBuilder_ = new com.google.protobuf.SingleFieldBuilder< + org.pivxj.wallet.Protos.Key, org.pivxj.wallet.Protos.Key.Builder, org.pivxj.wallet.Protos.KeyOrBuilder>( + getKey(), + getParentForChildren(), + isClean()); + key_ = null; + } + return keyBuilder_; + } + // @@protoc_insertion_point(builder_scope:wallet.Zpiv) } @@ -6703,6 +6908,40 @@ public interface TransactionInputOrBuilder extends * */ long getValue(); + + /** + * optional bytes private_transaction_out_point_hash = 6; + * + *

+     * Hash of the transaction this input is using.
+     * 
+ */ + boolean hasPrivateTransactionOutPointHash(); + /** + * optional bytes private_transaction_out_point_hash = 6; + * + *
+     * Hash of the transaction this input is using.
+     * 
+ */ + com.google.protobuf.ByteString getPrivateTransactionOutPointHash(); + + /** + * optional uint32 private_transaction_out_point_index = 7; + * + *
+     * Index of transaction output used by this input.
+     * 
+ */ + boolean hasPrivateTransactionOutPointIndex(); + /** + * optional uint32 private_transaction_out_point_index = 7; + * + *
+     * Index of transaction output used by this input.
+     * 
+ */ + int getPrivateTransactionOutPointIndex(); } /** * Protobuf type {@code wallet.TransactionInput} @@ -6781,6 +7020,16 @@ private TransactionInput( value_ = input.readInt64(); break; } + case 50: { + bitField0_ |= 0x00000020; + privateTransactionOutPointHash_ = input.readBytes(); + break; + } + case 56: { + bitField0_ |= 0x00000040; + privateTransactionOutPointIndex_ = input.readUInt32(); + break; + } } } } catch (com.google.protobuf.InvalidProtocolBufferException e) { @@ -6936,12 +7185,60 @@ public long getValue() { return value_; } + public static final int PRIVATE_TRANSACTION_OUT_POINT_HASH_FIELD_NUMBER = 6; + private com.google.protobuf.ByteString privateTransactionOutPointHash_; + /** + * optional bytes private_transaction_out_point_hash = 6; + * + *
+     * Hash of the transaction this input is using.
+     * 
+ */ + public boolean hasPrivateTransactionOutPointHash() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional bytes private_transaction_out_point_hash = 6; + * + *
+     * Hash of the transaction this input is using.
+     * 
+ */ + public com.google.protobuf.ByteString getPrivateTransactionOutPointHash() { + return privateTransactionOutPointHash_; + } + + public static final int PRIVATE_TRANSACTION_OUT_POINT_INDEX_FIELD_NUMBER = 7; + private int privateTransactionOutPointIndex_; + /** + * optional uint32 private_transaction_out_point_index = 7; + * + *
+     * Index of transaction output used by this input.
+     * 
+ */ + public boolean hasPrivateTransactionOutPointIndex() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * optional uint32 private_transaction_out_point_index = 7; + * + *
+     * Index of transaction output used by this input.
+     * 
+ */ + public int getPrivateTransactionOutPointIndex() { + return privateTransactionOutPointIndex_; + } + private void initFields() { transactionOutPointHash_ = com.google.protobuf.ByteString.EMPTY; transactionOutPointIndex_ = 0; scriptBytes_ = com.google.protobuf.ByteString.EMPTY; sequence_ = 0; value_ = 0L; + privateTransactionOutPointHash_ = com.google.protobuf.ByteString.EMPTY; + privateTransactionOutPointIndex_ = 0; } private byte memoizedIsInitialized = -1; public final boolean isInitialized() { @@ -6983,6 +7280,12 @@ public void writeTo(com.google.protobuf.CodedOutputStream output) if (((bitField0_ & 0x00000010) == 0x00000010)) { output.writeInt64(5, value_); } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + output.writeBytes(6, privateTransactionOutPointHash_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + output.writeUInt32(7, privateTransactionOutPointIndex_); + } getUnknownFields().writeTo(output); } @@ -7012,6 +7315,14 @@ public int getSerializedSize() { size += com.google.protobuf.CodedOutputStream .computeInt64Size(5, value_); } + if (((bitField0_ & 0x00000020) == 0x00000020)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(6, privateTransactionOutPointHash_); + } + if (((bitField0_ & 0x00000040) == 0x00000040)) { + size += com.google.protobuf.CodedOutputStream + .computeUInt32Size(7, privateTransactionOutPointIndex_); + } size += getUnknownFields().getSerializedSize(); memoizedSerializedSize = size; return size; @@ -7139,6 +7450,10 @@ public Builder clear() { bitField0_ = (bitField0_ & ~0x00000008); value_ = 0L; bitField0_ = (bitField0_ & ~0x00000010); + privateTransactionOutPointHash_ = com.google.protobuf.ByteString.EMPTY; + bitField0_ = (bitField0_ & ~0x00000020); + privateTransactionOutPointIndex_ = 0; + bitField0_ = (bitField0_ & ~0x00000040); return this; } @@ -7187,6 +7502,14 @@ public org.pivxj.wallet.Protos.TransactionInput buildPartial() { to_bitField0_ |= 0x00000010; } result.value_ = value_; + if (((from_bitField0_ & 0x00000020) == 0x00000020)) { + to_bitField0_ |= 0x00000020; + } + result.privateTransactionOutPointHash_ = privateTransactionOutPointHash_; + if (((from_bitField0_ & 0x00000040) == 0x00000040)) { + to_bitField0_ |= 0x00000040; + } + result.privateTransactionOutPointIndex_ = privateTransactionOutPointIndex_; result.bitField0_ = to_bitField0_; onBuilt(); return result; @@ -7218,6 +7541,12 @@ public Builder mergeFrom(org.pivxj.wallet.Protos.TransactionInput other) { if (other.hasValue()) { setValue(other.getValue()); } + if (other.hasPrivateTransactionOutPointHash()) { + setPrivateTransactionOutPointHash(other.getPrivateTransactionOutPointHash()); + } + if (other.hasPrivateTransactionOutPointIndex()) { + setPrivateTransactionOutPointIndex(other.getPrivateTransactionOutPointIndex()); + } this.mergeUnknownFields(other.getUnknownFields()); return this; } @@ -7503,6 +7832,105 @@ public Builder clearValue() { return this; } + private com.google.protobuf.ByteString privateTransactionOutPointHash_ = com.google.protobuf.ByteString.EMPTY; + /** + * optional bytes private_transaction_out_point_hash = 6; + * + *
+       * Hash of the transaction this input is using.
+       * 
+ */ + public boolean hasPrivateTransactionOutPointHash() { + return ((bitField0_ & 0x00000020) == 0x00000020); + } + /** + * optional bytes private_transaction_out_point_hash = 6; + * + *
+       * Hash of the transaction this input is using.
+       * 
+ */ + public com.google.protobuf.ByteString getPrivateTransactionOutPointHash() { + return privateTransactionOutPointHash_; + } + /** + * optional bytes private_transaction_out_point_hash = 6; + * + *
+       * Hash of the transaction this input is using.
+       * 
+ */ + public Builder setPrivateTransactionOutPointHash(com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000020; + privateTransactionOutPointHash_ = value; + onChanged(); + return this; + } + /** + * optional bytes private_transaction_out_point_hash = 6; + * + *
+       * Hash of the transaction this input is using.
+       * 
+ */ + public Builder clearPrivateTransactionOutPointHash() { + bitField0_ = (bitField0_ & ~0x00000020); + privateTransactionOutPointHash_ = getDefaultInstance().getPrivateTransactionOutPointHash(); + onChanged(); + return this; + } + + private int privateTransactionOutPointIndex_ ; + /** + * optional uint32 private_transaction_out_point_index = 7; + * + *
+       * Index of transaction output used by this input.
+       * 
+ */ + public boolean hasPrivateTransactionOutPointIndex() { + return ((bitField0_ & 0x00000040) == 0x00000040); + } + /** + * optional uint32 private_transaction_out_point_index = 7; + * + *
+       * Index of transaction output used by this input.
+       * 
+ */ + public int getPrivateTransactionOutPointIndex() { + return privateTransactionOutPointIndex_; + } + /** + * optional uint32 private_transaction_out_point_index = 7; + * + *
+       * Index of transaction output used by this input.
+       * 
+ */ + public Builder setPrivateTransactionOutPointIndex(int value) { + bitField0_ |= 0x00000040; + privateTransactionOutPointIndex_ = value; + onChanged(); + return this; + } + /** + * optional uint32 private_transaction_out_point_index = 7; + * + *
+       * Index of transaction output used by this input.
+       * 
+ */ + public Builder clearPrivateTransactionOutPointIndex() { + bitField0_ = (bitField0_ & ~0x00000040); + privateTransactionOutPointIndex_ = 0; + onChanged(); + return this; + } + // @@protoc_insertion_point(builder_scope:wallet.TransactionInput) } @@ -21974,88 +22402,91 @@ public Builder setFiatCurrencyCodeBytes( "s\030\003 \001(\r\022\026\n\016lookahead_size\030\004 \001(\r\022\023\n\013isFol" + "lowing\030\005 \001(\010\022\036\n\023sigsRequiredToSpend\030\006 \001(" + "\r:\0011\"G\n\nCommitment\022\017\n\007content\030\001 \002(\014\022\022\n\nr" + - "andomness\030\002 \002(\014\022\024\n\014contentValue\030\003 \002(\014\"\200\001", + "andomness\030\002 \002(\014\022\024\n\014contentValue\030\003 \002(\014\"\232\001", "\n\004Zpiv\022\017\n\007version\030\001 \001(\005\022&\n\ncommitment\030\002 " + "\002(\0132\022.wallet.Commitment\022\016\n\006serial\030\003 \002(\014\022" + "\013\n\003den\030\004 \001(\005\022\022\n\nparentTxId\030\005 \001(\014\022\016\n\006heig" + - "ht\030\006 \001(\003\"\266\003\n\003Key\022\036\n\004type\030\001 \002(\0162\020.wallet." + - "Key.Type\022\024\n\014secret_bytes\030\002 \001(\014\022-\n\016encryp" + - "ted_data\030\006 \001(\0132\025.wallet.EncryptedData\022\022\n" + - "\npublic_key\030\003 \001(\014\022\r\n\005label\030\004 \001(\t\022\032\n\022crea" + - "tion_timestamp\030\005 \001(\003\0223\n\021deterministic_ke" + - "y\030\007 \001(\0132\030.wallet.DeterministicKey\022\032\n\022det" + - "erministic_seed\030\010 \001(\014\022;\n\034encrypted_deter", - "ministic_seed\030\t \001(\0132\025.wallet.EncryptedDa" + - "ta\022\032\n\004zpiv\030\n \001(\0132\014.wallet.Zpiv\"a\n\004Type\022\014" + - "\n\010ORIGINAL\020\001\022\030\n\024ENCRYPTED_SCRYPT_AES\020\002\022\032" + - "\n\026DETERMINISTIC_MNEMONIC\020\003\022\025\n\021DETERMINIS" + - "TIC_KEY\020\004\"5\n\006Script\022\017\n\007program\030\001 \002(\014\022\032\n\022" + - "creation_timestamp\030\002 \002(\003\"\222\001\n\020Transaction" + - "Input\022\"\n\032transaction_out_point_hash\030\001 \002(" + - "\014\022#\n\033transaction_out_point_index\030\002 \002(\r\022\024" + - "\n\014script_bytes\030\003 \002(\014\022\020\n\010sequence\030\004 \001(\r\022\r" + - "\n\005value\030\005 \001(\003\"\177\n\021TransactionOutput\022\r\n\005va", - "lue\030\001 \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022!\n\031spent" + - "_by_transaction_hash\030\003 \001(\014\022\"\n\032spent_by_t" + - "ransaction_index\030\004 \001(\005\"\254\004\n\025TransactionCo" + - "nfidence\0220\n\004type\030\001 \001(\0162\".wallet.Transact" + - "ionConfidence.Type\022\032\n\022appeared_at_height" + - "\030\002 \001(\005\022\036\n\026overriding_transaction\030\003 \001(\014\022\r" + - "\n\005depth\030\004 \001(\005\022)\n\014broadcast_by\030\006 \003(\0132\023.wa" + - "llet.PeerAddress\022\033\n\023last_broadcasted_at\030" + - "\010 \001(\003\0224\n\006source\030\007 \001(\0162$.wallet.Transacti" + - "onConfidence.Source\022=\n\006ixType\030\023 \001(\0162$.wa", - "llet.TransactionConfidence.IXType:\007IX_NO" + - "NE\"`\n\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020\001\022\013\n" + - "\007PENDING\020\002\022\025\n\021NOT_IN_BEST_CHAIN\020\003\022\010\n\004DEA" + - "D\020\004\022\017\n\013IN_CONFLICT\020\005\"A\n\006Source\022\022\n\016SOURCE" + - "_UNKNOWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017\n\013SOURCE" + - "_SELF\020\002\"4\n\006IXType\022\013\n\007IX_NONE\020\000\022\016\n\nIX_REQ" + - "UEST\020\001\022\r\n\tIX_LOCKED\020\002\"\303\005\n\013Transaction\022\017\n" + - "\007version\030\001 \002(\005\022\014\n\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001" + - "(\0162\030.wallet.Transaction.Pool\022\021\n\tlock_tim" + - "e\030\004 \001(\r\022\022\n\nupdated_at\030\005 \001(\003\0223\n\021transacti", - "on_input\030\006 \003(\0132\030.wallet.TransactionInput" + - "\0225\n\022transaction_output\030\007 \003(\0132\031.wallet.Tr" + - "ansactionOutput\022\022\n\nblock_hash\030\010 \003(\014\022 \n\030b" + - "lock_relativity_offsets\030\013 \003(\005\0221\n\nconfide" + - "nce\030\t \001(\0132\035.wallet.TransactionConfidence" + - "\0225\n\007purpose\030\n \001(\0162\033.wallet.Transaction.P" + - "urpose:\007UNKNOWN\022+\n\rexchange_rate\030\014 \001(\0132\024" + - ".wallet.ExchangeRate\022\014\n\004memo\030\r \001(\t\"Y\n\004Po" + - "ol\022\013\n\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002" + - "\022\010\n\004DEAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACT", - "IVE\020\022\"\243\001\n\007Purpose\022\013\n\007UNKNOWN\020\000\022\020\n\014USER_P" + - "AYMENT\020\001\022\020\n\014KEY_ROTATION\020\002\022\034\n\030ASSURANCE_" + - "CONTRACT_CLAIM\020\003\022\035\n\031ASSURANCE_CONTRACT_P" + - "LEDGE\020\004\022\033\n\027ASSURANCE_CONTRACT_STUB\020\005\022\r\n\t" + - "RAISE_FEE\020\006\"N\n\020ScryptParameters\022\014\n\004salt\030" + - "\001 \002(\014\022\020\n\001n\030\002 \001(\003:\00516384\022\014\n\001r\030\003 \001(\005:\0018\022\014\n" + - "\001p\030\004 \001(\005:\0011\"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004" + - "data\030\002 \002(\014\022\021\n\tmandatory\030\003 \002(\010\" \n\003Tag\022\013\n\003" + - "tag\030\001 \002(\t\022\014\n\004data\030\002 \002(\014\"5\n\021TransactionSi" + - "gner\022\022\n\nclass_name\030\001 \002(\t\022\014\n\004data\030\002 \001(\014\"\351", - "\004\n\006Wallet\022\032\n\022network_identifier\030\001 \002(\t\022\034\n" + - "\024last_seen_block_hash\030\002 \001(\014\022\036\n\026last_seen" + - "_block_height\030\014 \001(\r\022!\n\031last_seen_block_t" + - "ime_secs\030\016 \001(\003\022\030\n\003key\030\003 \003(\0132\013.wallet.Key" + - "\022(\n\013transaction\030\004 \003(\0132\023.wallet.Transacti" + - "on\022&\n\016watched_script\030\017 \003(\0132\016.wallet.Scri" + - "pt\022C\n\017encryption_type\030\005 \001(\0162\035.wallet.Wal" + - "let.EncryptionType:\013UNENCRYPTED\0227\n\025encry" + - "ption_parameters\030\006 \001(\0132\030.wallet.ScryptPa" + - "rameters\022\022\n\007version\030\007 \001(\005:\0011\022$\n\textensio", - "n\030\n \003(\0132\021.wallet.Extension\022\023\n\013descriptio" + - "n\030\013 \001(\t\022\031\n\021key_rotation_time\030\r \001(\004\022\031\n\004ta" + - "gs\030\020 \003(\0132\013.wallet.Tag\0226\n\023transaction_sig" + - "ners\030\021 \003(\0132\031.wallet.TransactionSigner\";\n" + - "\016EncryptionType\022\017\n\013UNENCRYPTED\020\001\022\030\n\024ENCR" + - "YPTED_SCRYPT_AES\020\002\"a\n\013MultiWallet\022\022\n\007ver" + - "sion\030\001 \001(\005:\0011\022\037\n\007wallets\030\002 \003(\0132\016.wallet." + - "Wallet\022\035\n\010mnemonic\030\003 \002(\0132\013.wallet.Key\"R\n" + - "\014ExchangeRate\022\022\n\ncoin_value\030\001 \002(\003\022\022\n\nfia" + - "t_value\030\002 \002(\003\022\032\n\022fiat_currency_code\030\003 \002(", - "\tB\032\n\020org.pivxj.walletB\006Protos" + "ht\030\006 \001(\003\022\030\n\003key\030\007 \002(\0132\013.wallet.Key\"\266\003\n\003K" + + "ey\022\036\n\004type\030\001 \002(\0162\020.wallet.Key.Type\022\024\n\014se" + + "cret_bytes\030\002 \001(\014\022-\n\016encrypted_data\030\006 \001(\013" + + "2\025.wallet.EncryptedData\022\022\n\npublic_key\030\003 " + + "\001(\014\022\r\n\005label\030\004 \001(\t\022\032\n\022creation_timestamp" + + "\030\005 \001(\003\0223\n\021deterministic_key\030\007 \001(\0132\030.wall" + + "et.DeterministicKey\022\032\n\022deterministic_see", + "d\030\010 \001(\014\022;\n\034encrypted_deterministic_seed\030" + + "\t \001(\0132\025.wallet.EncryptedData\022\032\n\004zpiv\030\n \001" + + "(\0132\014.wallet.Zpiv\"a\n\004Type\022\014\n\010ORIGINAL\020\001\022\030" + + "\n\024ENCRYPTED_SCRYPT_AES\020\002\022\032\n\026DETERMINISTI" + + "C_MNEMONIC\020\003\022\025\n\021DETERMINISTIC_KEY\020\004\"5\n\006S" + + "cript\022\017\n\007program\030\001 \002(\014\022\032\n\022creation_times" + + "tamp\030\002 \002(\003\"\353\001\n\020TransactionInput\022\"\n\032trans" + + "action_out_point_hash\030\001 \002(\014\022#\n\033transacti" + + "on_out_point_index\030\002 \002(\r\022\024\n\014script_bytes" + + "\030\003 \002(\014\022\020\n\010sequence\030\004 \001(\r\022\r\n\005value\030\005 \001(\003\022", + "*\n\"private_transaction_out_point_hash\030\006 " + + "\001(\014\022+\n#private_transaction_out_point_ind" + + "ex\030\007 \001(\r\"\177\n\021TransactionOutput\022\r\n\005value\030\001" + + " \002(\003\022\024\n\014script_bytes\030\002 \002(\014\022!\n\031spent_by_t" + + "ransaction_hash\030\003 \001(\014\022\"\n\032spent_by_transa" + + "ction_index\030\004 \001(\005\"\254\004\n\025TransactionConfide" + + "nce\0220\n\004type\030\001 \001(\0162\".wallet.TransactionCo" + + "nfidence.Type\022\032\n\022appeared_at_height\030\002 \001(" + + "\005\022\036\n\026overriding_transaction\030\003 \001(\014\022\r\n\005dep" + + "th\030\004 \001(\005\022)\n\014broadcast_by\030\006 \003(\0132\023.wallet.", + "PeerAddress\022\033\n\023last_broadcasted_at\030\010 \001(\003" + + "\0224\n\006source\030\007 \001(\0162$.wallet.TransactionCon" + + "fidence.Source\022=\n\006ixType\030\023 \001(\0162$.wallet." + + "TransactionConfidence.IXType:\007IX_NONE\"`\n" + + "\004Type\022\013\n\007UNKNOWN\020\000\022\014\n\010BUILDING\020\001\022\013\n\007PEND" + + "ING\020\002\022\025\n\021NOT_IN_BEST_CHAIN\020\003\022\010\n\004DEAD\020\004\022\017" + + "\n\013IN_CONFLICT\020\005\"A\n\006Source\022\022\n\016SOURCE_UNKN" + + "OWN\020\000\022\022\n\016SOURCE_NETWORK\020\001\022\017\n\013SOURCE_SELF" + + "\020\002\"4\n\006IXType\022\013\n\007IX_NONE\020\000\022\016\n\nIX_REQUEST\020" + + "\001\022\r\n\tIX_LOCKED\020\002\"\303\005\n\013Transaction\022\017\n\007vers", + "ion\030\001 \002(\005\022\014\n\004hash\030\002 \002(\014\022&\n\004pool\030\003 \001(\0162\030." + + "wallet.Transaction.Pool\022\021\n\tlock_time\030\004 \001" + + "(\r\022\022\n\nupdated_at\030\005 \001(\003\0223\n\021transaction_in" + + "put\030\006 \003(\0132\030.wallet.TransactionInput\0225\n\022t" + + "ransaction_output\030\007 \003(\0132\031.wallet.Transac" + + "tionOutput\022\022\n\nblock_hash\030\010 \003(\014\022 \n\030block_" + + "relativity_offsets\030\013 \003(\005\0221\n\nconfidence\030\t" + + " \001(\0132\035.wallet.TransactionConfidence\0225\n\007p" + + "urpose\030\n \001(\0162\033.wallet.Transaction.Purpos" + + "e:\007UNKNOWN\022+\n\rexchange_rate\030\014 \001(\0132\024.wall", + "et.ExchangeRate\022\014\n\004memo\030\r \001(\t\"Y\n\004Pool\022\013\n" + + "\007UNSPENT\020\004\022\t\n\005SPENT\020\005\022\014\n\010INACTIVE\020\002\022\010\n\004D" + + "EAD\020\n\022\013\n\007PENDING\020\020\022\024\n\020PENDING_INACTIVE\020\022" + + "\"\243\001\n\007Purpose\022\013\n\007UNKNOWN\020\000\022\020\n\014USER_PAYMEN" + + "T\020\001\022\020\n\014KEY_ROTATION\020\002\022\034\n\030ASSURANCE_CONTR" + + "ACT_CLAIM\020\003\022\035\n\031ASSURANCE_CONTRACT_PLEDGE" + + "\020\004\022\033\n\027ASSURANCE_CONTRACT_STUB\020\005\022\r\n\tRAISE" + + "_FEE\020\006\"N\n\020ScryptParameters\022\014\n\004salt\030\001 \002(\014" + + "\022\020\n\001n\030\002 \001(\003:\00516384\022\014\n\001r\030\003 \001(\005:\0018\022\014\n\001p\030\004 " + + "\001(\005:\0011\"8\n\tExtension\022\n\n\002id\030\001 \002(\t\022\014\n\004data\030", + "\002 \002(\014\022\021\n\tmandatory\030\003 \002(\010\" \n\003Tag\022\013\n\003tag\030\001" + + " \002(\t\022\014\n\004data\030\002 \002(\014\"5\n\021TransactionSigner\022" + + "\022\n\nclass_name\030\001 \002(\t\022\014\n\004data\030\002 \001(\014\"\351\004\n\006Wa" + + "llet\022\032\n\022network_identifier\030\001 \002(\t\022\034\n\024last" + + "_seen_block_hash\030\002 \001(\014\022\036\n\026last_seen_bloc" + + "k_height\030\014 \001(\r\022!\n\031last_seen_block_time_s" + + "ecs\030\016 \001(\003\022\030\n\003key\030\003 \003(\0132\013.wallet.Key\022(\n\013t" + + "ransaction\030\004 \003(\0132\023.wallet.Transaction\022&\n" + + "\016watched_script\030\017 \003(\0132\016.wallet.Script\022C\n" + + "\017encryption_type\030\005 \001(\0162\035.wallet.Wallet.E", + "ncryptionType:\013UNENCRYPTED\0227\n\025encryption" + + "_parameters\030\006 \001(\0132\030.wallet.ScryptParamet" + + "ers\022\022\n\007version\030\007 \001(\005:\0011\022$\n\textension\030\n \003" + + "(\0132\021.wallet.Extension\022\023\n\013description\030\013 \001" + + "(\t\022\031\n\021key_rotation_time\030\r \001(\004\022\031\n\004tags\030\020 " + + "\003(\0132\013.wallet.Tag\0226\n\023transaction_signers\030" + + "\021 \003(\0132\031.wallet.TransactionSigner\";\n\016Encr" + + "yptionType\022\017\n\013UNENCRYPTED\020\001\022\030\n\024ENCRYPTED" + + "_SCRYPT_AES\020\002\"a\n\013MultiWallet\022\022\n\007version\030" + + "\001 \001(\005:\0011\022\037\n\007wallets\030\002 \003(\0132\016.wallet.Walle", + "t\022\035\n\010mnemonic\030\003 \002(\0132\013.wallet.Key\"R\n\014Exch" + + "angeRate\022\022\n\ncoin_value\030\001 \002(\003\022\022\n\nfiat_val" + + "ue\030\002 \002(\003\022\032\n\022fiat_currency_code\030\003 \002(\tB\032\n\020" + + "org.pivxj.walletB\006Protos" }; com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { @@ -22098,7 +22529,7 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( internal_static_wallet_Zpiv_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_wallet_Zpiv_descriptor, - new java.lang.String[] { "Version", "Commitment", "Serial", "Den", "ParentTxId", "Height", }); + new java.lang.String[] { "Version", "Commitment", "Serial", "Den", "ParentTxId", "Height", "Key", }); internal_static_wallet_Key_descriptor = getDescriptor().getMessageTypes().get(5); internal_static_wallet_Key_fieldAccessorTable = new @@ -22116,7 +22547,7 @@ public com.google.protobuf.ExtensionRegistry assignDescriptors( internal_static_wallet_TransactionInput_fieldAccessorTable = new com.google.protobuf.GeneratedMessage.FieldAccessorTable( internal_static_wallet_TransactionInput_descriptor, - new java.lang.String[] { "TransactionOutPointHash", "TransactionOutPointIndex", "ScriptBytes", "Sequence", "Value", }); + new java.lang.String[] { "TransactionOutPointHash", "TransactionOutPointIndex", "ScriptBytes", "Sequence", "Value", "PrivateTransactionOutPointHash", "PrivateTransactionOutPointIndex", }); internal_static_wallet_TransactionOutput_descriptor = getDescriptor().getMessageTypes().get(8); internal_static_wallet_TransactionOutput_fieldAccessorTable = new diff --git a/core/src/main/java/org/pivxj/wallet/Wallet.java b/core/src/main/java/org/pivxj/wallet/Wallet.java index d481a085b..8a0faae2d 100644 --- a/core/src/main/java/org/pivxj/wallet/Wallet.java +++ b/core/src/main/java/org/pivxj/wallet/Wallet.java @@ -24,6 +24,7 @@ import com.google.common.util.concurrent.*; import com.google.protobuf.*; import com.zerocoinj.core.CoinDenomination; +import com.zerocoinj.core.CoinSpend; import com.zerocoinj.core.ZCoin; import host.furszy.zerocoinj.WalletFilesInterface; import host.furszy.zerocoinj.protocol.GenWitMessage; @@ -47,7 +48,6 @@ import org.pivxj.wallet.listeners.WalletEventListener; import org.pivxj.wallet.listeners.WalletReorganizeEventListener; import org.slf4j.*; -import org.spongycastle.crypto.Commitment; import org.spongycastle.crypto.params.*; import javax.annotation.*; @@ -1038,7 +1038,7 @@ public boolean isWatchedScript(Script script) { } @Override - public boolean isZcOutputMine(Script script) { + public boolean isZcScriptMine(Script script) { keyChainGroupLock.lock(); try{ if (watchedScripts.contains(script)){ @@ -1047,10 +1047,11 @@ public boolean isZcOutputMine(Script script) { if (script.isZcMint()){ BigInteger commitmentValue = script.getCommitmentValue(); return keyChainGroup.isCommitmentValuesMine(commitmentValue); - }else { - // TODO: Check zc_spend here.. - return false; + }else if (script.isZcSpend()){ + CoinSpend coinSpend = script.getCoinSpend(params, Context.zerocoinContext); + return keyChainGroup.isCoinSerialMine(coinSpend.getCoinSerialNumber()); } + return false; } } finally { keyChainGroupLock.unlock(); @@ -1118,7 +1119,7 @@ private void markKeysAsUsed(Transaction tx) { } else if (script.isPayToScriptHash()) { Address a = Address.fromP2SHScript(tx.getParams(), script); keyChainGroup.markP2SHAddressAsUsed(a); - } else if (script.isZcMint()){ + } else if (script.isZcMint() && getActiveKeyChain().isZerocoinPath()){ keyChainGroup.markCommitmentValueAsUsed(script.getCommitmentValue()); } } catch (ScriptException e) { @@ -1904,6 +1905,40 @@ public boolean isPendingTransactionLockRelevant(Transaction tx) throws ScriptExc public boolean isTransactionRelevant(Transaction tx) throws ScriptException { lock.lock(); try { + if (getActiveKeyChain().isZerocoinPath() && + tx.getHashAsString().equals("81ad478724332c24ee6e3893e40bb4ef93e8240477b7b11a326ae5951567f8cb") + ){ + log.info("mine"); + } + // Before check this, try to connect the output in case of zc_spend + try { + for (int i = 0; i < tx.getInputs().size(); i++) { + TransactionInput input = tx.getInputs().get(i); + if (input.isZcspend()) { + CoinSpend coinSpend = input.getScriptSig().getCoinSpend(params, Context.zerocoinContext); + ZCoin zCoin = getActiveKeyChain().getZcoinsAssociatedToSerial(coinSpend.getCoinSerialNumber()); + if (zCoin != null) { + // now i can get the tx that minted this value + Sha256Hash parentHash = null; + int index = -1; + for (Transaction transaction : transactions.values()) { + for (TransactionOutput output : transaction.getOutputs()) { + if (output.isZcMint() && output.getScriptPubKey().getCommitmentValue().equals(zCoin.getCommitment().getCommitmentValue())) { + parentHash = transaction.getHash(); + index = output.getIndex(); + break; + } + } + if (parentHash != null) break; + } + input.getOutpoint().setPrivateIndex(index); + input.getOutpoint().setPrivateHash(parentHash); + } + } + } + }catch (Exception e){ + log.error("exception on zc_spend parsing..",e); + } return tx.getValueSentFromMe(this).signum() > 0 || tx.getValueSentToMe(this).signum() > 0 || !findDoubleSpendsAgainst(tx, transactions).isEmpty(); @@ -2244,7 +2279,7 @@ public void notifyNewBestBlock(StoredBlock block) throws VerificationException { // included once again. We could have a separate was-in-chain-and-now-isn't confidence type // but this way is backwards compatible with existing software, and the new state probably // wouldn't mean anything different to just remembering peers anyway. - if (confidence.incrementDepthInBlocks() > context.getEventHorizon()) + if (confidence.incrementDepthInBlocks(block.getHeight()) > context.getEventHorizon()) confidence.clearBroadcastBy(); confidenceChanged.put(tx, TransactionConfidence.Listener.ChangeReason.DEPTH); } @@ -2348,13 +2383,13 @@ private void updateForSpends(Transaction tx, boolean fromChain) throws Verificat if (fromChain) checkState(!pending.containsKey(tx.getHash())); for (TransactionInput input : tx.getInputs()) { - TransactionInput.ConnectionResult result = input.connect(unspent, TransactionInput.ConnectMode.ABORT_ON_CONFLICT); + TransactionInput.ConnectionResult result = input.connect(this, unspent, TransactionInput.ConnectMode.ABORT_ON_CONFLICT); if (result == TransactionInput.ConnectionResult.NO_SUCH_TX) { // Not found in the unspent map. Try again with the spent map. - result = input.connect(spent, TransactionInput.ConnectMode.ABORT_ON_CONFLICT); + result = input.connect(this, spent, TransactionInput.ConnectMode.ABORT_ON_CONFLICT); if (result == TransactionInput.ConnectionResult.NO_SUCH_TX) { // Not found in the unspent and spent maps. Try again with the pending map. - result = input.connect(pending, TransactionInput.ConnectMode.ABORT_ON_CONFLICT); + result = input.connect(this, pending, TransactionInput.ConnectMode.ABORT_ON_CONFLICT); if (result == TransactionInput.ConnectionResult.NO_SUCH_TX) { // Doesn't spend any of our outputs or is coinbase. continue; @@ -2402,7 +2437,8 @@ private void updateForSpends(Transaction tx, boolean fromChain) throws Verificat // less random order. for (Transaction pendingTx : pending.values()) { for (TransactionInput input : pendingTx.getInputs()) { - TransactionInput.ConnectionResult result = input.connect(tx, TransactionInput.ConnectMode.ABORT_ON_CONFLICT); + // TODO: Check this, have to be changed to the new method with the zcoin.. + TransactionInput.ConnectionResult result = input.connect(tx, null, TransactionInput.ConnectMode.ABORT_ON_CONFLICT); if (fromChain) { // This TX is supposed to have just appeared on the best chain, so its outputs should not be marked // as spent yet. If they are, it means something is happening out of order. @@ -2467,13 +2503,13 @@ private void killTxns(Set txnsToKill, @Nullable Transaction overrid return; log.warn("Now attempting to connect the inputs of the overriding transaction."); for (TransactionInput input : overridingTx.getInputs()) { - TransactionInput.ConnectionResult result = input.connect(unspent, TransactionInput.ConnectMode.DISCONNECT_ON_CONFLICT); + TransactionInput.ConnectionResult result = input.connect(this, unspent, TransactionInput.ConnectMode.DISCONNECT_ON_CONFLICT); if (result == TransactionInput.ConnectionResult.SUCCESS) { maybeMovePool(input.getConnectedTransaction(), "kill"); myUnspents.remove(input.getConnectedOutput()); log.info("Removing from UNSPENTS: {}", input.getConnectedOutput()); } else { - result = input.connect(spent, TransactionInput.ConnectMode.DISCONNECT_ON_CONFLICT); + result = input.connect(this, spent, TransactionInput.ConnectMode.DISCONNECT_ON_CONFLICT); if (result == TransactionInput.ConnectionResult.SUCCESS) { maybeMovePool(input.getConnectedTransaction(), "kill"); myUnspents.remove(input.getConnectedOutput()); @@ -2996,7 +3032,7 @@ private void addWalletTransaction(Pool pool, Transaction tx) { switch (pool) { case UNSPENT: //case INSTANTX_LOCKED: - if (unspent.containsKey(tx.getHash())) System.out.println("Unspent pool contains: "+tx.getHashAsString()); + if (unspent.containsKey(tx.getHash())) log.info("Unspent pool contains: "+tx.getHashAsString()); checkState(unspent.put(tx.getHash(), tx) == null); break; case SPENT: @@ -4182,6 +4218,7 @@ public void completeTx(SendRequest req) throws InsufficientMoneyException { */ public void completeSendRequest(ZCSpendRequest spendRequest) { SendRequest request = spendRequest.getSendRequest(); + long tweak = (long) (Math.random() * Long.MAX_VALUE); for (TransactionInput input : request.tx.getInputs()) { // First get the zcoin to spend TransactionOutput connectedOutput = input.getConnectedOutput(); @@ -4190,26 +4227,29 @@ public void completeSendRequest(ZCSpendRequest spendRequest) { // Now get the mint transaction associated with this coin Sha256Hash mintTxId = connectedOutput.getParentTransactionHash(); - int mintTxHeight = lastBlockSeenHeight - connectedOutput.getParentTransaction().getConfidence().getAppearedAtChainHeight(); + int mintTxHeight = connectedOutput.getParentTransaction().getConfidence().getAppearedAtChainHeight(); - if (mintTxHeight < CoinDefinition.ZEROCOIN_REQUIRED_STAKE_DEPTH){ + if (mintTxHeight < CoinDefinition.MINT_REQUIRED_CONFIRMATIONS){ throw new IllegalStateException("Coin depth is lower than the minimum spend depth"); } zCoin.setHeight(mintTxHeight); zCoin.setParentTxId(mintTxId); + if (zCoin.getCoinDenomination() == CoinDenomination.ZQ_ERROR){ + zCoin.setCoinDenomination(CoinDenomination.fromValue((int) (connectedOutput.getValue().value / 100000000))); + } // Now create the genWithMessage - spendRequest.addWaitingRequest(newGenWitMessage(zCoin), zCoin); + spendRequest.addWaitingRequest(newGenWitMessage(zCoin, tweak), zCoin); } } - private GenWitMessage newGenWitMessage(ZCoin zCoin) { + private GenWitMessage newGenWitMessage(ZCoin zCoin, long tweak) { GenWitMessage genWitMessage = new GenWitMessage( params, zCoin.getHeight(), // minted height zCoin.getCoinDenomination(), - 1, 0.001, (long) (Math.random() * Long.MAX_VALUE) + 1, 0.01, tweak ); BigInteger bnValue = zCoin.getCommitment().getCommitmentValue(); genWitMessage.insert(bnValue); diff --git a/core/src/main/java/org/pivxj/wallet/WalletProtobufSerializer.java b/core/src/main/java/org/pivxj/wallet/WalletProtobufSerializer.java index 4ee5550ad..8796d7afc 100644 --- a/core/src/main/java/org/pivxj/wallet/WalletProtobufSerializer.java +++ b/core/src/main/java/org/pivxj/wallet/WalletProtobufSerializer.java @@ -146,10 +146,12 @@ public String walletToText(Wallet wallet) { } public Protos.MultiWallet.Builder walletToProto(MultiWallet multiWallet) { + // TODO: Deadlock en el getWalletTransactions y en el saveToFile de la multiWallet. DeterministicSeed seed = multiWallet.getSeed(); Protos.Key.Builder mnemonicEntry = BasicKeyChain.serializeEncryptableItem(seed); mnemonicEntry.setType(Protos.Key.Type.DETERMINISTIC_MNEMONIC); serializeSeedEncryptableItem(seed, mnemonicEntry); + return Protos.MultiWallet.newBuilder() .addWallets( walletToProto(multiWallet.getPivWallet()) @@ -168,7 +170,6 @@ public Protos.Wallet walletToProto(Wallet wallet) { if (wallet.getDescription() != null) { walletBuilder.setDescription(wallet.getDescription()); } - for (WalletTransaction wtx : wallet.getWalletTransactions()) { Protos.Transaction txProto = makeTxProto(wtx); walletBuilder.addTransaction(txProto); @@ -272,6 +273,13 @@ private static Protos.Transaction makeTxProto(WalletTransaction wtx) { .setScriptBytes(ByteString.copyFrom(input.getScriptBytes())) .setTransactionOutPointHash(hashToByteString(input.getOutpoint().getHash())) .setTransactionOutPointIndex((int) input.getOutpoint().getIndex()); + if (input.getOutpoint().getPrivateHash() != null){ + inputBuilder.setPrivateTransactionOutPointHash(hashToByteString(input.getOutpoint().getPrivateHash())); + } + if (input.getOutpoint().getPrivateIndex() != -1){ + inputBuilder.setPrivateTransactionOutPointIndex((int) input.getOutpoint().getPrivateIndex()); + } + if (input.hasSequence()) inputBuilder.setSequence((int) input.getSequenceNumber()); if (input.getValue() != null) @@ -334,7 +342,17 @@ private static Protos.Transaction makeTxProto(WalletTransaction wtx) { if (tx.getMemo() != null) txBuilder.setMemo(tx.getMemo()); - return txBuilder.build(); + Protos.Transaction txProto = txBuilder.build(); + // Transaction should now be complete. + Sha256Hash protoHash = byteStringToHash(txProto.getHash()); + if (!tx.getHash().equals(protoHash)) + try { + throw new UnreadableWalletException(String.format(Locale.US, "Transaction did not deserialize completely: %s vs %s", tx.getHash(), protoHash)); + } catch (UnreadableWalletException e) { + e.printStackTrace(); + } + + return txProto; } private static Protos.Transaction.Pool getProtoPool(WalletTransaction wtx) { @@ -687,7 +705,7 @@ public static Protos.Wallet parseToProto(InputStream input) throws IOException { public static Protos.MultiWallet parseMultiToProto(InputStream input) throws IOException{ CodedInputStream codedInput = CodedInputStream.newInstance(input); - codedInput.setSizeLimit(WALLET_SIZE_LIMIT); + codedInput.setSizeLimit(WALLET_SIZE_LIMIT * 2); return Protos.MultiWallet.parseFrom(codedInput); } @@ -710,6 +728,12 @@ private void readTransaction(Protos.Transaction txProto, NetworkParameters param inputProto.getTransactionOutPointIndex() & 0xFFFFFFFFL, byteStringToHash(inputProto.getTransactionOutPointHash()) ); + if (inputProto.hasPrivateTransactionOutPointHash()){ + outpoint.setPrivateHash(byteStringToHash(inputProto.getPrivateTransactionOutPointHash())); + } + if (inputProto.hasPrivateTransactionOutPointIndex()){ + outpoint.setPrivateIndex(inputProto.getPrivateTransactionOutPointIndex() & 0xFFFFFFFFL); + } Coin value = inputProto.hasValue() ? Coin.valueOf(inputProto.getValue()) : null; TransactionInput input = new TransactionInput(params, tx, scriptBytes, outpoint, value); if (inputProto.hasSequence()) @@ -756,8 +780,11 @@ private void readTransaction(Protos.Transaction txProto, NetworkParameters param // Transaction should now be complete. Sha256Hash protoHash = byteStringToHash(txProto.getHash()); - if (!tx.getHash().equals(protoHash)) - throw new UnreadableWalletException(String.format(Locale.US, "Transaction did not deserialize completely: %s vs %s", tx.getHash(), protoHash)); + if (!tx.getHash().equals(protoHash)) { + if (!tx.getHash().equals(protoHash)) { + throw new UnreadableWalletException(String.format(Locale.US, "Transaction did not deserialize completely: tx: %s vs proto: %s", tx.getHash(), protoHash)); + } + } if (txMap.containsKey(txProto.getHash())) throw new UnreadableWalletException("Wallet contained duplicate transaction " + byteStringToHash(txProto.getHash())); txMap.put(txProto.getHash(), tx); diff --git a/core/src/main/java/org/pivxj/wallet/exceptions/InvalidCoinException.java b/core/src/main/java/org/pivxj/wallet/exceptions/InvalidCoinException.java new file mode 100644 index 000000000..6e9da3109 --- /dev/null +++ b/core/src/main/java/org/pivxj/wallet/exceptions/InvalidCoinException.java @@ -0,0 +1,7 @@ +package org.pivxj.wallet.exceptions; + +public class InvalidCoinException extends RuntimeException { + public InvalidCoinException(String message) { + super(message); + } +} diff --git a/core/src/main/java/org/pivxj/wallet/exceptions/RequestFailedException.java b/core/src/main/java/org/pivxj/wallet/exceptions/RequestFailedException.java new file mode 100644 index 000000000..b15974386 --- /dev/null +++ b/core/src/main/java/org/pivxj/wallet/exceptions/RequestFailedException.java @@ -0,0 +1,10 @@ +package org.pivxj.wallet.exceptions; + +public class RequestFailedException extends Exception { + public RequestFailedException() { + } + + public RequestFailedException(String message) { + super(message); + } +} diff --git a/core/src/test/java/org/pivxj/wallet/MultiWalletTest.java b/core/src/test/java/org/pivxj/wallet/MultiWalletTest.java index 61c11cbf3..f74fb550f 100644 --- a/core/src/test/java/org/pivxj/wallet/MultiWalletTest.java +++ b/core/src/test/java/org/pivxj/wallet/MultiWalletTest.java @@ -1,6 +1,7 @@ package org.pivxj.wallet; import com.zerocoinj.JniBridge; +import com.zerocoinj.core.CoinDenomination; import com.zerocoinj.core.ZCoin; import com.zerocoinj.core.context.ZerocoinContext; import host.furszy.zerocoinj.wallet.MultiWallet; @@ -70,24 +71,23 @@ public void generateZPIV(){ tx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{10,2,3,4}))); multiWallet.commitTx(tx); + // Confirmed tx + sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN, tx); + sendMoneyToWallet(multiWallet.getZpivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN,tx); sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); sendMoneyToWallet(multiWallet.getZpivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); sendMoneyToWallet(multiWallet.getZpivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); - // Confirmed tx - sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN, tx); - sendMoneyToWallet(multiWallet.getZpivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN,tx); // More blocks.. sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); - sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); - sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); + Transaction tx2 = multiWallet.getTransaction(tx.getHash()); - System.out.println(multiWallet.getPivWallet()); - // TODO: add the receiving part of this.. i have to check how is this calculated - System.out.println(multiWallet.getZPivWallet()); + Assert.assertEquals("Invalid depth in blocks", 5, tx2.getConfidence().getDepthInBlocks()); } catch (InsufficientMoneyException e) { @@ -149,10 +149,12 @@ public void recreateWalletTest(){ } /** - * Test to validate that the zPIV wallet understand mint txes and add them to the wallet balance + * Test create mint, save the wallet and restore it. + * The minted zcoin needs to have the values saved. */ + @Test - public void addZpivToWalletBalanceTest() { + public void mintSaveRestoreTest(){ try { NetworkParameters params = UnitTestParams.get(); setUp(); @@ -162,8 +164,71 @@ public void addZpivToWalletBalanceTest() { System.currentTimeMillis() ); MultiWallet multiWallet = new MultiWallet(params, new ZerocoinContext(new JniBridge()), seed); + + ZCoin myFirstCoin = multiWallet.getZPivWallet().getWallet().getActiveKeyChain().getZcoins(1).get(0); + + // load balance loadWallet(multiWallet, Coin.valueOf(2, 0)); - SendRequest req = multiWallet.createMintRequest(Coin.valueOf(2, 0)); + // mint + SendRequest req = multiWallet.createMintRequest(Coin.valueOf(1, 0)); + Transaction tx = req.tx; + tx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{1, 2, 3, 4}))); + tx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{10, 2, 3, 4}))); + multiWallet.commitTx(tx); + + // obtain the minted coin + TransactionOutput mintOutput = null; + for (TransactionOutput output : tx.getOutputs()) { + if (output.isZcMint()){ + mintOutput = output; + } + } + ZCoin minteCoin = multiWallet.getZcoinAssociated(mintOutput.getScriptPubKey().getCommitmentValue()); + + // Now check that both coins commitments are equals + Assert.assertEquals("Coins are not equals", minteCoin.getCommitment(), myFirstCoin.getCommitment()); + + Assert.assertSame("Minted coin denomination is not correct", minteCoin.getCoinDenomination(), CoinDenomination.ZQ_ONE); + + // Confirmed tx + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN, tx); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN, tx); + // More blocks.. + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + new WalletProtobufSerializer().walletToProto(multiWallet).build().writeTo(outputStream); + byte[] walletBytes = outputStream.toByteArray(); + outputStream.close(); + + ByteArrayInputStream inputStream = new ByteArrayInputStream(walletBytes); + MultiWallet multiWallet2 = new WalletProtobufSerializer().readMultiWallet(inputStream, false, null); + + ZCoin myCoinRestaured = multiWallet2.getZPivWallet().getWallet().getActiveKeyChain().getZcoins(1).get(0); + + Assert.assertEquals("Restored coin is not equal", minteCoin.getCommitment(), myCoinRestaured.getCommitment()); + Assert.assertSame("Restored minted coin denomination is not correct", myCoinRestaured.getCoinDenomination(), CoinDenomination.ZQ_ONE); + + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + } + + @Test + public void moveMintFromPendingPoolToUnspentPool(){ + + try { + NetworkParameters params = UnitTestParams.get(); + setUp(); + DeterministicSeed seed = new DeterministicSeed( + Hex.decode("760a00eda285a842ad99626b61faebb6e36d80decae6665ac9c5f4c17db5185858d9fed30b6cd78a7daff4e07c88bf280cfc595620a4107613b50cab42a32f9b"), + "", + System.currentTimeMillis() + ); + MultiWallet multiWallet = new MultiWallet(params, new ZerocoinContext(new JniBridge()), seed); + loadWallet(multiWallet, Coin.valueOf(2, 0)); + SendRequest req = multiWallet.createMintRequest(Coin.valueOf(1, 0)); Transaction tx = req.tx; @@ -171,6 +236,8 @@ public void addZpivToWalletBalanceTest() { tx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{10, 2, 3, 4}))); multiWallet.commitTx(tx); + Assert.assertTrue("Mint is not in pending pool", + multiWallet.getZpivWallet().getTransactionPool(WalletTransaction.Pool.PENDING).containsKey(tx.getHash())); sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); @@ -180,12 +247,69 @@ public void addZpivToWalletBalanceTest() { sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN, tx); sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN, tx); // More blocks.. + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + + Assert.assertTrue("Mint is not in unspendable pool", + multiWallet.getZpivWallet().getTransactionPool(WalletTransaction.Pool.UNSPENT).containsKey(tx.getHash())); + + Assert.assertEquals("Invalid value sent to me", tx.getValueSentToMe(multiWallet.getZpivWallet()), Coin.COIN); + Assert.assertEquals("Invalid value sent from me", tx.getValueSentFromMe(multiWallet.getPivWallet()), Coin.valueOf(2,0)); + + } catch (Exception e) { + Assert.fail(e.getMessage()); + } + + + } + + /** + * Test to validate that the zPIV wallet understand mint txes and add them to the wallet balance + */ + @Test + public void addZpivToWalletBalanceTest() { + try { + NetworkParameters params = UnitTestParams.get(); + setUp(); + DeterministicSeed seed = new DeterministicSeed( + Hex.decode("760a00eda285a842ad99626b61faebb6e36d80decae6665ac9c5f4c17db5185858d9fed30b6cd78a7daff4e07c88bf280cfc595620a4107613b50cab42a32f9b"), + "", + System.currentTimeMillis() + ); + MultiWallet multiWallet = new MultiWallet(params, new ZerocoinContext(new JniBridge()), seed); + loadWallet(multiWallet, Coin.valueOf(2, 0)); + SendRequest req = multiWallet.createMintRequest(Coin.valueOf(1, 0)); + + + Transaction tx = req.tx; + tx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{1, 2, 3, 4}))); + tx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{10, 2, 3, 4}))); + multiWallet.commitTx(tx); + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + // Confirmed tx + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN, tx); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN, tx); + // More blocks.. sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); Assert.assertTrue("Zpiv balance has not been increased" , multiWallet.getZpivWallet().getBalance().isGreaterThan(Coin.ZERO)); + + + // Now spend it and check if the wallet notice that + + //SendRequest sendRequest = multiWallet.createSpendRequest(multiWallet.getCurrentReceiveAddress(),Coin.COIN); + //multiWallet.spendZpiv(sendRequest) + + } catch (Exception e) { Assert.fail(e.getMessage()); } diff --git a/core/src/test/java/org/pivxj/zerocoin/CoinSpendTest.java b/core/src/test/java/org/pivxj/zerocoin/CoinSpendTest.java index d5a501872..132044f14 100644 --- a/core/src/test/java/org/pivxj/zerocoin/CoinSpendTest.java +++ b/core/src/test/java/org/pivxj/zerocoin/CoinSpendTest.java @@ -2,24 +2,31 @@ import com.google.common.collect.Lists; import com.zerocoinj.JniBridge; -import com.zerocoinj.core.CoinDenomination; -import com.zerocoinj.core.Commitment; -import com.zerocoinj.core.ZCoin; +import com.zerocoinj.core.*; import com.zerocoinj.core.accumulators.Accumulator; import com.zerocoinj.core.accumulators.AccumulatorWitness; +import com.zerocoinj.core.accumulators.Accumulators; import com.zerocoinj.core.context.ZerocoinContext; import host.furszy.zerocoinj.protocol.GenWitMessage; import host.furszy.zerocoinj.protocol.PubcoinsMessage; +import host.furszy.zerocoinj.wallet.InvalidSpendException; import host.furszy.zerocoinj.wallet.MultiWallet; +import org.junit.Assert; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.pivxj.core.*; import org.pivxj.net.MessageWriteTarget; +import org.pivxj.params.MainNetParams; import org.pivxj.params.UnitTestParams; import org.pivxj.testing.TestWithWallet; import org.pivxj.wallet.DeterministicSeed; import org.pivxj.wallet.SendRequest; +import org.pivxj.wallet.Wallet; +import org.pivxj.wallet.WalletProtobufSerializer; import org.spongycastle.util.encoders.Hex; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; @@ -27,119 +34,294 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import org.junit.Rule; public class CoinSpendTest extends TestWithWallet { - @Test - public void validCoinSpendTest() throws Exception { + public void validCoinSpendWithCppDataTest(){ - // The test basically load the wallet with 2 new mints and fill up them until they are spendable - // Then try to spending them getting a valid accumulator from the node. + NetworkParameters params = MainNetParams.get(); + Context context = Context.getOrCreate(params); + context.zerocoinContext.jniBridge = new JniBridge(); - final NetworkParameters params = UnitTestParams.get(); - setUp(); + // Setup the wallet DeterministicSeed seed = new DeterministicSeed( Hex.decode("760a00eda285a842ad99626b61faebb6e36d80decae6665ac9c5f4c17db5185858d9fed30b6cd78a7daff4e07c88bf280cfc595620a4107613b50cab42a32f9b"), "", System.currentTimeMillis() ); - final MultiWallet multiWallet = new MultiWallet(params, new ZerocoinContext(new JniBridge()), seed); - loadWallet(multiWallet, Coin.valueOf(2,0)); - SendRequest req = multiWallet.createMintRequest(Coin.valueOf(2, 0)); + final MultiWallet multiWallet = new MultiWallet(params, new ZerocoinContext(new JniBridge()), seed, 15); - Transaction tx = req.tx; - tx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{1,2,3,4}))); - tx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{10,2,3,4}))); - multiWallet.commitTx(tx); + // Setup the accumulator status with random coins + List coins = multiWallet.freshZcoins(15); + for (ZCoin coin : coins) { + coin.setCoinDenomination(CoinDenomination.ZQ_ONE); + } - sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); - sendMoneyToWallet(multiWallet.getZpivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); - // Confirmed tx - sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN, tx); - sendMoneyToWallet(multiWallet.getZpivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN,tx); + ZCoin myCoin = coins.get(5); - this.wallet = multiWallet.getZpivWallet(); - // Now 200 blocks depth - for (int i = 0; i < 500; i++) { - sendMoneyToWallet(multiWallet.getPivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); - sendMoneyToWallet(multiWallet.getZpivWallet(),AbstractBlockChain.NewBlockType.BEST_CHAIN); + Assert.assertEquals("Serial not valid", + new BigInteger("112528974699127969510791029434430131089903980535436389917566704532828560273751"), + myCoin.getSerial()); + // valid serial --> 008f9c42288d572cf96394a7ff0c6247579c8a5bdc1227e220417cb7f620721b75 + // adjusted serial --> 3973891039144036301193230988785217477463369911398361130575219525410001236311 + // adjusted serial vch (NET) --> 809c42288d572cf96394a7ff0c6247579c8a5bdc1227e220417cb7f620721b75 + // adjusted serial hex (no sirve este..)--> 8c92482d875c29f36497affc0267475c9a8b5cd21722e0214c77b6f0227b157 + + System.out.println(myCoin); + + Accumulator accumulator = new Accumulator(context.zerocoinContext.accumulatorParams, myCoin.getCoinDenomination()); + AccumulatorWitness witness = new AccumulatorWitness(accumulator, myCoin); + + for (ZCoin coin : coins) { + accumulator.accumulate(coin); + if (!coin.equals(myCoin)) + witness.addElement(coin); } - // Now create the accumulator with the coin to spend + System.out.println("Accumulator: " + accumulator.getValue()); + System.out.println("Witness: " + witness.getValue()); + + // build the transaction + Transaction tx = new Transaction(params); + tx.addOutput(Coin.COIN, multiWallet.freshReceiveAddress()); + Sha256Hash ptxHash = tx.getHash(); + + CoinSpend coinSpend = new CoinSpend( + context.zerocoinContext, + myCoin, + accumulator, + BigInteger.ZERO, + witness, + ptxHash, + SpendType.SPEND, + null + ); + if (!coinSpend.verify(accumulator)) { + Assert.fail("CoinSpend verify failed"); + } - // Create the spend of 1 zPIV - ExecutorService executor = Executors.newSingleThreadExecutor(); - PeergroupUtil peergroupUtil = new PeergroupUtil(params); - peergroupUtil.addWallet(multiWallet.getZpivWallet()); + if (!coinSpend.hasValidSignature()){ + Assert.fail("CoinSpend signature invalid, coinSpend: " + coinSpend); + } - SendRequest spendRequest = multiWallet.createSpendRequest(multiWallet.getPivWallet().freshReceiveAddress(), Coin.COIN); + BigInteger adjustedSerial = ZCoin.getAdjustedSerial(coinSpend.getCoinSerialNumber()); + Assert.assertTrue( + "Not valid serial", + Utils.areBigIntegersEqual( + new BigInteger("3973891039144036301193230988785217477463369911398361130575219525410001236311"), + adjustedSerial + ) + ); + } - BigInteger commitmentValue = spendRequest.tx.getInput(0).getConnectedOutput().getScriptPubKey().getCommitmentValue(); - final ZCoin coinToSpend = multiWallet.getZpivWallet().getZcoin(commitmentValue); + @Test + public void validCoinSpendWithCppData2Test(){ - final Peer peer = peergroupUtil.getConnectedPeers().get(0); - peer.setWriteTarget(new MessageWriteTarget() { - @Override - public void writeBytes(byte[] message) throws IOException { + NetworkParameters params = MainNetParams.get(); + Context context = Context.getOrCreate(params); + context.zerocoinContext.jniBridge = new JniBridge(); - System.out.println("Sending message.."); - System.out.println(Hex.toHexString(message)); + // Setup the wallet + DeterministicSeed seed = new DeterministicSeed( + Hex.decode("760a00eda285a842ad99626b61faebb6e36d80decae6665ac9c5f4c17db5185858d9fed30b6cd78a7daff4e07c88bf280cfc595620a4107613b50cab42a32f9b"), + "", + System.currentTimeMillis() + ); + final MultiWallet multiWallet = new MultiWallet(params, new ZerocoinContext(new JniBridge()), seed, 15); - new Thread(new Runnable() { - @Override - public void run() { - // Accumulator calculation - ZerocoinContext zerocoinContext = Context.get().zerocoinContext; - // Accumualtor - Accumulator acc = new Accumulator(zerocoinContext.getAccumulatorParams(),CoinDenomination.ZQ_ONE); - AccumulatorWitness witness = new AccumulatorWitness(acc.copy(), coinToSpend); + // Setup the accumulator status with random coins + List coins = multiWallet.freshZcoins(15); + for (ZCoin coin : coins) { + coin.setCoinDenomination(CoinDenomination.ZQ_ONE); + } - List networkCoins = Lists.newArrayList(multiWallet.getZpivWallet().getZcoins(4)); - if (!networkCoins.contains(coinToSpend)){ - networkCoins.add(coinToSpend); - } - for (ZCoin coin : networkCoins) { - if (coin.getCoinDenomination() != CoinDenomination.ZQ_ONE) - coin.setCoinDenomination(CoinDenomination.ZQ_ONE); - acc.accumulate(coin); - if (!coin.equals(coinToSpend)) { - witness.addElement(coin); - } - } + for (int i = 0; i < coins.size(); i++) { - PubcoinsMessage pubcoinsMessage = new PubcoinsMessage( - params, - acc.getValue(), - witness.getValue(), - Lists.newArrayList(coinToSpend.getCommitment().getCommitmentValue()), - 10 - ); - - try { - TimeUnit.SECONDS.sleep(1); - peer.processPubcoins(pubcoinsMessage); - } catch (Exception e) { - e.printStackTrace(); - } + ZCoin myCoin = coins.get(i); - } - }).start(); + Accumulator accumulator = new Accumulator(context.zerocoinContext.accumulatorParams, myCoin.getCoinDenomination()); + AccumulatorWitness witness = new AccumulatorWitness(accumulator, myCoin); + for (ZCoin coin : coins) { + accumulator.accumulate(coin); + if (!coin.equals(myCoin)) + witness.addElement(coin); + } + // build the transaction + Transaction tx = new Transaction(params); + tx.addOutput(Coin.COIN, multiWallet.freshReceiveAddress()); + Sha256Hash ptxHash = tx.getHash(); + + CoinSpend coinSpend = new CoinSpend( + context.zerocoinContext, + myCoin, + accumulator, + BigInteger.ZERO, + witness, + ptxHash, + SpendType.SPEND, + null + ); + + if (!coinSpend.verify(accumulator)) { + Assert.fail("CoinSpend verify failed"); } - @Override - public void closeConnection() { + if (!coinSpend.hasValidSignature()){ + Assert.fail("CoinSpend signature invalid, coinSpend: " + coinSpend); + } + + } + } + + @Test + public void test(){ + NetworkParameters params = MainNetParams.get(); + Context.getOrCreate(params); + System.out.println(ECKey.fromPrivate(Hex.decode("8b21ddfbd2e20cc5b04606b8d57736ea390176f170cbe1216019680cfb36f0f2")).getPrivateKeyAsWiF(params)); + } + + @Test + public void validCoinSpendTest() { + + try { + + // The test basically load the wallet with 2 new mints and fill up them until they are spendable + // Then try to spending them getting a valid accumulator from the node. + + final NetworkParameters params = UnitTestParams.get(); + setUp(); + DeterministicSeed seed = new DeterministicSeed( + Hex.decode("760a00eda285a842ad99626b61faebb6e36d80decae6665ac9c5f4c17db5185858d9fed30b6cd78a7daff4e07c88bf280cfc595620a4107613b50cab42a32f9b"), + "", + System.currentTimeMillis() + ); + final MultiWallet multiWallet = new MultiWallet(params, new ZerocoinContext(new JniBridge()), seed); + loadWallet(multiWallet, Coin.valueOf(1, 0)); + SendRequest req = multiWallet.createMintRequest(Coin.valueOf(1, 0)); + + Transaction mintTx = req.tx; + mintTx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{1, 2, 3, 4}))); + mintTx.getConfidence().markBroadcastBy(new PeerAddress(PARAMS, InetAddress.getByAddress(new byte[]{10, 2, 3, 4}))); + multiWallet.commitTx(mintTx); + + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + // Confirmed tx + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN, mintTx); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN, mintTx); + + this.wallet = multiWallet.getZpivWallet(); + // Now 20 blocks depth + for (int i = 0; i < 20; i++) { + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); } - }); - multiWallet.spendZpiv(spendRequest,peergroupUtil,executor); + // Now create the accumulator with the coin to spend + + + // Create the spend of 1 zPIV + ExecutorService executor = Executors.newSingleThreadExecutor(); + PeergroupUtil peergroupUtil = new PeergroupUtil(params); + peergroupUtil.addWallet(multiWallet.getZpivWallet()); + + SendRequest spendRequest = multiWallet.createSpendRequest(multiWallet.getPivWallet().freshReceiveAddress(), Coin.COIN); + + BigInteger commitmentValue = spendRequest.tx.getInput(0).getConnectedOutput().getScriptPubKey().getCommitmentValue(); + final ZCoin coinToSpend = multiWallet.getZpivWallet().getZcoin(commitmentValue); + + final Peer peer = peergroupUtil.getConnectedPeers().get(0); + peer.setWriteTarget(new MessageWriteTarget() { + @Override + public void writeBytes(byte[] message) throws IOException { + + System.out.println("Sending message.."); + System.out.println(Hex.toHexString(message)); + + new Thread(new Runnable() { + @Override + public void run() { + try { + // Accumulator calculation + ZerocoinContext zerocoinContext = Context.get().zerocoinContext; + zerocoinContext.jniBridge = new JniBridge(); + // Accumulator + Accumulator acc = new Accumulator(zerocoinContext.getAccumulatorParams(), CoinDenomination.ZQ_ONE); + AccumulatorWitness witness = new AccumulatorWitness(acc.copy(), coinToSpend); + + List networkCoins = Lists.newArrayList(multiWallet.getZpivWallet().getZcoins(4)); + if (!networkCoins.contains(coinToSpend)) { + networkCoins.add(coinToSpend); + } + for (ZCoin coin : networkCoins) { + if (coin.getCoinDenomination() != CoinDenomination.ZQ_ONE) + coin.setCoinDenomination(CoinDenomination.ZQ_ONE); + acc.accumulate(coin); + if (!coin.equals(coinToSpend)) { + witness.addElement(coin); + } + } + + PubcoinsMessage pubcoinsMessage = new PubcoinsMessage( + params, + acc.getValue(), + witness.getValue(), + Lists.newArrayList(coinToSpend.getCommitment().getCommitmentValue()), + 1 + ); + + try { + TimeUnit.SECONDS.sleep(1); + peer.processPubcoins(pubcoinsMessage); + } catch (Exception e) { + e.printStackTrace(); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + }).start(); + + + } + + @Override + public void closeConnection() { + + } + }); + + Transaction spentTx = multiWallet.spendZpiv(spendRequest, peergroupUtil, executor, new JniBridge()); + + // Now check + multiWallet.getZpivWallet().maybeCommitTx(spentTx); - System.out.println(multiWallet.getZpivWallet()); + // Confirm tx + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getPivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN, spentTx); + + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + sendMoneyToWallet(multiWallet.getZpivWallet(), AbstractBlockChain.NewBlockType.BEST_CHAIN); + + // Check the balance, must be zero + Assert.assertEquals("Wallet balance result is not correct", multiWallet.getZPivWallet().getBalance(Wallet.BalanceType.AVAILABLE), Coin.ZERO); + + }catch (Exception e){ + Assert.fail(e.getMessage()); + } } @@ -157,4 +339,8 @@ private void loadWallet(MultiWallet multiWallet, Coin coin) { } } + /** + * TODO: Un buen test puede ser armar una transacción valida de coinSpend, generar la wallet y enviarla por el notifyTx + */ + } diff --git a/core/src/test/java/org/pivxj/zerocoin/ConnectionTest.java b/core/src/test/java/org/pivxj/zerocoin/ConnectionTest.java new file mode 100644 index 000000000..f3c644ae7 --- /dev/null +++ b/core/src/test/java/org/pivxj/zerocoin/ConnectionTest.java @@ -0,0 +1,244 @@ +package org.pivxj.zerocoin; + +import com.google.common.base.Charsets; +import com.subgraph.orchid.encoders.Hex; +import com.zerocoinj.core.CoinSpend; +import host.furszy.zerocoinj.MultiWalletFiles; +import host.furszy.zerocoinj.wallet.MultiWallet; +import host.furszy.zerocoinj.wallet.files.Listener; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.pivxj.core.*; +import org.pivxj.core.listeners.AbstractPeerDataEventListener; +import org.pivxj.core.listeners.BlocksDownloadedEventListener; +import org.pivxj.core.listeners.TransactionConfidenceEventListener; +import org.pivxj.net.discovery.PeerDiscovery; +import org.pivxj.net.discovery.PeerDiscoveryException; +import org.pivxj.params.MainNetParams; +import org.pivxj.store.BlockStore; +import org.pivxj.store.BlockStoreException; +import org.pivxj.store.LevelDBBlockStore; +import org.pivxj.utils.BriefLogFormatter; +import org.pivxj.wallet.KeyChainGroup; +import org.pivxj.wallet.UnreadableWalletException; +import org.pivxj.wallet.Wallet; +import org.pivxj.wallet.WalletProtobufSerializer; + +import javax.annotation.Nullable; +import java.io.*; +import java.net.InetSocketAddress; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.TimeZone; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class ConnectionTest { + + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); + + @Test + public void syncTest(){ + try { + NetworkParameters params = MainNetParams.get(); + final MultiWallet multiWallet = restore(params); + multiWallet.setKeyChainGroupLookaheadThreshold(75); + BriefLogFormatter.init(); + + Context context = new Context(params); + File walletFile = new File("wallet_connection_test.dat"); + if (walletFile.exists()){ + walletFile.delete(); + } + File file = new File("watching_blockstore_2.dat"); + if (file.exists()){ + if (file.isDirectory()){ + for (File file1 : file.listFiles()) { + file1.delete(); + } + }else file.delete(); + } + BlockStore spvBlockStore = new LevelDBBlockStore(context,file); + try { + String filename = "checkpoints"; + String suffix = params instanceof MainNetParams ? "":"-testnet"; + final InputStream checkpointsInputStream = new FileInputStream(new File("/Users/furszy/Documents/pivx_wallet/dashj", filename)); + CheckpointManager.checkpoint(params, checkpointsInputStream, spvBlockStore, multiWallet.getEarliestKeyCreationTime()); + }catch (final IOException x) { + x.printStackTrace(); + }catch (Exception e){ + e.printStackTrace(); + } + final BlockChain blockChain = new BlockChain(context,spvBlockStore); + multiWallet.addWalletFrom(blockChain); + PeerGroup peerGroup = new PeerGroup(params,blockChain); + //peerGroup.addPeerDiscovery(new DnsDiscovery(networkParameters)); + peerGroup.addPeerDiscovery(new PeerDiscovery() { + @Override + public InetSocketAddress[] getPeers(long services, long timeoutValue, TimeUnit timeoutUnit) throws PeerDiscoveryException { + return new InetSocketAddress[]{ + //new InetSocketAddress("202.5.21.31",51474), + new InetSocketAddress("localhost",7776) + //new InetSocketAddress("localhost",51474) + //new InetSocketAddress("88.198.192.110",51474) + }; + } + + @Override + public void shutdown() { + + } + }); + peerGroup.setDownloadTxDependencies(0); + multiWallet.addPeergroup(peerGroup); + peerGroup.setMaxPeersToDiscoverCount(1); + peerGroup.startBlockChainDownload(new AbstractPeerDataEventListener(){ + @Override + public void onBlocksDownloaded(Peer peer, Block block, @Nullable FilteredBlock filteredBlock, int blocksLeft) { + if ((blocksLeft/10000) == 0) { + System.out.println("block left: " + blocksLeft + ", hash: " + block.getHash().toString()); + } + } + }); + + ExecutorService executor = Executors.newSingleThreadExecutor(); + final File tempFile = tempFolder.newFile("tempFile.txt"); + multiWallet.addOnTransactionsConfidenceChange(executor, new TransactionConfidenceEventListener() { + @Override + public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) { + //try { + // Check that the serialization works right.. + + System.out.println( + "Transaction: " + tx.getHashAsString() + ", "+ org.spongycastle.util.encoders.Hex.toHexString(tx.unsafeBitcoinSerialize() + ) + ); + + //multiWallet.saveToFile(tempFile); + //FileInputStream inputStream = new FileInputStream(tempFile); + //MultiWallet wallet1 = new WalletProtobufSerializer().readMultiWallet(inputStream, false, null); + + //Assert.assertTrue("Not consistent wallet", wallet1.isConsistent()); +// } catch (UnreadableWalletException e) { +// e.printStackTrace(); +// } catch (FileNotFoundException e) { +// e.printStackTrace(); +// } catch (IOException e) { +// e.printStackTrace(); +// } + } + }); + + peerGroup.startAsync(); + peerGroup.downloadBlockChain(); + + + while (true){ + try { + TimeUnit.SECONDS.sleep(120); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + + } catch (IOException e) { + e.printStackTrace(); + } catch (BlockStoreException e) { + e.printStackTrace(); + } + } + + public MultiWallet restore(NetworkParameters networkParameters) throws IOException { + String filename = "3.0.0_pivx-wallet-backup_org.pivx.production-2018-08-11"; + //"1.01_pivx-wallet-backup_org.pivx.production-2017-07-26 (2)"; + String password = "123";//"12345678"; + + + File file = new File("/Users/furszy/Documents/pivx_wallet/dashj/core/src/test/java/org/pivxj/zerocoin", filename); + System.out.println(file.getAbsolutePath()); + final BufferedReader cipherIn = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charsets.UTF_8)); + final StringBuilder cipherText = new StringBuilder(); + copy(cipherIn, cipherText, 10000000); + cipherIn.close(); + + final byte[] plainText = Crypto.decryptBytes(cipherText.toString(), password.toCharArray()); + final InputStream is = new ByteArrayInputStream(plainText); + + MultiWallet wallet = restoreWalletFromProtobufOrBase58(is, networkParameters, 10000000); + return wallet; + } + + public static final long copy(final Reader reader, final StringBuilder builder) throws IOException + { + return copy(reader, builder, 0); + } + + public static final long copy(final Reader reader, final StringBuilder builder, final long maxChars) throws IOException + { + final char[] buffer = new char[256]; + long count = 0; + int n = 0; + while (-1 != (n = reader.read(buffer))) + { + builder.append(buffer, 0, n); + count += n; + + if (maxChars != 0 && count > maxChars) + throw new IOException("Read more than the limit of " + maxChars + " characters"); + } + return count; + } + + public static final long copy(final InputStream is, final OutputStream os) throws IOException + { + final byte[] buffer = new byte[1024]; + long count = 0; + int n = 0; + while (-1 != (n = is.read(buffer))) + { + os.write(buffer, 0, n); + count += n; + } + return count; + } + + public static MultiWallet restoreWalletFromProtobufOrBase58(final InputStream is, final NetworkParameters expectedNetworkParameters,long backupMaxChars) throws IOException + { + is.mark((int) backupMaxChars); + + try + { + return restoreWalletFromProtobuf(is, expectedNetworkParameters); + } + catch (final IOException x) + { + throw new IOException("cannot read protobuf (" + x.getMessage() + ") or base58 (" + x.getMessage() + ")", x); + + } + } + + public static MultiWallet restoreWalletFromProtobuf(final InputStream is, final NetworkParameters expectedNetworkParameters) throws IOException { + try { + final MultiWallet wallet = new WalletProtobufSerializer().readMultiWallet(is, true, null); + if (!wallet.getParams().equals(expectedNetworkParameters)) + throw new IOException("bad wallet backup network parameters: " + wallet.getParams().getId()); + if (!wallet.isConsistent()) + throw new IOException("inconsistent wallet backup"); + + return wallet; + } catch (final UnreadableWalletException x) { + throw new IOException("unreadable wallet", x); + } + } + +} diff --git a/core/src/test/java/org/pivxj/zerocoin/PeergroupUtil.java b/core/src/test/java/org/pivxj/zerocoin/PeergroupUtil.java index 3275b4ba7..bb783c7fa 100644 --- a/core/src/test/java/org/pivxj/zerocoin/PeergroupUtil.java +++ b/core/src/test/java/org/pivxj/zerocoin/PeergroupUtil.java @@ -1,6 +1,7 @@ package org.pivxj.zerocoin; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.ListenableFuture; import org.pivxj.core.*; import org.pivxj.net.ClientConnectionManager; import javax.annotation.Nullable; @@ -45,4 +46,9 @@ public PeergroupUtil(Context context, @Nullable AbstractBlockChain chain, Client public List getConnectedPeers() { return Lists.newArrayList(peerUtil); } + + @Override + public List findPeersOfAtLeastVersion(long protocolVersion) { + return Lists.newArrayList(peerUtil); + } } diff --git a/core/src/wallet.proto b/core/src/wallet.proto index f101b8ef7..e7b7ffe34 100644 --- a/core/src/wallet.proto +++ b/core/src/wallet.proto @@ -99,6 +99,7 @@ message Zpiv{ optional int32 den = 4; optional bytes parentTxId = 5; optional int64 height = 6; + required Key key = 7; } @@ -186,6 +187,11 @@ message TransactionInput { optional uint32 sequence = 4; // Value of connected output, if known optional int64 value = 5; + + // Hash of the transaction this input is using. + optional bytes private_transaction_out_point_hash = 6; + // Index of transaction output used by this input. + optional uint32 private_transaction_out_point_index = 7; } message TransactionOutput { diff --git a/examples/src/main/java/org/pivxj/examples/BackupToMnemonicSeed.java b/examples/src/main/java/org/pivxj/examples/BackupToMnemonicSeed.java index 1013d2da1..0afe7357b 100644 --- a/examples/src/main/java/org/pivxj/examples/BackupToMnemonicSeed.java +++ b/examples/src/main/java/org/pivxj/examples/BackupToMnemonicSeed.java @@ -36,9 +36,9 @@ public static void main(String[] args) { Wallet wallet = new Wallet(params); DeterministicSeed seed = wallet.getKeyChainSeed(); - System.out.println("seed: " + seed.toString()); + //System.out.println("seed: " + seed.toString()); - System.out.println("creation time: " + seed.getCreationTimeSeconds()); - System.out.println("mnemonicCode: " + Utils.join(seed.getMnemonicCode())); + //System.out.println("creation time: " + seed.getCreationTimeSeconds()); + //System.out.println("mnemonicCode: " + Utils.join(seed.getMnemonicCode())); } } diff --git a/tools/src/main/java/org/pivxj/tools/BuildCheckpoints.java b/tools/src/main/java/org/pivxj/tools/BuildCheckpoints.java index 0baa5d99b..9611367ae 100644 --- a/tools/src/main/java/org/pivxj/tools/BuildCheckpoints.java +++ b/tools/src/main/java/org/pivxj/tools/BuildCheckpoints.java @@ -31,6 +31,7 @@ import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; +import sun.applet.Main; import java.io.DataOutputStream; import java.io.File; @@ -94,7 +95,7 @@ public static void main(String[] args) throws Exception { //params = TestNet3Params.get(); //suffix = "-testnet"; - params = TestNet3Params.get(); + params = MainNetParams.get(); suffix = ""; @@ -109,7 +110,7 @@ public static void main(String[] args) throws Exception { return; }InetAddress.getLocalHost(); } else { - ipAddress = InetAddress.getByName("202.5.21.31"); // InetAddress.getLocalHost(); + ipAddress = InetAddress.getLocalHost(); //InetAddress.getByName("202.5.21.31"); // InetAddress.getLocalHost(); } final PeerAddress peerAddress = new PeerAddress(ipAddress, params.getPort()); @@ -129,14 +130,17 @@ public static void main(String[] args) throws Exception { long now = new Date().getTime() / 1000; peerGroup.setFastCatchupTimeSecs(now); - final long timeAgo = now - (86400 * 170);//options.valueOf(daysFlag)); + final long timeAgo = now - (86400 * options.valueOf(daysFlag)); System.out.println("Checkpointing up to " + Utils.dateTimeFormat(timeAgo * 1000)); chain.addNewBestBlockListener(Threading.SAME_THREAD, new NewBestBlockListener() { @Override public void notifyNewBestBlock(StoredBlock block) throws VerificationException { int height = block.getHeight(); - System.out.println("block height: "+block.getHeight()); + //System.out.println("block height: "+block.getHeight()); + if (height % 10000 == 0){ + System.out.println("height: " + height); + } if (height % CoinDefinition.getIntervalCheckpoints() == 0 && block.getHeader().getTimeSeconds() <= timeAgo) { //if(height == 201500){ System.out.println(String.format("Checkpointing block %s at height %d, time %s", @@ -176,7 +180,7 @@ private static void writeBinaryCheckpoints(TreeMap checkpo dataOutputStream.writeInt(0); // Number of signatures to read. Do this later. digestOutputStream.on(true); dataOutputStream.writeInt(checkpoints.size()); - ByteBuffer buffer = ByteBuffer.allocate(StoredBlock.COMPACT_SERIALIZED_SIZE); + ByteBuffer buffer = ByteBuffer.allocate(StoredBlock.COMPACT_SERIALIZED_SIZE_ZEROCOIN); for (StoredBlock block : checkpoints.values()) { block.serializeCompact(buffer); dataOutputStream.write(buffer.array()); @@ -195,7 +199,7 @@ private static void writeTextualCheckpoints(TreeMap checkp writer.println("TXT CHECKPOINTS 1"); writer.println("0"); // Number of signatures to read. Do this later. writer.println(checkpoints.size()); - ByteBuffer buffer = ByteBuffer.allocate(StoredBlock.COMPACT_SERIALIZED_SIZE); + ByteBuffer buffer = ByteBuffer.allocate(StoredBlock.COMPACT_SERIALIZED_SIZE_ZEROCOIN); for (StoredBlock block : checkpoints.values()) { block.serializeCompact(buffer); writer.println(CheckpointManager.BASE64.encode(buffer.array()));