From a7c8579b139c75e20472f5aea36aa7ed6cb17b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sa=C5=82aban?= Date: Thu, 4 Apr 2019 13:06:04 +0200 Subject: [PATCH] Check type of amounts passed to conversion, avoid MemoryError when a string is being concatenated 10^12 times. Close#48 --- monero/numbers.py | 3 +++ tests/test_numbers.py | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/monero/numbers.py b/monero/numbers.py index c2c9973..a5ddd18 100644 --- a/monero/numbers.py +++ b/monero/numbers.py @@ -13,6 +13,9 @@ else: # pragma: no cover def to_atomic(amount): """Convert Monero decimal to atomic integer of piconero.""" + if not isinstance(amount, (Decimal, float) + _integer_types): + raise ValueError("Amount '{}' doesn't have numeric type. Only Decimal, int, long and " + "float (not recommended) are accepted as amounts.") return int(amount * 10**12) def from_atomic(amount): diff --git a/tests/test_numbers.py b/tests/test_numbers.py index df96952..0640a5f 100644 --- a/tests/test_numbers.py +++ b/tests/test_numbers.py @@ -1,4 +1,5 @@ from decimal import Decimal +import sys import unittest from monero.numbers import to_atomic, from_atomic, as_monero, PaymentID @@ -12,6 +13,14 @@ class NumbersTestCase(unittest.TestCase): self.assertEqual(to_atomic(Decimal('0.000000000001')), 1) self.assertEqual(from_atomic(1), Decimal('0.000000000001')) + def test_numeric_types(self): + "Only check if conversion of given type succeeds or fails." + self.assertTrue(to_atomic(1)) + self.assertTrue(to_atomic(1.0)) + if hasattr(sys, 'maxint'): # Python 2.x + self.assertTrue(to_atomic(sys.maxint + 1)) + self.assertRaises(ValueError, to_atomic, '1') + def test_rounding(self): self.assertEqual(to_atomic(Decimal('1.0000000000004')), 1000000000000) self.assertEqual(as_monero(Decimal('1.0000000000014')), Decimal('1.000000000001'))