mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-12 18:25:51 +00:00
Merge branch 'master' of https://code.google.com/p/bitcoinj
This commit is contained in:
commit
ddb6da155b
@ -181,15 +181,21 @@ public class ECKey implements Serializable {
|
||||
public String toString() {
|
||||
StringBuffer b = new StringBuffer();
|
||||
b.append("pub:").append(Utils.bytesToHexString(pub));
|
||||
if (priv != null) {
|
||||
b.append(" priv:").append(Utils.bytesToHexString(priv.toByteArray()));
|
||||
}
|
||||
if (creationTimeSeconds != 0) {
|
||||
b.append(" timestamp:" + creationTimeSeconds);
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public String toStringWithPrivate() {
|
||||
StringBuffer b = new StringBuffer();
|
||||
b.append(toString());
|
||||
if (priv != null) {
|
||||
b.append(" priv:").append(Utils.bytesToHexString(priv.toByteArray()));
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address that corresponds to the public part of this ECKey. Note that an address is derived from
|
||||
* the RIPEMD-160 hash of the public key and is not the public key itself (which is too large to be convenient).
|
||||
|
@ -275,6 +275,26 @@ public class Utils {
|
||||
BigInteger cents = value.remainder(COIN);
|
||||
return String.format("%s%d.%02d", negative ? "-" : "", coins.intValue(), cents.intValue() / 1000000);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Returns the given value as a plain string denominated in BTC.
|
||||
* The result is unformatted with no trailing zeroes.
|
||||
* For instance, an input value of BigInteger.valueOf(150000) nanocoin gives an output string of "0.0015" BTC
|
||||
* </p>
|
||||
*
|
||||
* @param value The value in nanocoins to convert to a string (denominated in BTC)
|
||||
* @throws IllegalArgumentException
|
||||
* If the input value is null
|
||||
*/
|
||||
public static String bitcoinValueToPlainString(BigInteger value) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
}
|
||||
|
||||
BigDecimal valueInBTC = new BigDecimal(value).divide(new BigDecimal(Utils.COIN));
|
||||
return valueInBTC.toPlainString();
|
||||
}
|
||||
|
||||
/**
|
||||
* MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
|
||||
|
375
src/com/google/bitcoin/uri/BitcoinURI.java
Normal file
375
src/com/google/bitcoin/uri/BitcoinURI.java
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.google.bitcoin.uri;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.bitcoin.core.Address;
|
||||
import com.google.bitcoin.core.AddressFormatException;
|
||||
import com.google.bitcoin.core.NetworkParameters;
|
||||
import com.google.bitcoin.core.Utils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Provides a standard implementation of a Bitcoin URI with support for the
|
||||
* following:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>URLEncoded URIs (as passed in by IE on the command line)</li>
|
||||
* <li>BIP21 names (including the "req-" prefix handling requirements)</li>
|
||||
* </ul>
|
||||
* <h2>Accepted formats</h2>
|
||||
* <p>
|
||||
* The following input forms are accepted
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@code bitcoin:<address>}</li>
|
||||
* <li>{@code bitcoin:<address>?<name1>=<value1>&<name2>=<value2>} with multiple
|
||||
* additional name/value pairs</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The name/value pairs are processed as follows:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>URL encoding is stripped and treated as UTF-8</li>
|
||||
* <li>names prefixed with {@code req-} are treated as required and if unknown
|
||||
* or conflicting cause a parse exception</li>
|
||||
* <li>Unknown names not prefixed with {@code req-} are added to a Map, accessible
|
||||
* by parameter name</li>
|
||||
* <li>Known names not prefixed with {@code req-} are processed unless they are
|
||||
* malformed</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The following names are known and have the following formats
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>{@code amount} decimal value to 8 dp (e.g. 0.12345678) <b>Note that the
|
||||
* exponent notation is not supported any more</b></li>
|
||||
* <li>{@code label} any URL encoded alphanumeric</li>
|
||||
* <li>{@code message} any URL encoded alphanumeric</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Andreas Schildbach (initial code)
|
||||
* @author Jim Burton (enhancements for MultiBit)
|
||||
* @author Gary Rowe (BIP21 support)
|
||||
* @see <a href="https://en.bitcoin.it/wiki/BIP_0021">BIP 0021</a>
|
||||
*/
|
||||
public class BitcoinURI {
|
||||
/**
|
||||
* Provides logging for this class
|
||||
*/
|
||||
private static final Logger log = LoggerFactory.getLogger(BitcoinURI.class);
|
||||
|
||||
// Not worth turning into an enum
|
||||
private static final String FIELD_MESSAGE = "message";
|
||||
private static final String FIELD_LABEL = "label";
|
||||
private static final String FIELD_AMOUNT = "amount";
|
||||
private static final String FIELD_ADDRESS = "address";
|
||||
|
||||
public static final String BITCOIN_SCHEME = "bitcoin";
|
||||
private static final String ENCODED_SPACE_CHARACTER = "%20";
|
||||
private static final String AMPERSAND_SEPARATOR = "&";
|
||||
private static final String QUESTION_MARK_SEPARATOR = "?";
|
||||
private static final String COLON_SEPARATOR = ":";
|
||||
|
||||
/**
|
||||
* Contains all the parameters in the order in which they were processed
|
||||
*/
|
||||
private final Map<String, Object> parameterMap = new LinkedHashMap<String, Object>();
|
||||
|
||||
/**
|
||||
* @param networkParameters
|
||||
* The BitCoinJ network parameters that determine which network
|
||||
* the URI is from
|
||||
* @param input
|
||||
* The raw URI data to be parsed (see class comments for accepted
|
||||
* formats)
|
||||
* @throws BitcoinURIParseException
|
||||
* If the input fails Bitcoin URI syntax and semantic checks
|
||||
*/
|
||||
public BitcoinURI(NetworkParameters networkParameters, String input) {
|
||||
// Basic validation
|
||||
if (networkParameters == null) {
|
||||
throw new IllegalArgumentException("NetworkParameters cannot be null");
|
||||
}
|
||||
if (input == null) {
|
||||
throw new IllegalArgumentException("Input cannot be null");
|
||||
}
|
||||
|
||||
log.debug("Attempting to parse '{}' for {}", input, networkParameters.port == 8333 ? "prodNet" : "testNet");
|
||||
|
||||
// URI validation
|
||||
if (!input.startsWith(BITCOIN_SCHEME)) {
|
||||
throw new BitcoinURIParseException("Bad scheme - expecting '" + BITCOIN_SCHEME + "'");
|
||||
}
|
||||
|
||||
// Attempt to form the URI (fail fast syntax checking to official standards)
|
||||
URI uri;
|
||||
try {
|
||||
uri = new URI(input);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new BitcoinURIParseException("Bad URI syntax", e);
|
||||
}
|
||||
|
||||
// URI is formed as bitcoin:<address>?<query parameters>
|
||||
|
||||
// Remove the bitcoin scheme
|
||||
// (Note: getSchemeSpecificPart() is not used as it unescapes the label and parse then fails.
|
||||
// For instance with : bitcoin:129mVqKUmJ9uwPxKJBnNdABbuaaNfho4Ha?amount=0.06&label=Tom%20%26%20Jerry
|
||||
// the & (%26) in Tom and Jerry gets interpreted as a separator and the label then gets parsed as 'Tom ' instead of 'Tom & Jerry')
|
||||
String schemeSpecificPart = "";
|
||||
if (uri.toString().startsWith(BITCOIN_SCHEME + COLON_SEPARATOR)) {
|
||||
schemeSpecificPart = uri.toString().substring(BITCOIN_SCHEME.length() + 1);
|
||||
}
|
||||
|
||||
// Split off the address from the rest of the query parameters
|
||||
String[] addressSplitTokens = schemeSpecificPart.split("\\?");
|
||||
if (addressSplitTokens.length == 0 || "".equals(addressSplitTokens[0])) {
|
||||
throw new BitcoinURIParseException("Missing address");
|
||||
}
|
||||
String addressToken = addressSplitTokens[0];
|
||||
|
||||
String[] nameValuePairTokens;
|
||||
if (addressSplitTokens.length == 1) {
|
||||
// only an address is specified - use an empty '<name>=<value>' token array
|
||||
nameValuePairTokens = new String[] {};
|
||||
} else {
|
||||
if (addressSplitTokens.length == 2) {
|
||||
// split into '<name>=<value>' tokens
|
||||
nameValuePairTokens = addressSplitTokens[1].split("&");
|
||||
} else {
|
||||
throw new BitcoinURIParseException("Too many question marks in URI '" + input + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to parse the rest of the URI parameters
|
||||
parseParameters(networkParameters, addressToken, nameValuePairTokens);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param networkParameters
|
||||
* The network parameters
|
||||
* @param nameValuePairTokens
|
||||
* The tokens representing the name value pairs (assumed to be
|
||||
* separated by '=' e.g. 'amount=0.2')
|
||||
*/
|
||||
private void parseParameters(NetworkParameters networkParameters, String addressToken, String[] nameValuePairTokens) {
|
||||
// Attempt to parse the addressToken as a Bitcoin address for this network
|
||||
try {
|
||||
Address address = new Address(networkParameters, 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
|
||||
for (int i = 0; i < nameValuePairTokens.length; i++) {
|
||||
|
||||
String[] tokens = nameValuePairTokens[i].split("=");
|
||||
if (tokens.length != 2 || "".equals(tokens[0])) {
|
||||
throw new BitcoinURIParseException("Malformed Bitcoin URI - cannot parse name value pair '" + nameValuePairTokens[i] + "'");
|
||||
}
|
||||
|
||||
String nameToken = tokens[0].toLowerCase();
|
||||
String valueToken = tokens[1];
|
||||
|
||||
// Parse the amount
|
||||
if (FIELD_AMOUNT.equals(nameToken)) {
|
||||
// Decode the amount (contains an optional decimal component to 8dp)
|
||||
try {
|
||||
BigInteger amount = Utils.toNanoCoins(valueToken);
|
||||
putWithValidation(FIELD_AMOUNT, amount);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new OptionalFieldValidationException("'" + valueToken + "' value is not a valid amount", e);
|
||||
}
|
||||
} else {
|
||||
if (nameToken.startsWith("req-")) {
|
||||
// A required parameter that we do not know about
|
||||
throw new RequiredFieldValidationException("'" + nameToken + "' is required but not known, this URI is not valid");
|
||||
} else {
|
||||
// Known fields and unknown parameters that are optional
|
||||
try {
|
||||
putWithValidation(nameToken, URLDecoder.decode(valueToken, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// should not happen as UTF-8 is valid encoding
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note to the future : when you want to implement 'req-expires' have a look at commit 410a53791841 which had it in
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Put the value against the key in the map checking for duplication.
|
||||
* This avoids address field overwrite etc.
|
||||
* </p>
|
||||
*
|
||||
* @param key
|
||||
* The key for the map
|
||||
* @param value
|
||||
* The value to store
|
||||
*/
|
||||
private void putWithValidation(String key, Object value) {
|
||||
if (parameterMap.containsKey(key)) {
|
||||
throw new BitcoinURIParseException("'" + key + "' is duplicated, URI is invalid");
|
||||
} else {
|
||||
parameterMap.put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Bitcoin Address from the URI
|
||||
*/
|
||||
public Address getAddress() {
|
||||
return (Address) parameterMap.get(FIELD_ADDRESS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The amount name encoded using a pure integer value based at
|
||||
* 10,000,000 units is 1 BTC. May be null if no amount is specified
|
||||
*/
|
||||
public BigInteger getAmount() {
|
||||
return (BigInteger) parameterMap.get(FIELD_AMOUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The label from the URI.
|
||||
*/
|
||||
public String getLabel() {
|
||||
return (String) parameterMap.get(FIELD_LABEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The message from the URI.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return (String) parameterMap.get(FIELD_MESSAGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name The name of the parameter
|
||||
* @return The parameter value, or null if not present
|
||||
*/
|
||||
public Object getParameterByName(String name) {
|
||||
return parameterMap.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder("BitcoinURI[");
|
||||
boolean first = true;
|
||||
for (Map.Entry<String, Object> entry : parameterMap.entrySet()) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
builder.append(",");
|
||||
}
|
||||
builder.append("'").append(entry.getKey()).append("'=").append("'").append(entry.getValue().toString()).append("'");
|
||||
}
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Simple Bitcoin URI builder using known good fields
|
||||
* </p>
|
||||
*
|
||||
* @param address
|
||||
* The Bitcoin address
|
||||
* @param amount
|
||||
* The amount in nanocoins (decimal)
|
||||
* @param label
|
||||
* A label
|
||||
* @param message
|
||||
* A message
|
||||
* @return A String containing the Bitcoin URI
|
||||
*/
|
||||
public static String convertToBitcoinURI(Address address, BigInteger amount, String label, String message) {
|
||||
if (address == null) {
|
||||
throw new IllegalArgumentException("Missing address");
|
||||
}
|
||||
|
||||
if (amount != null && amount.compareTo(BigInteger.ZERO) < 0) {
|
||||
throw new IllegalArgumentException("Amount must be positive");
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(BITCOIN_SCHEME).append(COLON_SEPARATOR).append(address.toString());
|
||||
|
||||
boolean questionMarkHasBeenOutput = false;
|
||||
|
||||
if (amount != null) {
|
||||
builder.append(QUESTION_MARK_SEPARATOR).append(FIELD_AMOUNT).append("=");
|
||||
builder.append(Utils.bitcoinValueToPlainString(amount));
|
||||
questionMarkHasBeenOutput = true;
|
||||
}
|
||||
|
||||
if (label != null && !"".equals(label)) {
|
||||
if (questionMarkHasBeenOutput) {
|
||||
builder.append(AMPERSAND_SEPARATOR);
|
||||
} else {
|
||||
builder.append(QUESTION_MARK_SEPARATOR);
|
||||
questionMarkHasBeenOutput = true;
|
||||
}
|
||||
builder.append(FIELD_LABEL).append("=").append(encodeURLString(label));
|
||||
}
|
||||
|
||||
if (message != null && !"".equals(message)) {
|
||||
if (questionMarkHasBeenOutput) {
|
||||
builder.append(AMPERSAND_SEPARATOR);
|
||||
} else {
|
||||
builder.append(QUESTION_MARK_SEPARATOR);
|
||||
questionMarkHasBeenOutput = true;
|
||||
}
|
||||
builder.append(FIELD_MESSAGE).append("=").append(encodeURLString(message));
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Encode a string using URL encoding
|
||||
* </p>
|
||||
*
|
||||
* @param stringToEncode
|
||||
* The string to URL encode
|
||||
*/
|
||||
static String encodeURLString(String stringToEncode) {
|
||||
try {
|
||||
return java.net.URLEncoder.encode(stringToEncode, "UTF-8").replace("+", ENCODED_SPACE_CHARACTER);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// should not happen - UTF-8 is a valid encoding
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
24
src/com/google/bitcoin/uri/BitcoinURIParseException.java
Normal file
24
src/com/google/bitcoin/uri/BitcoinURIParseException.java
Normal file
@ -0,0 +1,24 @@
|
||||
package com.google.bitcoin.uri;
|
||||
|
||||
/**
|
||||
* <p>Exception to provide the following to {@link BitcoinURI}:</p>
|
||||
* <ul>
|
||||
* <li>Provision of parsing error messages</li>
|
||||
* </ul>
|
||||
* <p>This base exception acts as a general failure mode not attributable to a specific cause (other than
|
||||
* that reported in the exception message). Since this is in English, it may not be worth reporting directly
|
||||
* to the user other than as part of a "general failure to parse" response.</p>
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
*/
|
||||
public class BitcoinURIParseException extends RuntimeException {
|
||||
|
||||
public BitcoinURIParseException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public BitcoinURIParseException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.google.bitcoin.uri;
|
||||
|
||||
/**
|
||||
* <p>Exception to provide the following to {@link org.multibit.qrcode.BitcoinURI}:</p>
|
||||
* <ul>
|
||||
* <li>Provision of parsing error messages</li>
|
||||
* </ul>
|
||||
* <p>This exception occurs when an optional field is detected (under the Bitcoin URI scheme) and fails
|
||||
* to pass the associated test (such as {@code amount} not being a valid number).</p>
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
*/
|
||||
public class OptionalFieldValidationException extends BitcoinURIParseException {
|
||||
|
||||
public OptionalFieldValidationException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public OptionalFieldValidationException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package com.google.bitcoin.uri;
|
||||
|
||||
/**
|
||||
* <p>Exception to provide the following to {@link BitcoinURI}:</p>
|
||||
* <ul>
|
||||
* <li>Provision of parsing error messages</li>
|
||||
* </ul>
|
||||
* <p>This exception occurs when a required field is detected (under the BIP21 rules) and fails
|
||||
* to pass the associated test (such as {@code req-expires} being out of date), or the required field is unknown
|
||||
* to this version of the client in which case it should fail for security reasons.</p>
|
||||
*
|
||||
* @since 0.3.0
|
||||
*
|
||||
*/
|
||||
public class RequiredFieldValidationException extends BitcoinURIParseException {
|
||||
|
||||
public RequiredFieldValidationException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public RequiredFieldValidationException(String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
}
|
||||
}
|
@ -16,10 +16,15 @@
|
||||
|
||||
package com.google.bitcoin.core;
|
||||
|
||||
import static com.google.bitcoin.core.Utils.CENT;
|
||||
import static com.google.bitcoin.core.Utils.COIN;
|
||||
import static com.google.bitcoin.core.Utils.bitcoinValueToFriendlyString;
|
||||
import static com.google.bitcoin.core.Utils.bitcoinValueToPlainString;
|
||||
import static com.google.bitcoin.core.Utils.toNanoCoins;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.fail;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import static com.google.bitcoin.core.Utils.*;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
@ -34,7 +39,7 @@ public class UtilsTest {
|
||||
assertEquals(COIN.add(Utils.CENT), toNanoCoins("1.01"));
|
||||
try {
|
||||
toNanoCoins("2E-20");
|
||||
fail("should not have accepted fractional nanocoins");
|
||||
org.junit.Assert.fail("should not have accepted fractional nanocoins");
|
||||
} catch (ArithmeticException e) {
|
||||
}
|
||||
|
||||
@ -53,6 +58,44 @@ public class UtilsTest {
|
||||
assertEquals("-1.23", bitcoinValueToFriendlyString(toNanoCoins(1, 23).negate()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the bitcoinValueToPlainString amount formatter
|
||||
*/
|
||||
@Test
|
||||
public void testBitcoinValueToPlainString() {
|
||||
// null argument check
|
||||
try {
|
||||
bitcoinValueToPlainString(null);
|
||||
org.junit.Assert.fail("Expecting IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(e.getMessage().contains("Value cannot be null"));
|
||||
}
|
||||
|
||||
assertEquals("0.0015", bitcoinValueToPlainString(BigInteger.valueOf(150000)));
|
||||
assertEquals("1.23", bitcoinValueToPlainString(toNanoCoins("1.23")));
|
||||
assertEquals("-1.23", bitcoinValueToPlainString(toNanoCoins("-1.23")));
|
||||
|
||||
assertEquals("0.1", bitcoinValueToPlainString(toNanoCoins("0.1")));
|
||||
assertEquals("1.1", bitcoinValueToPlainString(toNanoCoins("1.1")));
|
||||
assertEquals("21.12", bitcoinValueToPlainString(toNanoCoins("21.12")));
|
||||
assertEquals("321.123", bitcoinValueToPlainString(toNanoCoins("321.123")));
|
||||
assertEquals("4321.1234", bitcoinValueToPlainString(toNanoCoins("4321.1234")));
|
||||
assertEquals("54321.12345", bitcoinValueToPlainString(toNanoCoins("54321.12345")));
|
||||
assertEquals("654321.123456", bitcoinValueToPlainString(toNanoCoins("654321.123456")));
|
||||
assertEquals("7654321.1234567", bitcoinValueToPlainString(toNanoCoins("7654321.1234567")));
|
||||
assertEquals("87654321.12345678", bitcoinValueToPlainString(toNanoCoins("87654321.12345678")));
|
||||
|
||||
// check there are no trailing zeros
|
||||
assertEquals("1", bitcoinValueToPlainString(toNanoCoins("1.0")));
|
||||
assertEquals("2", bitcoinValueToPlainString(toNanoCoins("2.00")));
|
||||
assertEquals("3", bitcoinValueToPlainString(toNanoCoins("3.000")));
|
||||
assertEquals("4", bitcoinValueToPlainString(toNanoCoins("4.0000")));
|
||||
assertEquals("5", bitcoinValueToPlainString(toNanoCoins("5.00000")));
|
||||
assertEquals("6", bitcoinValueToPlainString(toNanoCoins("6.000000")));
|
||||
assertEquals("7", bitcoinValueToPlainString(toNanoCoins("7.0000000")));
|
||||
assertEquals("8", bitcoinValueToPlainString(toNanoCoins("8.00000000")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReverseBytes() {
|
||||
Assert.assertArrayEquals(new byte[] {1,2,3,4,5}, Utils.reverseBytes(new byte[] {5,4,3,2,1}));
|
||||
|
448
tests/com/google/bitcoin/uri/BitcoinURITest.java
Normal file
448
tests/com/google/bitcoin/uri/BitcoinURITest.java
Normal file
@ -0,0 +1,448 @@
|
||||
/*
|
||||
* Copyright 2012 the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.google.bitcoin.uri;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.bitcoin.core.Address;
|
||||
import com.google.bitcoin.core.AddressFormatException;
|
||||
import com.google.bitcoin.core.NetworkParameters;
|
||||
import com.google.bitcoin.core.Utils;
|
||||
|
||||
public class BitcoinURITest {
|
||||
|
||||
private BitcoinURI testObject = null;
|
||||
|
||||
private static final String PRODNET_GOOD_ADDRESS = "1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH";
|
||||
|
||||
/**
|
||||
* Tests conversion to Bitcoin URI
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
* @throws AddressFormatException
|
||||
*/
|
||||
@Test
|
||||
public void testConvertToBitcoinURI() throws BitcoinURIParseException, AddressFormatException {
|
||||
Address goodAddress = new Address(NetworkParameters.prodNet(), PRODNET_GOOD_ADDRESS);
|
||||
|
||||
// simple example
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?amount=12.34&label=Hello&message=AMessage", BitcoinURI.convertToBitcoinURI(goodAddress, Utils.toNanoCoins("12.34"), "Hello", "AMessage"));
|
||||
|
||||
// example with spaces, ampersand and plus
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?amount=12.34&label=Hello%20World&message=Mess%20%26%20age%20%2B%20hope", BitcoinURI.convertToBitcoinURI(goodAddress, Utils.toNanoCoins("12.34"), "Hello World", "Mess & age + hope"));
|
||||
|
||||
// address null
|
||||
try {
|
||||
BitcoinURI.convertToBitcoinURI(null, Utils.toNanoCoins("0.1"), "hope", "glory");
|
||||
fail("Expecting IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(e.getMessage().contains("address"));
|
||||
}
|
||||
|
||||
// amount negative
|
||||
try {
|
||||
BitcoinURI.convertToBitcoinURI(goodAddress, Utils.toNanoCoins("-0.1"), "hope", "glory");
|
||||
fail("Expecting IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(e.getMessage().contains("Amount must be positive"));
|
||||
}
|
||||
|
||||
// no amount, label present, message present
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?label=Hello&message=glory", BitcoinURI.convertToBitcoinURI(goodAddress, null, "Hello", "glory"));
|
||||
|
||||
// amount present, no label, message present
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?amount=0.1&message=glory", BitcoinURI.convertToBitcoinURI(goodAddress, Utils.toNanoCoins("0.1"), null, "glory"));
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?amount=0.1&message=glory", BitcoinURI.convertToBitcoinURI(goodAddress, Utils.toNanoCoins("0.1"), "", "glory"));
|
||||
|
||||
// amount present, label present, no message
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?amount=12.34&label=Hello", BitcoinURI.convertToBitcoinURI(goodAddress,Utils.toNanoCoins("12.34"), "Hello", null));
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?amount=12.34&label=Hello", BitcoinURI.convertToBitcoinURI(goodAddress, Utils.toNanoCoins("12.34"), "Hello", ""));
|
||||
|
||||
// amount present, no label, no message
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?amount=1000", BitcoinURI.convertToBitcoinURI(goodAddress, Utils.toNanoCoins("1000"), null, null));
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?amount=1000", BitcoinURI.convertToBitcoinURI(goodAddress, Utils.toNanoCoins("1000"), "", ""));
|
||||
|
||||
// no amount, label present, no message
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?label=Hello", BitcoinURI.convertToBitcoinURI(goodAddress, null, "Hello", null));
|
||||
|
||||
// no amount, no label, message present
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?message=Agatha", BitcoinURI.convertToBitcoinURI(goodAddress, null, null, "Agatha"));
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS + "?message=Agatha", BitcoinURI.convertToBitcoinURI(goodAddress, null, "", "Agatha"));
|
||||
|
||||
// no amount, no label, no message
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS, BitcoinURI.convertToBitcoinURI(goodAddress, null, null, null));
|
||||
assertEquals("bitcoin:" + PRODNET_GOOD_ADDRESS, BitcoinURI.convertToBitcoinURI(goodAddress, null, "", ""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the simplest well-formed URI
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testGood_Simple() throws BitcoinURIParseException {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS);
|
||||
assertNotNull(testObject);
|
||||
assertNull("Unexpected amount", testObject.getAmount());
|
||||
assertNull("Unexpected label", testObject.getLabel());
|
||||
assertEquals("Unexpected label", 20, testObject.getAddress().getHash160().length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test missing constructor parameters
|
||||
*/
|
||||
@Test
|
||||
public void testBad_Constructor() {
|
||||
try {
|
||||
testObject = new BitcoinURI(null, "blimpcoin:" + PRODNET_GOOD_ADDRESS);
|
||||
fail("Expecting IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(e.getMessage().contains("NetworkParameters"));
|
||||
}
|
||||
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), null);
|
||||
fail("Expecting IllegalArgumentException");
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(e.getMessage().contains("Input"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a broken URI (bad scheme)
|
||||
*/
|
||||
@Test
|
||||
public void testBad_Scheme() {
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), "blimpcoin:" + PRODNET_GOOD_ADDRESS);
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("Bad scheme"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a broken URI (bad syntax)
|
||||
*/
|
||||
@Test
|
||||
public void testBad_BadSyntax() {
|
||||
// Various illegal characters
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + "|" + PRODNET_GOOD_ADDRESS);
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("Bad URI syntax"));
|
||||
}
|
||||
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS + "\\");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("Bad URI syntax"));
|
||||
}
|
||||
|
||||
// Separator without field
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("Bad URI syntax"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a broken URI (missing address)
|
||||
*/
|
||||
@Test
|
||||
public void testBad_Address() {
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME);
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("Missing address"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a broken URI (bad address type)
|
||||
*/
|
||||
@Test
|
||||
public void testBad_IncorrectAddressType() {
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.testNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS);
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("Bad address"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a simple amount
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testGood_Amount() throws BitcoinURIParseException {
|
||||
// Test the decimal parsing
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?amount=9876543210.12345678");
|
||||
assertEquals("987654321012345678", testObject.getAmount().toString());
|
||||
|
||||
// Test the decimal parsing
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?amount=.12345678");
|
||||
assertEquals("12345678", testObject.getAmount().toString());
|
||||
|
||||
// Test the integer parsing
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?amount=9876543210");
|
||||
assertEquals("987654321000000000", testObject.getAmount().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a simple label
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testGood_Label() throws BitcoinURIParseException {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?label=Hello%20World");
|
||||
assertEquals("Hello World", testObject.getLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a simple label with an embedded ampersand and plus
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
@Test
|
||||
public void testGood_LabelWithAmpersandAndPlus() throws BitcoinURIParseException, UnsupportedEncodingException {
|
||||
String testString = "Hello Earth & Mars + Venus";
|
||||
String encodedLabel = BitcoinURI.encodeURLString(testString);
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS + "?label="
|
||||
+ encodedLabel);
|
||||
assertEquals(testString, testObject.getLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a Russian label (Unicode test)
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
@Test
|
||||
public void testGood_LabelWithRussian() throws BitcoinURIParseException, UnsupportedEncodingException {
|
||||
// Moscow in Russian in Cyrillic
|
||||
String moscowString = "\u041c\u043e\u0441\u043a\u0432\u0430";
|
||||
String encodedLabel = BitcoinURI.encodeURLString(moscowString);
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS + "?label="
|
||||
+ encodedLabel);
|
||||
assertEquals(moscowString, testObject.getLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a simple message
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testGood_Message() throws BitcoinURIParseException {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?message=Hello%20World");
|
||||
assertEquals("Hello World", testObject.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles various well-formed combinations
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testGood_Combinations() throws BitcoinURIParseException {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?amount=9876543210&label=Hello%20World&message=Be%20well");
|
||||
assertEquals(
|
||||
"BitcoinURI['address'='1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH','amount'='987654321000000000','label'='Hello World','message'='Be well']",
|
||||
testObject.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a badly formatted amount field
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testBad_Amount() throws BitcoinURIParseException {
|
||||
// Missing
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?amount=");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("amount"));
|
||||
}
|
||||
|
||||
// Non-decimal (BIP 21)
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?amount=12X4");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("amount"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a badly formatted label field
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testBad_Label() throws BitcoinURIParseException {
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?label=");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("label"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a badly formatted message field
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testBad_Message() throws BitcoinURIParseException {
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?message=");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("message"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles duplicated fields (sneaky address overwrite attack)
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testBad_Duplicated() throws BitcoinURIParseException {
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?address=aardvark");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("address"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles case when there are too many equals
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testBad_TooManyEquals() throws BitcoinURIParseException {
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?label=aardvark=zebra");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("cannot parse name value pair"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles case when there are too many question marks
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testBad_TooManyQuestionMarks() throws BitcoinURIParseException {
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?label=aardvark?message=zebra");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("Too many question marks"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles unknown fields (required and not required)
|
||||
*
|
||||
* @throws BitcoinURIParseException
|
||||
* If something goes wrong
|
||||
*/
|
||||
@Test
|
||||
public void testUnknown() throws BitcoinURIParseException {
|
||||
// Unknown not required field
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?aardvark=true");
|
||||
assertEquals("BitcoinURI['address'='1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH','aardvark'='true']", testObject.toString());
|
||||
|
||||
assertEquals("true", (String) testObject.getParameterByName("aardvark"));
|
||||
|
||||
// Unknown not required field (isolated)
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?aardvark");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("cannot parse name value pair"));
|
||||
}
|
||||
|
||||
// Unknown and required field
|
||||
try {
|
||||
testObject = new BitcoinURI(NetworkParameters.prodNet(), BitcoinURI.BITCOIN_SCHEME + ":" + PRODNET_GOOD_ADDRESS
|
||||
+ "?req-aardvark=true");
|
||||
fail("Expecting BitcoinURIParseException");
|
||||
} catch (BitcoinURIParseException e) {
|
||||
assertTrue(e.getMessage().contains("req-aardvark"));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user