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()));