Allow Bitcoin URI's that don't have any address component if the r= payment protocol param is there.

This commit is contained in:
Mike Hearn
2014-01-28 13:04:09 +01:00
parent 3966875e8e
commit ddec4f9106
3 changed files with 32 additions and 16 deletions

View File

@@ -149,10 +149,9 @@ public class BitcoinURI {
// Split off the address from the rest of the query parameters. // Split off the address from the rest of the query parameters.
String[] addressSplitTokens = schemeSpecificPart.split("\\?"); String[] addressSplitTokens = schemeSpecificPart.split("\\?");
if (addressSplitTokens.length == 0 || "".equals(addressSplitTokens[0])) { if (addressSplitTokens.length == 0)
throw new BitcoinURIParseException("Missing address"); throw new BitcoinURIParseException("No data found after the bitcoin: prefix");
} String addressToken = addressSplitTokens[0]; // may be empty!
String addressToken = addressSplitTokens[0];
String[] nameValuePairTokens; String[] nameValuePairTokens;
if (addressSplitTokens.length == 1) { if (addressSplitTokens.length == 1) {
@@ -169,6 +168,20 @@ public class BitcoinURI {
// Attempt to parse the rest of the URI parameters. // Attempt to parse the rest of the URI parameters.
parseParameters(params, addressToken, nameValuePairTokens); parseParameters(params, addressToken, nameValuePairTokens);
if (!addressToken.isEmpty()) {
// Attempt to parse the addressToken as a Bitcoin address for this network
try {
Address address = new Address(params, addressToken);
putWithValidation(FIELD_ADDRESS, address);
} catch (final AddressFormatException e) {
throw new BitcoinURIParseException("Bad address", e);
}
}
if (addressToken.isEmpty() && getPaymentRequestUrl() == null) {
throw new BitcoinURIParseException("No address and no r= parameter found");
}
} }
/** /**
@@ -177,14 +190,6 @@ public class BitcoinURI {
* separated by '=' e.g. 'amount=0.2') * separated by '=' e.g. 'amount=0.2')
*/ */
private void parseParameters(@Nullable NetworkParameters params, String addressToken, String[] nameValuePairTokens) throws BitcoinURIParseException { private void parseParameters(@Nullable NetworkParameters params, String addressToken, String[] nameValuePairTokens) throws BitcoinURIParseException {
// Attempt to parse the addressToken as a Bitcoin address for this network
try {
Address address = new Address(params, addressToken);
putWithValidation(FIELD_ADDRESS, address);
} catch (final AddressFormatException e) {
throw new BitcoinURIParseException("Bad address", e);
}
// Attempt to decode the rest of the tokens into a parameter map. // Attempt to decode the rest of the tokens into a parameter map.
for (String nameValuePairToken : nameValuePairTokens) { for (String nameValuePairToken : nameValuePairTokens) {
String[] tokens = nameValuePairToken.split("="); String[] tokens = nameValuePairToken.split("=");
@@ -242,8 +247,11 @@ public class BitcoinURI {
} }
/** /**
* @return The Bitcoin Address from the URI * The Bitcoin Address from the URI, if one was present. It's possible to have Bitcoin URI's with no address if a
* r= payment protocol parameter is specified, though this form is not recommended as older wallets can't understand
* it.
*/ */
@Nullable
public Address getAddress() { public Address getAddress() {
return (Address) parameterMap.get(FIELD_ADDRESS); return (Address) parameterMap.get(FIELD_ADDRESS);
} }

View File

@@ -240,7 +240,7 @@ public class BitcoinURITest {
testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
+ "?amount=6543210&label=Hello%20World&message=Be%20well"); + "?amount=6543210&label=Hello%20World&message=Be%20well");
assertEquals( assertEquals(
"BitcoinURI['address'='1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH','amount'='654321000000000','label'='Hello World','message'='Be well']", "BitcoinURI['amount'='654321000000000','label'='Hello World','message'='Be well','address'='1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH']",
testObject.toString()); testObject.toString());
} }
@@ -367,7 +367,7 @@ public class BitcoinURITest {
// Unknown not required field // Unknown not required field
testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
+ "?aardvark=true"); + "?aardvark=true");
assertEquals("BitcoinURI['address'='1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH','aardvark'='true']", testObject.toString()); assertEquals("BitcoinURI['aardvark'='true','address'='1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH']", testObject.toString());
assertEquals("true", (String) testObject.getParameterByName("aardvark")); assertEquals("true", (String) testObject.getParameterByName("aardvark"));
@@ -416,4 +416,12 @@ public class BitcoinURITest {
new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
+ "?amount=100000000"); + "?amount=100000000");
} }
@Test
public void testPaymentProtocolReq() throws Exception {
// Non-backwards compatible form ...
BitcoinURI uri = new BitcoinURI(TestNet3Params.get(), "bitcoin:?r=https%3A%2F%2Fbitcoincore.org%2F%7Egavin%2Ff.php%3Fh%3Db0f02e7cea67f168e25ec9b9f9d584f9");
assertEquals("https://bitcoincore.org/~gavin/f.php?h=b0f02e7cea67f168e25ec9b9f9d584f9", uri.getPaymentRequestUrl());
assertNull(uri.getAddress());
}
} }

View File

@@ -506,7 +506,7 @@ public class WalletTool {
try { try {
paymentRequestURI = new BitcoinURI(location); paymentRequestURI = new BitcoinURI(location);
} catch (BitcoinURIParseException e) { } catch (BitcoinURIParseException e) {
System.err.println("Invalid bitcoin uri " + e.getMessage()); System.err.println("Invalid bitcoin uri: " + e.getMessage());
System.exit(1); System.exit(1);
} }
try { try {