commit 2441001c9925987f4f0f953ef0be3fa987b9970a
parent 1d4025d708b7ebffaf1bfa6f271b8d75c71e1160
Author: Christian Grothoff <christian@grothoff.org>
Date: Sun, 22 Jun 2025 00:02:14 +0200
allow prog_name to be NULL/missing for AML programs with checks of type INFO (#9874)
Diffstat:
11 files changed, 252 insertions(+), 135 deletions(-)
diff --git a/src/exchange/taler-exchange-httpd_config.h b/src/exchange/taler-exchange-httpd_config.h
@@ -41,7 +41,7 @@
*
* Returned via both /config and /keys endpoints.
*/
-#define EXCHANGE_PROTOCOL_VERSION "29:0:7"
+#define EXCHANGE_PROTOCOL_VERSION "30:0:8"
/**
diff --git a/src/exchange/taler-exchange-httpd_kyc-info.c b/src/exchange/taler-exchange-httpd_kyc-info.c
@@ -365,13 +365,10 @@ resume_with_reply (struct KycPoller *kyp,
json_array_foreach ((json_t *) measures, i, mi)
{
const char *check_name;
- const char *prog_name;
const json_t *context = NULL;
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_string ("check_name",
&check_name),
- GNUNET_JSON_spec_string ("prog_name",
- &prog_name),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_object_const ("context",
&context),
@@ -395,9 +392,8 @@ resume_with_reply (struct KycPoller *kyp,
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Found required check `%s' with program `%s'\n",
- check_name,
- prog_name);
+ "Found required check `%s'\n",
+ check_name);
if (NULL != context)
{
json_dumpf (context,
@@ -443,7 +439,6 @@ resume_with_reply (struct KycPoller *kyp,
}
kri = TALER_KYCLOGIC_measure_to_requirement (
check_name,
- prog_name,
context,
&kyp->access_token,
i,
@@ -576,8 +571,8 @@ current_rules_cb (
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_array_steal (
"voluntary_measures",
- TALER_KYCLOGIC_voluntary_measures
- (kyp->lrs))
+ TALER_KYCLOGIC_voluntary_measures (
+ kyp->lrs))
)));
return;
}
diff --git a/src/exchangedb/exchangedb_aml.c b/src/exchangedb/exchangedb_aml.c
@@ -477,7 +477,18 @@ run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru,
/* Free previous one, in case we are iterating... */
GNUNET_free (ru->aml_program_name);
- ru->aml_program_name = GNUNET_strdup (m->prog_name);
+ if (NULL != m->prog_name)
+ {
+ ru->aml_program_name = GNUNET_strdup (m->prog_name);
+ }
+ else
+ {
+ /* How do we get to run a measure if the check type
+ is INFO (which is the only case where prog_name
+ is allowed to be NULL?) */
+ GNUNET_break (0);
+ ru->aml_program_name = NULL;
+ }
qs = ru->plugin->set_aml_lock (
ru->plugin->cls,
&ru->account,
@@ -516,7 +527,7 @@ run_measure (struct TALER_EXCHANGEDB_RuleUpdater *ru,
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Check is of type 'skip', running AML program %s.\n",
+ "Check is of type 'SKIP', running AML program %s.\n",
m->prog_name);
GNUNET_assert (NULL == ru->t);
ru->amlh = TALER_KYCLOGIC_run_aml_program3 (
diff --git a/src/include/taler/taler_exchange_service.h b/src/include/taler/taler_exchange_service.h
@@ -5310,7 +5310,8 @@ struct TALER_EXCHANGE_MeasureInformation
const char *check_name;
/**
- * Name of the AML program.
+ * Name of the AML program, can be NULL if @e check_name
+ * is for a check of type "INFO".
*/
const char *prog_name;
diff --git a/src/include/taler/taler_kyclogic_lib.h b/src/include/taler/taler_kyclogic_lib.h
@@ -502,7 +502,8 @@ TALER_KYCLOGIC_rules_to_limits (const json_t *jrules,
* @param jmeasures a LegitimizationMeasures object
* @param measure_index an index into the measures
* @param[out] check_name set to the name of the check
- * @param[out] prog_name set to the name of the program
+ * @param[out] prog_name set to the name of the program,
+ * possibly NULL for "SKIP" checks
* @param[out] context set to the measure context
* (or NULL if there is no context)
* @return #TALER_EC_NONE on success
@@ -541,7 +542,6 @@ TALER_KYCLOGIC_check_form (
* KycRequirementInformation used by the client.
*
* @param check_name the prescribed check
- * @param prog_name the program to run
* @param context context to return, can be NULL
* @param access_token access token for the measure
* @param offset offset of the measure
@@ -551,7 +551,6 @@ TALER_KYCLOGIC_check_form (
json_t *
TALER_KYCLOGIC_measure_to_requirement (
const char *check_name,
- const char *prog_name,
const json_t *context,
const struct TALER_AccountAccessTokenP *access_token,
size_t offset,
diff --git a/src/kyclogic/Makefile.am b/src/kyclogic/Makefile.am
@@ -62,7 +62,7 @@ libtalerkyclogic_la_LIBADD = \
-ljansson \
$(XLIB)
libtalerkyclogic_la_LDFLAGS = \
- -version-info 2:0:0 \
+ -version-info 3:0:0 \
-no-undefined
diff --git a/src/kyclogic/kyclogic_api.c b/src/kyclogic/kyclogic_api.c
@@ -452,6 +452,11 @@ find_check (const char *check_name)
static struct TALER_KYCLOGIC_AmlProgram *
find_program (const char *program_name)
{
+ if (NULL == program_name)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
for (unsigned int i = 0; i<num_aml_programs; i++)
{
struct TALER_KYCLOGIC_AmlProgram *program
@@ -504,96 +509,126 @@ static bool
check_measure (const struct TALER_KYCLOGIC_Measure *measure)
{
const struct TALER_KYCLOGIC_KycCheck *check;
- const struct TALER_KYCLOGIC_AmlProgram *program;
- program = find_program (measure->prog_name);
- if (NULL == program)
+ check = find_check (measure->check_name);
+ if ( (NULL == check) &&
+ (0 != strcasecmp (measure->check_name,
+ "SKIP")) )
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unknown program `%s' used in measure `%s'\n",
- measure->prog_name,
+ "Unknown check `%s' used in measure `%s'\n",
+ measure->check_name,
measure->measure_name);
return false;
}
- for (unsigned int j = 0; j<program->num_required_contexts; j++)
+ if ( (NULL == check) ||
+ (TALER_KYCLOGIC_CT_INFO != check->type) )
{
- const char *required_context = program->required_contexts[j];
+ const struct TALER_KYCLOGIC_AmlProgram *program;
- if (NULL ==
- json_object_get (measure->context,
- required_context))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Measure `%s' lacks required context `%s' for AML program `%s'\n",
- measure->measure_name,
- required_context,
- program->program_name);
- return false;
- }
- }
- if (0 == strcasecmp (measure->check_name,
- "SKIP"))
- {
- if (0 != program->num_required_attributes)
+ program = find_program (measure->prog_name);
+ if (NULL == program)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "AML program `%s' of measure `%s' has required attributes, but check is of type `SKIP' and thus cannot provide any!\n",
- program->program_name,
+ "Unknown program `%s' used in measure `%s'\n",
+ measure->prog_name,
measure->measure_name);
return false;
}
- return true;
- }
- check = find_check (measure->check_name);
- if (NULL == check)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Unknown check `%s' used in measure `%s'\n",
- measure->check_name,
- measure->measure_name);
- return false;
- }
- for (unsigned int j = 0; j<program->num_required_attributes; j++)
- {
- const char *required_attribute = program->required_attributes[j];
- bool found = false;
+ for (unsigned int j = 0; j<program->num_required_contexts; j++)
+ {
+ const char *required_context = program->required_contexts[j];
- for (unsigned int i = 0; i<check->num_outputs; i++)
+ if (NULL ==
+ json_object_get (measure->context,
+ required_context))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Measure `%s' lacks required context `%s' for AML program `%s'\n",
+ measure->measure_name,
+ required_context,
+ program->program_name);
+ return false;
+ }
+ }
+ if (0 == strcasecmp (measure->check_name,
+ "SKIP"))
{
- if (0 == strcasecmp (required_attribute,
- check->outputs[i]))
+ if (0 != program->num_required_attributes)
{
- found = true;
- break;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "AML program `%s' of measure `%s' has required attributes, but check is of type `SKIP' and thus cannot provide any!\n",
+ program->program_name,
+ measure->measure_name);
+ return false;
}
+ return true;
}
- if (! found)
+ for (unsigned int j = 0; j<program->num_required_attributes; j++)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Check `%s' of measure `%s' does not provide required output `%s' for AML program `%s'\n",
- check->check_name,
- measure->measure_name,
- required_attribute,
- program->program_name);
- return false;
+ const char *required_attribute = program->required_attributes[j];
+ bool found = false;
+
+ if (NULL != check)
+ {
+ for (unsigned int i = 0; i<check->num_outputs; i++)
+ {
+ if (0 == strcasecmp (required_attribute,
+ check->outputs[i]))
+ {
+ found = true;
+ break;
+ }
+ }
+ }
+ if (! found)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Check `%s' of measure `%s' does not provide required output `%s' for AML program `%s'\n",
+ measure->check_name,
+ measure->measure_name,
+ required_attribute,
+ program->program_name);
+ return false;
+ }
}
}
- for (unsigned int j = 0; j<check->num_requires; j++)
+ else
{
- const char *required_input = check->requires[j];
-
- if (NULL ==
- json_object_get (measure->context,
- required_input))
+ /* Check is of type "INFO" */
+ if (NULL != measure->prog_name)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Program `%s' used in INFO measure `%s' will never be used.\n",
+ measure->prog_name,
+ measure->measure_name);
+ if (0 == strcasecmp (measure->check_name,
+ "SKIP"))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Measure `%s' lacks required context `%s' for check `%s'\n",
- measure->measure_name,
- required_input,
- check->check_name);
+ "INFO check of measure `%s' should not be called 'SKIP'.\n",
+ measure->measure_name);
return false;
}
}
+ if (NULL != check)
+ {
+ for (unsigned int j = 0; j<check->num_requires; j++)
+ {
+ const char *required_input = check->requires[j];
+
+ if (NULL ==
+ json_object_get (measure->context,
+ required_input))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Measure `%s' lacks required context `%s' for check `%s'\n",
+ measure->measure_name,
+ required_input,
+ measure->check_name);
+ return false;
+ }
+ }
+ }
return true;
}
@@ -721,7 +756,7 @@ TALER_KYCLOGIC_rules_parse (const json_t *jlrs)
jmeasure)
{
const char *check_name;
- const char *prog_name;
+ const char *prog_name = NULL;
const json_t *context = NULL;
bool voluntary = false;
struct TALER_KYCLOGIC_Measure *measure
@@ -729,8 +764,10 @@ TALER_KYCLOGIC_rules_parse (const json_t *jlrs)
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_string ("check_name",
&check_name),
- GNUNET_JSON_spec_string ("prog_name",
- &prog_name),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("prog_name",
+ &prog_name),
+ NULL),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_object_const ("context",
&context),
@@ -754,8 +791,9 @@ TALER_KYCLOGIC_rules_parse (const json_t *jlrs)
= GNUNET_strdup (measure_name);
measure->check_name
= GNUNET_strdup (check_name);
- measure->prog_name
- = GNUNET_strdup (prog_name);
+ if (NULL != prog_name)
+ measure->prog_name
+ = GNUNET_strdup (prog_name);
measure->voluntary
= voluntary;
if (NULL != context)
@@ -1192,8 +1230,9 @@ TALER_KYCLOGIC_rule_to_measures (
mi = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("check_name",
ms->check_name),
- GNUNET_JSON_pack_string ("prog_name",
- ms->prog_name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("prog_name",
+ ms->prog_name)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("context",
ms->context)));
@@ -1265,8 +1304,9 @@ TALER_KYCLOGIC_zero_measures (
rule->trigger),
GNUNET_JSON_pack_string ("check_name",
ms->check_name),
- GNUNET_JSON_pack_string ("prog_name",
- ms->prog_name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("prog_name",
+ ms->prog_name)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("context",
ms->context)));
@@ -1328,8 +1368,9 @@ append_voluntary_measure (
mj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("check_name",
ms->check_name),
- GNUNET_JSON_pack_string ("prog_name",
- ms->prog_name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("prog_name",
+ ms->prog_name)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("context",
ms->context)));
@@ -1481,8 +1522,9 @@ TALER_KYCLOGIC_get_jmeasures (
mi = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("check_name",
ms->check_name),
- GNUNET_JSON_pack_string ("prog_name",
- ms->prog_name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("prog_name",
+ ms->prog_name)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("context",
ms->context)));
@@ -1515,8 +1557,9 @@ TALER_KYCLOGIC_check_to_jmeasures (
NULL == check
? "SKIP"
: check->check_name),
- GNUNET_JSON_pack_string ("prog_name",
- kcc->prog_name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("prog_name",
+ kcc->prog_name)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("context",
(json_t *) kcc->context)));
@@ -1545,8 +1588,9 @@ TALER_KYCLOGIC_measure_to_jmeasures (
mi = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("check_name",
m->check_name),
- GNUNET_JSON_pack_string ("prog_name",
- m->prog_name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("prog_name",
+ m->prog_name)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("context",
(json_t *) m->context)));
@@ -2765,6 +2809,7 @@ add_measure (const struct GNUNET_CONFIGURATION_Handle *cfg,
{
bool voluntary;
char *check_name = NULL;
+ struct TALER_KYCLOGIC_KycCheck *kc = NULL;
char *context_str = NULL;
char *program = NULL;
json_t *context;
@@ -2781,22 +2826,52 @@ add_measure (const struct GNUNET_CONFIGURATION_Handle *cfg,
{
check_name = GNUNET_strdup ("SKIP");
}
+ if (0 != strcasecmp (check_name,
+ "SKIP"))
+ {
+ kc = find_check (check_name);
+ if (NULL == kc)
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "CHECK_NAME",
+ "check unknown");
+ goto fail;
+ }
+ }
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
section,
"PROGRAM",
&program))
{
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- section,
- "PROGRAM");
- goto fail;
+ if ( (NULL == kc) ||
+ (TALER_KYCLOGIC_CT_INFO != kc->type) )
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "PROGRAM");
+ goto fail;
+ }
+ }
+ else
+ {
+ /* AML program given, but do we want one? */
+ if ( (NULL != kc) &&
+ (TALER_KYCLOGIC_CT_INFO == kc->type) )
+ {
+ GNUNET_log_config_invalid (
+ GNUNET_ERROR_TYPE_WARNING,
+ section,
+ "PROGRAM",
+ "AML program specified for a check of type INFO (ignored)");
+ GNUNET_free (program);
+ }
}
voluntary = (GNUNET_YES ==
GNUNET_CONFIGURATION_get_value_yesno (cfg,
section,
"VOLUNTARY"));
-
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
section,
@@ -3118,7 +3193,6 @@ TALER_KYCLOGIC_kyc_init (
const struct TALER_KYCLOGIC_AmlProgram *program
= aml_programs[i];
const struct TALER_KYCLOGIC_Measure *m;
- const struct TALER_KYCLOGIC_AmlProgram *fprogram;
m = find_measure (&default_rules,
program->fallback);
@@ -3140,16 +3214,21 @@ TALER_KYCLOGIC_kyc_init (
m->check_name);
return GNUNET_SYSERR;
}
- fprogram = find_program (m->prog_name);
- GNUNET_assert (NULL != fprogram);
- if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
+ if (NULL != m->prog_name)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Fallback program %s of fallback measure `%s' used in AML program `%s' has required inputs, but fallback measures must not require any inputs\n",
- m->prog_name,
- program->program_name,
- m->check_name);
- return GNUNET_SYSERR;
+ const struct TALER_KYCLOGIC_AmlProgram *fprogram;
+
+ fprogram = find_program (m->prog_name);
+ GNUNET_assert (NULL != fprogram);
+ if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fallback program %s of fallback measure `%s' used in AML program `%s' has required inputs, but fallback measures must not require any inputs\n",
+ m->prog_name,
+ program->program_name,
+ m->check_name);
+ return GNUNET_SYSERR;
+ }
}
}
@@ -3158,7 +3237,6 @@ TALER_KYCLOGIC_kyc_init (
struct TALER_KYCLOGIC_KycCheck *kyc_check
= kyc_checks[i];
const struct TALER_KYCLOGIC_Measure *measure;
- const struct TALER_KYCLOGIC_AmlProgram *fprogram;
measure = find_measure (&default_rules,
kyc_check->fallback);
@@ -3180,16 +3258,21 @@ TALER_KYCLOGIC_kyc_init (
measure->check_name);
return GNUNET_SYSERR;
}
- fprogram = find_program (measure->prog_name);
- GNUNET_assert (NULL != fprogram);
- if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
+ if (NULL != measure->prog_name)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "AML program `%s' used fallback measure `%s' of KYC check `%s' has required inputs, but fallback measures must not require any inputs\n",
- measure->prog_name,
- kyc_check->fallback,
- kyc_check->check_name);
- return GNUNET_SYSERR;
+ const struct TALER_KYCLOGIC_AmlProgram *fprogram;
+
+ fprogram = find_program (measure->prog_name);
+ GNUNET_assert (NULL != fprogram);
+ if (API_NONE != (fprogram->input_mask & (API_CONTEXT | API_ATTRIBUTES)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "AML program `%s' used fallback measure `%s' of KYC check `%s' has required inputs, but fallback measures must not require any inputs\n",
+ measure->prog_name,
+ kyc_check->fallback,
+ kyc_check->check_name);
+ return GNUNET_SYSERR;
+ }
}
}
@@ -3706,7 +3789,6 @@ TALER_KYCLOGIC_kyc_test_required (
json_t *
TALER_KYCLOGIC_measure_to_requirement (
const char *check_name,
- const char *prog_name,
const json_t *context,
const struct TALER_AccountAccessTokenP *access_token,
size_t offset,
@@ -3816,8 +3898,9 @@ TALER_KYCLOGIC_get_measure_configuration (
jm = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("check_name",
m->check_name),
- GNUNET_JSON_pack_string ("prog_name",
- m->prog_name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("prog_name",
+ m->prog_name)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("context",
m->context)));
@@ -3993,8 +4076,10 @@ TALER_KYCLOGIC_select_measure (
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_string ("check_name",
check_name),
- GNUNET_JSON_spec_string ("prog_name",
- prog_name),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("prog_name",
+ prog_name),
+ NULL),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_object_const ("context",
context),
@@ -4070,6 +4155,12 @@ TALER_KYCLOGIC_check_form (
GNUNET_break_op (0);
return TALER_EC_EXCHANGE_KYC_NOT_A_FORM;
}
+ if (NULL == prog_name)
+ {
+ /* non-INFO checks must have an AML program */
+ GNUNET_break (0);
+ return TALER_EC_EXCHANGE_KYC_GENERIC_LOGIC_BUG;
+ }
for (unsigned int i = 0; i<kc->num_outputs; i++)
{
const char *rattr = kc->outputs[i];
@@ -4547,6 +4638,21 @@ TALER_KYCLOGIC_run_aml_program (
return NULL;
}
}
+ if (NULL == prog_name)
+ {
+ /* Trying to run AML program on a measure that does not
+ have one, and that should thus be an INFO check which
+ should never lead here. Very strange. */
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Measure %u with check `%s' does not have an AML program!\n",
+ measure_index,
+ check_name);
+ json_dumpf (jmeasures,
+ stderr,
+ JSON_INDENT (2));
+ return NULL;
+ }
return TALER_KYCLOGIC_run_aml_program2 (prog_name,
context,
is_wallet,
diff --git a/src/lib/exchange_api_add_aml_decision.c b/src/lib/exchange_api_add_aml_decision.c
@@ -214,8 +214,9 @@ TALER_EXCHANGE_post_aml_decision (
measure = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("check_name",
mi->check_name),
- GNUNET_JSON_pack_string ("prog_name",
- mi->prog_name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("prog_name",
+ mi->prog_name)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("context",
(json_t *) mi->context))
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
@@ -40,12 +40,12 @@
* Which version of the Taler protocol is implemented
* by this library? Used to determine compatibility.
*/
-#define EXCHANGE_PROTOCOL_CURRENT 29
+#define EXCHANGE_PROTOCOL_CURRENT 30
/**
* How many versions are we backwards compatible with?
*/
-#define EXCHANGE_PROTOCOL_AGE 3
+#define EXCHANGE_PROTOCOL_AGE 4
/**
* Set to 1 for extra debug logging.
diff --git a/src/lib/exchange_api_lookup_aml_decisions.c b/src/lib/exchange_api_lookup_aml_decisions.c
@@ -141,8 +141,10 @@ parse_limits (struct TALER_EXCHANGE_LookupAmlDecisions *lh,
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_string ("check_name",
&mi->check_name),
- GNUNET_JSON_spec_string ("prog_name",
- &mi->prog_name),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("prog_name",
+ &mi->prog_name),
+ NULL),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_object_const ("context",
&mi->context),
diff --git a/src/testing/testing_api_cmd_take_aml_decision.c b/src/testing/testing_api_cmd_take_aml_decision.c
@@ -321,8 +321,10 @@ take_aml_decision_run (void *cls,
GNUNET_JSON_spec_string ("check_name",
&mi->check_name),
NULL),
- GNUNET_JSON_spec_string ("prog_name",
- &mi->prog_name),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("prog_name",
+ &mi->prog_name),
+ NULL),
GNUNET_JSON_spec_mark_optional (
GNUNET_JSON_spec_object_const ("context",
&mi->context),