clean up amount logic, fix 2^53 check

This commit is contained in:
Christian Grothoff 2020-01-19 19:39:14 +01:00
parent 1f5c814b73
commit 5da9cfc51c
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
2 changed files with 56 additions and 44 deletions

View File

@ -66,8 +66,8 @@ BANK_URL=http://localhost:${BANK_PORT}/
AUDITOR_URL=http://localhost:8083/ AUDITOR_URL=http://localhost:8083/
# patch configuration # patch configuration
taler-config -c $CONF -s EXCHANGE -o MASTER_PUBLIC_KEY -V $MASTER_PUB taler-config -c $CONF -s exchange -o MASTER_PUBLIC_KEY -V $MASTER_PUB
taler-config -c $CONF -s EXCHANGE-DEFAULT -o MASTER_KEY -V $MASTER_PUB taler-config -c $CONF -s merchant-exchange-default -o MASTER_KEY -V $MASTER_PUB
taler-config -c $CONF -s exchangedb-postgres -o CONFIG -V postgres:///$TARGET_DB taler-config -c $CONF -s exchangedb-postgres -o CONFIG -V postgres:///$TARGET_DB
taler-config -c $CONF -s auditordb-postgres -o CONFIG -V postgres:///$TARGET_DB taler-config -c $CONF -s auditordb-postgres -o CONFIG -V postgres:///$TARGET_DB
taler-config -c $CONF -s merchantdb-postgres -o CONFIG -V postgres:///$TARGET_DB taler-config -c $CONF -s merchantdb-postgres -o CONFIG -V postgres:///$TARGET_DB

View File

@ -61,13 +61,11 @@ int
TALER_string_to_amount (const char *str, TALER_string_to_amount (const char *str,
struct TALER_Amount *denom) struct TALER_Amount *denom)
{ {
size_t i;
int n; int n;
uint32_t b; uint32_t b;
const char *colon; const char *colon;
const char *value; const char *value;
invalidate (denom);
/* skip leading whitespace */ /* skip leading whitespace */
while (isspace ( (unsigned char) str[0])) while (isspace ( (unsigned char) str[0]))
str++; str++;
@ -75,8 +73,10 @@ TALER_string_to_amount (const char *str,
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Null before currency\n"); "Null before currency\n");
invalidate (denom);
return GNUNET_SYSERR; return GNUNET_SYSERR;
} }
/* parse currency */ /* parse currency */
colon = strchr (str, (int) ':'); colon = strchr (str, (int) ':');
if ( (NULL == colon) || if ( (NULL == colon) ||
@ -85,91 +85,103 @@ TALER_string_to_amount (const char *str,
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Invalid currency specified before colon: `%s'\n", "Invalid currency specified before colon: `%s'\n",
str); str);
goto fail; invalidate (denom);
return GNUNET_SYSERR;
} }
GNUNET_assert (TALER_CURRENCY_LEN > (colon - str));
memcpy (denom->currency, memcpy (denom->currency,
str, str,
colon - str); colon - str);
/* 0-terminate *and* normalize buffer by setting everything to '\0' */
memset (&denom->currency [colon - str],
0,
TALER_CURRENCY_LEN - (colon - str));
/* skip colon */ /* skip colon */
value = colon + 1; value = colon + 1;
if ('\0' == value[0]) if ('\0' == value[0])
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Null before value\n"); "Actual value missing in amount `%s'\n",
goto fail; str);
invalidate (denom);
return GNUNET_SYSERR;
} }
denom->value = 0;
denom->fraction = 0;
/* parse value */ /* parse value */
i = 0; while ('.' != *value)
while ('.' != value[i])
{ {
if ('\0' == value[i]) if ('\0' == *value)
{ {
/* we are done */
return GNUNET_OK; return GNUNET_OK;
} }
if ( (value[i] < '0') || (value[i] > '9') ) if ( (*value < '0') ||
(*value > '9') )
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Invalid character `%c'\n", "Invalid character `%c' in amount `%s'\n",
value[i]); (int) *value,
goto fail; str);
invalidate (denom);
return GNUNET_SYSERR;
} }
n = value[i] - '0'; n = *value - '0';
if (denom->value * 10 + n < denom->value) if ( (denom->value * 10 + n < denom->value) ||
(denom->value > MAX_AMOUNT_VALUE) )
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Value too large\n"); "Value specified in amount `%s' is too large\n",
goto fail; str);
invalidate (denom);
return GNUNET_SYSERR;
} }
denom->value = (denom->value * 10) + n; denom->value = (denom->value * 10) + n;
i++; value++;
} }
/* skip the dot */ /* skip the dot */
i++; value++;
/* parse fraction */ /* parse fraction */
if ('\0' == value[i]) if ('\0' == *value)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Null after dot\n"); "Amount `%s' ends abruptly after `.'\n",
goto fail; str);
invalidate (denom);
return GNUNET_SYSERR;
} }
b = TALER_AMOUNT_FRAC_BASE / 10; b = TALER_AMOUNT_FRAC_BASE / 10;
while ('\0' != value[i]) while ('\0' != *value)
{ {
if (0 == b) if (0 == b)
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Fractional value too small (only %u digits supported)\n", "Fractional value too small (only %u digits supported) in amount `%s'\n",
(unsigned int) TALER_AMOUNT_FRAC_LEN); (unsigned int) TALER_AMOUNT_FRAC_LEN,
goto fail; str);
invalidate (denom);
return GNUNET_SYSERR;
} }
if ( (value[i] < '0') || (value[i] > '9') ) if ( (*value < '0') ||
(*value > '9') )
{ {
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Error after dot\n"); "Error after dot\n");
goto fail; invalidate (denom);
return GNUNET_SYSERR;
} }
n = value[i] - '0'; n = *value - '0';
denom->fraction += n * b; denom->fraction += n * b;
b /= 10; b /= 10;
i++; value++;
}
if (denom->value > MAX_AMOUNT_VALUE)
{
/* too large to be legal */
invalidate (denom);
return GNUNET_SYSERR;
} }
return GNUNET_OK; return GNUNET_OK;
fail:
/* set currency to 'invalid' to prevent accidental use */
memset (denom->currency,
0,
TALER_CURRENCY_LEN);
return GNUNET_SYSERR;
} }