aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-07-30 22:54:21 +0200
committerChristian Grothoff <christian@grothoff.org>2022-07-30 22:54:21 +0200
commit150917694a4dc3709319fc9586e502eb4b05151f (patch)
tree2b4882089bdf4c190b410a1c0f8516c901c766f8
parent544fbd4fe9f536b5933467d3f1adc65a3f1b772d (diff)
finish taler-exchange-drain implementation
-rw-r--r--src/exchange/taler-exchange-aggregator.c6
-rw-r--r--src/exchange/taler-exchange-drain.c180
-rw-r--r--src/exchange/taler-exchange-httpd.c6
-rw-r--r--src/include/taler_exchangedb_plugin.h38
4 files changed, 213 insertions, 17 deletions
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
index 9568f011e..3d30ccd08 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -234,12 +234,12 @@ shutdown_task (void *cls)
/**
- * Parse the configuration for wirewatch.
+ * Parse the configuration for aggregator.
*
* @return #GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
-parse_wirewatch_config (void)
+parse_aggregator_config (void)
{
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
@@ -811,7 +811,7 @@ run (void *cls,
(void) cfgfile;
cfg = c;
- if (GNUNET_OK != parse_wirewatch_config ())
+ if (GNUNET_OK != parse_aggregator_config ())
{
cfg = NULL;
global_ret = EXIT_NOTCONFIGURED;
diff --git a/src/exchange/taler-exchange-drain.c b/src/exchange/taler-exchange-drain.c
index 71656412e..d409487c1 100644
--- a/src/exchange/taler-exchange-drain.c
+++ b/src/exchange/taler-exchange-drain.c
@@ -40,11 +40,21 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg;
static struct TALER_EXCHANGEDB_Plugin *db_plugin;
/**
+ * Our master public key.
+ */
+static struct TALER_MasterPublicKeyP master_pub;
+
+/**
* Next task to run, if any.
*/
static struct GNUNET_SCHEDULER_Task *task;
/**
+ * Base URL of this exchange.
+ */
+static char *exchange_base_url;
+
+/**
* Value to return from main(). 0 on success, non-zero on errors.
*/
static int global_ret;
@@ -82,6 +92,47 @@ shutdown_task (void *cls)
static enum GNUNET_GenericReturnValue
parse_drain_config (void)
{
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "BASE_URL",
+ &exchange_base_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "BASE_URL");
+ return GNUNET_SYSERR;
+ }
+
+ {
+ char *master_public_key_str;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "exchange",
+ "MASTER_PUBLIC_KEY",
+ &master_public_key_str))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "MASTER_PUBLIC_KEY");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_public_key_from_string (master_public_key_str,
+ strlen (
+ master_public_key_str),
+ &master_pub.eddsa_pub))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "MASTER_PUBLIC_KEY",
+ "invalid base32 encoding for a master public key");
+ GNUNET_free (master_public_key_str);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (master_public_key_str);
+ }
if (NULL ==
(db_plugin = TALER_EXCHANGEDB_plugin_load (cfg)))
{
@@ -134,6 +185,13 @@ static void
run_drain (void *cls)
{
enum GNUNET_DB_QueryStatus qs;
+ uint64_t serial;
+ struct TALER_WireTransferIdentifierRawP wtid;
+ char *account_section;
+ char *payto_uri;
+ struct GNUNET_TIME_Timestamp request_timestamp;
+ struct TALER_Amount amount;
+ struct TALER_MasterSignatureP master_sig;
(void) cls;
task = NULL;
@@ -147,11 +205,14 @@ run_drain (void *cls)
GNUNET_SCHEDULER_shutdown ();
return;
}
-#if 0
- qs = db_plugin->profit_drains_get_pending (db_plugin->cls);
-#else
- qs = -1;
-#endif
+ qs = db_plugin->profit_drains_get_pending (db_plugin->cls,
+ &serial,
+ &wtid,
+ &account_section,
+ &payto_uri,
+ &request_timestamp,
+ &amount,
+ &master_sig);
switch (qs)
{
case GNUNET_DB_STATUS_HARD_ERROR:
@@ -161,7 +222,6 @@ run_drain (void *cls)
GNUNET_SCHEDULER_shutdown ();
return;
case GNUNET_DB_STATUS_SOFT_ERROR:
- /* try again */
db_plugin->rollback (db_plugin->cls);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Serialization failure on simple SELECT!?\n");
@@ -169,7 +229,7 @@ run_drain (void *cls)
GNUNET_SCHEDULER_shutdown ();
return;
case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
- /* no more profit drains, go sleep a bit! */
+ /* no profit drains, finished */
db_plugin->rollback (db_plugin->cls);
GNUNET_assert (NULL == task);
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
@@ -180,11 +240,107 @@ run_drain (void *cls)
/* continued below */
break;
}
- // FIXME: check signature (again!)
- // FIMXE: display for human check
- // FIXME: insert into pre-wire
- // FIXME: mark as done
- // FIXME: commit transaction + report success + exit
+ /* Check signature (again, this is a critical operation!) */
+ if (GNUNET_OK !=
+ TALER_exchange_offline_profit_drain_verify (
+ &wtid,
+ request_timestamp,
+ &amount,
+ account_section,
+ payto_uri,
+ &master_pub,
+ &master_sig))
+ {
+ GNUNET_break (0);
+ global_ret = EXIT_FAILURE;
+ db_plugin->rollback (db_plugin->cls);
+ GNUNET_assert (NULL == task);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ /* Display data for manual human check */
+ fprintf (stdout,
+ "Critical operation. MANUAL CHECK REQUIRED.\n");
+ fprintf (stdout,
+ "We will wire %s to `%s'\n based on instructions from %s.\n",
+ TALER_amount2s (&amount),
+ payto_uri,
+ GNUNET_TIME_timestamp2s (request_timestamp));
+ fprintf (stdout,
+ "Press ENTER to confirm, CTRL-D to abort.\n");
+ while (1)
+ {
+ int key;
+
+ key = getchar ();
+ if (EOF == key)
+ {
+ fprintf (stdout,
+ "Transfer aborted.\n"
+ "Re-run 'taler-exchange-drain' to try it again.\n"
+ "Contact Taler Systems SA to cancel it for good.\n"
+ "Exiting.\n");
+ db_plugin->rollback (db_plugin->cls);
+ GNUNET_assert (NULL == task);
+ GNUNET_SCHEDULER_shutdown ();
+ global_ret = EXIT_FAILURE;
+ return;
+ }
+ if ('\n' == key)
+ break;
+ }
+
+ /* Note: account_section ignored for now, we
+ might want to use it here in the future... */
+ (void) account_section;
+ {
+ char *method;
+ void *buf;
+ size_t buf_size;
+
+ TALER_BANK_prepare_transfer (payto_uri,
+ &amount,
+ exchange_base_url,
+ &wtid,
+ &buf,
+ &buf_size);
+ method = TALER_payto_get_method (payto_uri);
+ qs = db_plugin->wire_prepare_data_insert (db_plugin->cls,
+ method,
+ buf,
+ buf_size);
+ GNUNET_free (method);
+ GNUNET_free (buf);
+ }
+ qs = db_plugin->profit_drains_set_finished (db_plugin->cls,
+ serial);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ db_plugin->rollback (db_plugin->cls);
+ GNUNET_break (0);
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ db_plugin->rollback (db_plugin->cls);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed: database serialization issue\n");
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ db_plugin->rollback (db_plugin->cls);
+ GNUNET_assert (NULL == task);
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ default:
+ /* continued below */
+ break;
+ }
+ /* commit transaction + report success + exit */
if (0 >= commit_or_warn ())
GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
"Profit drain triggered. Exiting.\n");
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index 2d659058a..14cc8c1c5 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -1836,8 +1836,10 @@ exchange_serve_process_config (void)
&TEH_master_public_key.
eddsa_pub))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Invalid master public key given in exchange configuration.");
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "MASTER_PUBLIC_KEY",
+ "invalid base32 encoding for a master public key");
GNUNET_free (master_public_key_str);
return GNUNET_SYSERR;
}
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 7f31752df..2ffa84866 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -5545,6 +5545,44 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_MasterSignatureP *master_sig);
+ /**
+ * Get profit drain operation ready to execute.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param[out] serial set to serial ID of the entry
+ * @param[out] wtid set set to wire transfer ID to use
+ * @param[out] account_section set to account to drain
+ * @param[out] payto_uri set to account to wire funds to
+ * @param[out] request_timestamp set to time of the signature
+ * @param[out] amount set to amount to wire
+ * @param[out] master_sig set to signature affirming the operation
+ * @return transaction status code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*profit_drains_get_pending)(
+ void *cls,
+ uint64_t *serial,
+ struct TALER_WireTransferIdentifierRawP *wtid,
+ char **account_section,
+ char **payto_uri,
+ struct GNUNET_TIME_Timestamp *request_timestamp,
+ struct TALER_Amount *amount,
+ struct TALER_MasterSignatureP *master_sig);
+
+
+ /**
+ * Set profit drain operation to finished.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param serial serial ID of the entry to mark finished
+ * @return transaction status code
+ */
+ enum GNUNET_DB_QueryStatus
+ (*profit_drains_set_finished)(
+ void *cls,
+ uint64_t serial);
+
+
};
#endif /* _TALER_EXCHANGE_DB_H */