3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-31 15:22:16 +00:00

Eliminate support for parsing negative or too large amounts in Utils.toNanoCoins. Add tests for out of range URI amounts. Resolves issue 407.

This commit is contained in:
Mike Hearn 2013-07-11 17:33:31 +02:00
parent d3eab06dba
commit 719a786db1
3 changed files with 52 additions and 24 deletions

View File

@ -29,7 +29,6 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;
import static com.google.common.base.Preconditions.checkArgument;
@ -75,6 +74,9 @@ public class Utils {
*/
public static BigInteger toNanoCoins(int coins, int cents) {
checkArgument(cents < 100);
checkArgument(cents >= 0);
checkArgument(coins >= 0);
checkArgument(coins < NetworkParameters.MAX_MONEY.divide(Utils.COIN).longValue());
BigInteger bi = BigInteger.valueOf(coins).multiply(COIN);
bi = bi.add(BigInteger.valueOf(cents).multiply(CENT));
return bi;
@ -106,10 +108,15 @@ public class Utils {
* This takes string in a format understood by {@link BigDecimal#BigDecimal(String)},
* for example "0", "1", "0.10", "1.23E3", "1234.5E-5".
*
* @throws ArithmeticException if you try to specify fractional nanocoins
* @throws ArithmeticException if you try to specify fractional nanocoins, or nanocoins out of range.
*/
public static BigInteger toNanoCoins(String coins) {
return new BigDecimal(coins).movePointRight(8).toBigIntegerExact();
BigInteger bigint = new BigDecimal(coins).movePointRight(8).toBigIntegerExact();
if (bigint.compareTo(BigInteger.ZERO) < 0)
throw new ArithmeticException("Negative coins specified");
if (bigint.compareTo(NetworkParameters.MAX_MONEY) > 0)
throw new ArithmeticException("Amount larger than the total quantity of Bitcoins possible specified.");
return bigint;
}
public static void uint32ToByteArrayBE(long val, byte[] out, int offset) {

View File

@ -23,6 +23,7 @@ import java.math.BigInteger;
import static com.google.bitcoin.core.Utils.*;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
import static org.junit.Assert.assertTrue;
public class UtilsTest {
@ -42,10 +43,18 @@ public class UtilsTest {
// int version
assertEquals(CENT, toNanoCoins(0, 1));
// TODO: should this really pass?
assertEquals(COIN.subtract(CENT), toNanoCoins(1, -1));
assertEquals(COIN.negate(), toNanoCoins(-1, 0));
assertEquals(COIN.negate(), toNanoCoins("-1"));
try {
toNanoCoins(1, -1);
fail();
} catch (IllegalArgumentException e) {}
try {
toNanoCoins(-1, 0);
fail();
} catch (IllegalArgumentException e) {}
try {
toNanoCoins("-1");
fail();
} catch (ArithmeticException e) {}
}
@Test
@ -71,8 +80,7 @@ public class UtilsTest {
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")));
@ -81,7 +89,10 @@ public class UtilsTest {
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")));
try {
assertEquals("87654321.12345678", bitcoinValueToPlainString(toNanoCoins("87654321.12345678")));
Assert.fail(); // More than MAX_MONEY
} catch (Exception e) {}
// check there are no trailing zeros
assertEquals("1", bitcoinValueToPlainString(toNanoCoins("1.0")));

View File

@ -44,14 +44,6 @@ public class BitcoinURITest {
// example with spaces, ampersand and plus
assertEquals("bitcoin:" + MAINNET_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"));
// 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:" + MAINNET_GOOD_ADDRESS + "?label=Hello&message=glory", BitcoinURI.convertToBitcoinURI(goodAddress, null, "Hello", "glory"));
@ -164,8 +156,8 @@ public class BitcoinURITest {
public void testGood_Amount() throws BitcoinURIParseException {
// Test the decimal parsing
testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
+ "?amount=9876543210.12345678");
assertEquals("987654321012345678", testObject.getAmount().toString());
+ "?amount=6543210.12345678");
assertEquals("654321012345678", testObject.getAmount().toString());
// Test the decimal parsing
testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
@ -174,8 +166,8 @@ public class BitcoinURITest {
// Test the integer parsing
testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
+ "?amount=9876543210");
assertEquals("987654321000000000", testObject.getAmount().toString());
+ "?amount=6543210");
assertEquals("654321000000000", testObject.getAmount().toString());
}
/**
@ -246,9 +238,9 @@ public class BitcoinURITest {
@Test
public void testGood_Combinations() throws BitcoinURIParseException {
testObject = new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
+ "?amount=9876543210&label=Hello%20World&message=Be%20well");
+ "?amount=6543210&label=Hello%20World&message=Be%20well");
assertEquals(
"BitcoinURI['address'='1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH','amount'='987654321000000000','label'='Hello World','message'='Be well']",
"BitcoinURI['address'='1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH','amount'='654321000000000','label'='Hello World','message'='Be well']",
testObject.toString());
}
@ -406,4 +398,22 @@ public class BitcoinURITest {
assertEquals("1KzTSfqjF2iKCduwz59nv2uqh1W2JsTxZH", uri.getAddress().toString());
assertEquals(Utils.toNanoCoins(0, 1), uri.getAmount());
}
@Test(expected = BitcoinURIParseException.class)
public void testBad_AmountTooPrecise() throws BitcoinURIParseException {
new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
+ "?amount=0.123456789");
}
@Test(expected = BitcoinURIParseException.class)
public void testBad_NegativeAmount() throws BitcoinURIParseException {
new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
+ "?amount=-1");
}
@Test(expected = BitcoinURIParseException.class)
public void testBad_TooLargeAmount() throws BitcoinURIParseException {
new BitcoinURI(MainNetParams.get(), BitcoinURI.BITCOIN_SCHEME + ":" + MAINNET_GOOD_ADDRESS
+ "?amount=100000000");
}
}