Closed mackuba closed 10 years ago
It'd be a good idea to upgrade to 0.11.1 before doing that. There have been a bunch of fixes you'd want in that release and more queuing up.
I'm gonna need some design advice...
I'm adding the memos/notes now. There are three kinds of memos in the payment protocol, one for each of the messages, all optional:
I've added the first one for now, as a "details" field that can appear below the recipient (it's hidden if it's empty):
Now I'm wondering what to do with the other two. My current ideas:
Other unrelated changes:
Comments?
The PaymentACK memo is meant for people sending money to each other casually, tipping, donating etc really. It's probably not useful or might be actively unhelpful for payment processors and webshops. I think we might need a BIP70 extension to mark that PaymentACK memo's would actually get read. For now, hide it - other wallets don't support uploading a message either. It's a feature that seems half baked.
All the other design points look good to me.
@mikehearn if a bitcoin: URL through which you get the payment request also includes label/message fields, is it ok to use the label as a fallback for the receiver's name (if the request is not verified) or the message as a fallback memo, or should these be completely ignored if r= is set?
Hm, good question. I think most wallets ignore the rest of the URI if the r= parameter is there. This feels like another place where the relevant BIP could be tightened up. I'm not sure what the best behaviour is.
Whew, error handling is complex... and that's just the first part, now the error handling of payment sending...
Yeah, error handling is always a big chunk of code.
Sometimes I wonder if bitcoinj should provide pre-translated strings for common exceptions to save people the burden of doing this kind of thing over and over. Not sure. That looks like a good set of error messages so if you get translations for them I might steal them :)
Sometimes I wonder if bitcoinj should provide pre-translated strings for common exceptions to save people the burden of doing this kind of thing over and over.
I don't think this is something that should be done at the level of the library, people might want to use different language depending on what the target audience of their wallet is... ("java.net.UnknownHostException: Invalid hostname" vs. "Have you tried to turn it off and on again?" :).
I guess most wallet apps will want the latter vs the former. Or, exception.getMessage vs getLocalisedMessage.
Basically, what I want is that wallet authors can concentrate on stuff that differentiates themselves vs just boring plumbing. And I'd like to see a thousand wallets because that's awesomely decentralised, even if they're based on the same core code (they can easily fork it). So reducing expensive and redundant work seems valuable.
@mikehearn - two questions:
1) What should the wallet do if there is no payment_url?
2) I'm wondering about the case when I have a bad internet connection, I submit a payment to a merchant, and they receive the transaction, but the connection fails and the ACK doesn't get back to me. From their point of view, the payment was made, they broadcast the transaction and process my order. From my point of view, the payment wasn't made, since my wallet doesn't know if they've received my Payment message and it just told me "Payment could not be completed".
Is this something I should worry about? Do you think this can cause problems? (If the merchant broadcasts the transaction, my wallet should receive it in a moment anyway, right? Though it's possible that in the meantime I will try to send it again (creating a new transaction), but then hopefully the merchant will check some kind of order ID in the payment data and respond with an error because the order was already paid...)
1) Just broadcast the tx as normal. Payment is ignored. PaymentSession should handle this for you I thought? If not then we should fix it!
2) The wallet will see the transaction next time it connects to the internet. Though I note you can get this kind of razor-thin edge case with credit cards too (actually you get much worse problems like submitting orders twice and such).
PaymentSession should handle this for you I thought? If not then we should fix it!
I don't think it does, or at least I don't know how to do it... There's sendPayment
, but it calls getPayment
and if it returns null
it just gives up.
@mikehearn so if session.sendPayment
returns null
, I should just take the Wallet.SendRequest
that I tried to pass there and call wallet.sendCoins(peerGroup, request)
like in the normal send?
Yeah. Not a very good API. We need to integrate PaymentSession and wallet more.
Ok, added ticket here: https://code.google.com/p/bitcoinj/issues/detail?id=557
Woo! All boxes ticked!
It failed. I tried at the BitGive foundation:
http://bitgivefoundation.org/donate-now/
but got "Payment request file could not be loaded."
Works for me, or at least it opens:
Try again or check the logs.
What version of OS X are you testing with and how did you install Java?
The problem is that the base Apple 1.6 JVM is broken:
waterford:Hive mike$ ls -alh /Library/Java/JavaVirtualMachines/1.6.0_39-b04-443.jdk/Contents/Home/lib/security/ total 24 drwxr-xr-x 10 root wheel 340B 28 Feb 2013 ./ drwxr-xr-x 42 root wheel 1.4K 28 Feb 2013 ../ -rw-r--r-- 1 root wheel 2.4K 28 Feb 2013 US_export_policy.jar lrwxr-xr-x 1 root wheel 79B 28 Feb 2013 blacklist -> /System/Library/Java/Support/Deploy.bundle/Contents/Home/lib/security/blacklist lrwxr-xr-x 1 root wheel 81B 28 Feb 2013 cacerts -> /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts -rw-r--r-- 1 root wheel 3.4K 28 Feb 2013 java.policy -rw-r--r-- 1 root wheel 11K 28 Feb 2013 java.security -rw-r--r-- 1 root wheel 2.4K 28 Feb 2013 local_policy.jar -rw-r--r-- 1 root wheel 347B 28 Feb 2013 sunpkcs11-macosx.cfg lrwxr-xr-x 1 root wheel 87B 28 Feb 2013 trusted.libraries -> /System/Library/Java/Support/Deploy.bundle/Contents/Home/lib/security/trusted.libraries waterford:Hive mike$ waterford:Hive mike$ cat /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts cat: /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts: No such file or directory
so when it tries to download something via SSL:
DEBUG: Payment request load error: Error Domain=BitcoinKit Code=0 "The operation couldn’t be completed. javax.net.ssl.SSLException: java.lang.RuntimeException: Un expected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty" UserInfo=0x7fb4886a1190 {NSLocalizedFailureReason= javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non -empty, stackTrace=at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:190) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1762) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1723) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.handleException(SSLSocketImpl.java:1706) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1237) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1214) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1172) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234) at com.google.bitcoin.protocols.payments.PaymentSession$1.call(PaymentSession.java:192) at com.google.bitcoin.protocols.payments.PaymentSession$1.call(PaymentSession.java:186)
Given that bitcoinj already ships its own root store, we could probably work around this Apple bug quite easily on the bitcoinj side by just overriding the default trust store for HTTPS connections.
Ugh. OK, so I fixed it by installing the last update from Apple. Apparently that fixes Mavericks. However, now I see something even weirder.
Hive still cannot download via SSL:
DEBUG: Payment request load error: Error Domain=BitcoinKit Code=0 "The operation couldn’t be completed. javax.net.ssl.SSLKeyException: RSA premaster secret error" UserInfo=0x608000271a40 {NSLocalizedFailureReason=javax.net.ssl.SSLKeyException: RSA premaster secret error, stackTrace=at com.sun.net.ssl.internal.ssl.RSAClientKeyExchange.
However, using exactly the same JVM from the command line, WalletTool can fetch it just peachy!? I wonder what the difference is.
The above exception looks like it wraps another one. Normally you'd get several stack traces from such a throw, but in the logs I see only one. You might want to use Throwables.getRootCause(e) on the exception before passing it back to BitcoinKit to ensure maximum detail. Otherwise it's hard to debug what the real problem is here.
Anyway. It seems Apple managed to screw up their JVM pretty badly in this respect, I see lots of complaints that the Mavericks "upgrade" broke things on stackoverflow etc. So the question is what to do about it. We can:
1) Use the shipped cacerts file to patch up the Apple JVM. 2) Don't use bitcoinj/Java to download the payment request file/upload the ack and do it all in Objective-C. This would be inconvenient so I'd rather figure out what's going wrong. Plus Apple's SSL stack is obviously not tested and had a nasty security hole recently. 3) Wait for me to get Hive working with Avian (one of my post-conference tasks)
What version of OS X are you testing with and how did you install Java?
1.9.2, I don't remember how I got Java... I've got 1.6.0_65, but apparently I have nothing in /Library/Java/JavaVirtualMachines
, my Java is in /System/Library/Frameworks/JavaVM.framework
...
/System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts
file exists.
Let's see if anyone else has this problem, it's possible that it's just your installation that's somehow broken and it will work for everyone else...
However, using exactly the same JVM from the command line, WalletTool can fetch it just peachy!? I wonder what the difference is.
Can you check what java.ext.dirs
is set to on your machine? We're passing an option to the VM to exclude all of the directories that aren't in /System
to avoid collisions with some custom software, that might potentially cause problems. (Actually, if you have everything in /Library/Java
instead of /System
, then it probably does.)
The above exception looks like it wraps another one. Normally you'd get several stack traces from such a throw, but in the logs I see only one. You might want to use Throwables.getRootCause(e) on the exception before passing it back to BitcoinKit to ensure maximum detail. Otherwise it's hard to debug what the real problem is here.
I'll take a look.
Don't use bitcoinj/Java to download the payment request file/upload the ack and do it all in Objective-C. This would be inconvenient so I'd rather figure out what's going wrong.
I could do that for downloading the request without a lot of effort, but sending the payment would be harder since I'd need to rewrite a large part of what PaymentSession
does there...
Ah yes. It's probably the extdirs thing. I'll take a look at Avian soon.
Just tell me what those extdirs are on your computer, it's possible that I can just tweak that filter.
With the system Java 6 I see:
/Library/Java/Extensions:/System/Library/Java/Extensions:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext
(with wallet tool). Looks pretty normal. I don't think I have anything weird in those directories:
waterford:target mike$ ls /System/Library/Java/Extensions/ AppleScriptEngine.jar j3dcore.jar libJ3D.jnilib mlibwrapper_jai.jar MRJToolkit.jar j3dutils.jar libJ3DAudio.jnilib vecmath.jar QTJava.zip jai_codec.jar libJ3DUtils.jnilib dns_sd.jar jai_core.jar libQTJNative.jnilib j3daudio.jar libAppleScriptEngine.jnilib libmlib_jai.jnilib waterford:target mike$ ls /Library/Java/Extensions/ waterford:target mike$ ls /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext apple_provider.jar dnsns.jar localedata.jar sunjce_provider.jar sunpkcs11.jar waterford:target mike$
Hmm, so nothing from /Library/Java
in the extdirs except /Library/Java/Extensions
? In that case that shouldn't affect anything... Do you have anything in /Library/Java/Extensions
?
Nope it's empty. Not sure why it's dying, but I suspect one of the JARs in these directories is required for TLS to work - god knows why it's considered an "extension" but I see various crypto libs in the file listing above. So if extdirs is cleared perhaps it can't find the crypto libs anymore. From reading the code around that stack trace, I see dynamic loading of crypto code inside the try block, so that could be the case. Is there a way to stop Hive clearing the extdirs?
But only the /Library
extensions are excluded, the /System
ones should still be loaded...
Relevant code: https://github.com/hivewallet/BitcoinKit/blob/master/BitcoinJKit/java/bitcoinkit/src/main/java/com/hivewallet/bitcoinkit/ExtensionPathsReader.java https://github.com/hivewallet/BitcoinKit/blob/master/BitcoinJKit/HIBitcoinManager.m#L504-L517 https://github.com/hivewallet/BitcoinKit/blob/master/BitcoinJKit/HIBitcoinManager.m#L583-L617
The above exception looks like it wraps another one. Normally you'd get several stack traces from such a throw, but in the logs I see only one. You might want to use Throwables.getRootCause(e) on the exception before passing it back to BitcoinKit to ensure maximum detail. Otherwise it's hard to debug what the real problem is here.
Fixed here: https://github.com/hivewallet/BitcoinKit/commit/87f25526223fe921d4183d31428a7a094653a502
In this case, the root exception was:
java.security.NoSuchAlgorithmException: SunTlsRsaPremasterSecret KeyGenerator not available
at javax.crypto.KeyGenerator.<init>(DashoA13*..)
at javax.crypto.KeyGenerator.getInstance(DashoA13*..)
at com.sun.net.ssl.internal.ssl.JsseJce.getKeyGenerator(JsseJce.java:223)
...
I managed to reproduce this by setting java.ext.dirs
to an empty string, so it definitely has something to do with that.
Can you tell me:
java -cp Hive.app/Contents/Frameworks/BitcoinJKit.framework/Resources/boot.jar ExtensionPathsReader
I see:
/System/Library/Java/Extensions
and I don't see any messages with the words "list" in them in any Hive log file.
Hm, this is weird. If you look into ExtensionPathsReader.java
, you can see that it just prints java.ext.dirs
and filters out those that don't start with "/System". Which means that if your java.ext.dirs
is /Library/Java/Extensions:/System/Library/Java/Extensions:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext
, then ExtensionPathsReader
should return /System/Library/Java/Extensions:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext
, but it returns only the first one.
Where is your java
binary located? This method calls /usr/bin/java
. Is it possible that you have more than one java
binary and they use different configurations?
Oh you're right, sorry, my java defaults to 1.8.0. I ran it with the one in /Library/Java/Home
/System/Library/Java/Extensions:/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/ext
So /usr/bin/java
is 1.8 and 1.6 is in /Library/Java/Home/bin/java
?
Apparently! Not sure how it works. Probably /usr/bin/java is some kind of wrapper.
Try this one: https://github.com/hivewallet/hive-osx/releases/tag/2014052101 - I've changed it to use Java from Library instead of /usr/bin.
Yep now it works.
@mikehearn could you check if this build works for you? https://github.com/hivewallet/hive-osx/releases/tag/2014052701
I had to change the path again from /Library/Java/Home/bin/java
to /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java
, because the former doesn't work for some users. (BTW, these two are two different binaries on my computer, even though they print exactly the same version...)
Doesn't work. Nothing is printed in the console. The mess Apple has made of Java on MacOS is amazing:
waterford:assets mike$ /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Commands/java -version java version "1.6.0_65" Java(TM) SE Runtime Environment (build 1.6.0_65-b14-462-11M4609) Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-462, mixed mode) waterford:assets mike$ /System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java -version java version "1.8.0" Java(TM) SE Runtime Environment (build 1.8.0-b132) Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
How hard is it to just throw the apple Java 1.6 framework into the Hive app bundle entirely? I know Avian is a lot smaller and I'm making progress with that, but the system JVMs seem to move around or be very unreliable.
https://code.google.com/p/bitcoinj/wiki/PaymentProtocol
TODO: