aboutsummaryrefslogtreecommitdiff
path: root/replay.c
diff options
context:
space:
mode:
authorÖzgür Kesim <oec@codeblau.de>2022-09-28 15:39:24 +0200
committerÖzgür Kesim <oec@codeblau.de>2022-09-28 15:39:24 +0200
commitd5d37b631495c60f2248ca51e065a452c71f567e (patch)
tree4dd3fd5b63482f1c1ce2737ab10fbe12117db143 /replay.c
parenta6306bbc80b3c6e911ff915e7d6f4c3760da8e06 (diff)
Transcript generation and replay
test_brandt now generates transcripts of auctions in JSON form on stdout. replay is a program that reads such a transcript and replays the auction.
Diffstat (limited to 'replay.c')
-rw-r--r--replay.c407
1 files changed, 407 insertions, 0 deletions
diff --git a/replay.c b/replay.c
new file mode 100644
index 0000000..bf2b50c
--- /dev/null
+++ b/replay.c
@@ -0,0 +1,407 @@
+/* This file is part of libbrandt.
+ * Copyright (C) 2022 GNUnet e.V.
+ *
+ * libbrandt is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * libbrandt is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * libbrandt. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file replay.c
+ * @brief Replay a auction, given as transcript in json form on stdin
+ * @author Özgür Kesim
+ */
+
+#include "platform.h"
+
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <taler/taler_amount_lib.h>
+#include <jansson.h>
+
+#include "brandt.h"
+#include "crypto.h"
+#include "util.h"
+
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+
+struct msg
+{
+ uint16_t sender;
+ void *buf;
+ size_t buf_len;
+};
+
+/* This is basically BRANDT_Result with an extra string field */
+struct result
+{
+ uint16_t bidder;
+ uint16_t price_idx;
+ const char *price;
+};
+
+struct transcript
+{
+ // All fields from json come here.
+ uint16_t n; // #bidders + 1
+ uint16_t k; // #prices
+ uint16_t m; // type of auction
+ struct GNUNET_TIME_Absolute time_start;
+ struct GNUNET_TIME_Relative time_round;
+ bool public;
+ char **prices; // Must be of length k. We do not parse those
+ struct msg *msgs; // Array must be of length 4*n
+
+ struct BRANDT_Auction *auction;
+ struct result *expected;
+ size_t expected_len;
+ uint16_t id;
+ struct GNUNET_CRYPTO_EccDlogContext *edc;
+};
+
+static struct transcript tr;
+
+static void
+tr_result (void *arg,
+ struct BRANDT_Result results[],
+ uint16_t results_len)
+{
+ struct transcript *tr = (struct transcript *) arg;
+ for (uint16_t i = 0; i < results_len; i++)
+ {
+ GNUNET_log (
+ GNUNET_ERROR_TYPE_INFO,
+ "REPLAY [seller] computed result is: bidder %d got status %d with price %d (%s)\n",
+ results[i].bidder,
+ results[i].status,
+ results[i].price,
+ tr->prices[results[i].price]);
+ }
+
+ for (uint16_t i = 0; i < tr->expected_len; i++)
+ {
+ GNUNET_log (
+ GNUNET_ERROR_TYPE_INFO,
+ "REPLAY [seller] expected result is: bidder %d wins with price %d (%s)\n",
+ tr->expected[i].bidder,
+ tr->expected[i].price_idx,
+ tr->expected[i].price);
+ }
+
+
+ // TODO: generate JSON-output
+}
+
+
+static uint16_t
+tr_start (void *auction_closure)
+{
+ struct transcript *tr = (struct transcript *) auction_closure;
+ struct cls
+ {
+ size_t i;
+ struct transcript *tr;
+ };
+
+ void
+ resend (void *x)
+ {
+ struct cls c = *(struct cls *) x;
+ struct msg m = c.tr->msgs[c.i];
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "REPLAY sending msg no. %ld, length %ld\n", c.i, m.buf_len);
+ BRANDT_got_message (c.tr->auction, m.sender, m.buf, m.buf_len);
+ }
+
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, "REPLAY start replay auction\n");
+ for (size_t i = 0; i < 4 * tr->n; i++)
+ {
+ struct cls *c = GNUNET_new (struct cls);
+ c->i = i;
+ c->tr = tr;
+ GNUNET_SCHEDULER_add_now (&resend, (void *) c);
+ }
+
+ return tr->n;
+}
+
+
+static void
+replay_transcript (void *arg)
+{
+ struct transcript *tr = (struct transcript *) arg;
+ void *desc;
+ size_t desc_len;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "REPLAY calling BRANDT_new with %s outcome.\n",
+ tr->public ? "public" : "private");
+
+ tr->auction = BRANDT_new (&tr_result,
+ NULL,
+ &tr_start,
+ tr,
+ &desc,
+ &desc_len,
+ GNUNET_TIME_absolute_get (),
+ tr->time_round,
+ tr->k, /* number of prizes */
+ tr->m, /* m */
+ tr->public, /* outcome public */
+ tr->public ? tr->edc : NULL);
+ if (!tr->auction)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "REPLAY BRANDT_new() failed.\n");
+ _exit (1);
+ // TODO: generate JSON error response
+ }
+
+}
+
+
+enum GNUNET_GenericReturnValue
+parse_json_stdin (struct transcript *tr)
+{
+ json_error_t jerror;
+ json_t *jtr;
+ struct GNUNET_CRYPTO_EddsaSignature sig;
+
+ jtr = json_loadfd (0,
+ JSON_REJECT_DUPLICATES,
+ &jerror);
+
+ if (!jtr)
+ {
+ // TODO: generate JSON error response
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "REPLAY failed to parse json: %s in line %d, column %d (pos %d)\n",
+ jerror.text, jerror.line, jerror.column, jerror.position);
+ _exit (1);
+ }
+
+
+ {
+ json_t *auc;
+ char *perr;
+ unsigned int eline;
+ struct GNUNET_JSON_Specification au_spec[] = {
+ GNUNET_JSON_spec_bool ("public", &tr->public),
+ GNUNET_JSON_spec_uint16 ("type", &tr->m),
+ GNUNET_JSON_spec_end ()
+ };
+
+ auc = json_object_get (jtr, "auction");
+ if (NULL == auc)
+ {
+ // TODO error message as json
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "no auction found in JSON");
+ _exit (1);
+ }
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_JSON_parse (auc,
+ au_spec,
+ (const char **) &perr,
+ &eline));
+
+ // Prices...
+ {
+ json_t *prices = json_object_get (auc, "prices");
+ size_t idx;
+ json_t *val;
+
+
+ if (!json_is_array (prices))
+ {
+ // TODO error message as json
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "no prices found in JSON\n");
+ _exit (1);
+ }
+
+ tr->k = json_array_size (prices);
+ tr->prices = GNUNET_new_array (tr->k, char *);
+ json_array_foreach (prices, idx, val)
+ {
+ if (!json_is_string (val))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "price %ld is not a string\n", idx);
+ _exit (1);
+ }
+ tr->prices[idx] = (char *) json_string_value (val);
+ }
+
+ }
+
+ }
+
+ // Bidders
+ {
+ json_t *bidders;
+
+ bidders = json_object_get (jtr, "bidders");
+ if (!bidders || !json_is_array (bidders))
+ {
+ // TODO: json-error
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "bidders missing or not an array\n");
+ _exit (1);
+ }
+
+ tr->n = json_array_size (bidders);
+ }
+
+
+ // Messages
+ {
+ json_t *messages;
+ size_t nm;
+ size_t idx;
+ json_t *val;
+
+ messages = json_object_get (jtr, "transcript");
+ if (!json_is_array (messages))
+ {
+ // TODO: json-error
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "transcript missing or not an array\n");
+ _exit (1);
+ }
+
+ nm = json_array_size (messages);
+
+ if (nm != (4 * tr->n))
+ {
+ // TODO: json-error
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "wrong number of messages in transcript\n");
+ _exit (1);
+ }
+
+ tr->msgs = GNUNET_new_array (nm, struct msg);
+
+ json_array_foreach (messages, idx, val) {
+ char *error;
+ uint16_t sender;
+ void *msg;
+ size_t size;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint16 ("bidder",
+ &sender),
+ GNUNET_JSON_spec_varsize ("msg",
+ &msg,
+ &size),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (val,
+ spec,
+ (const char**) &error,
+ NULL))
+ {
+ // TODO: json-error
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "error parsing message[%ld] in transcript: %s\njson:\n%s\n",
+ idx,
+ error,
+ json_dumps (val, JSON_INDENT (2)));
+ _exit (1);
+ }
+
+ tr->msgs[idx].sender = sender;
+ tr->msgs[idx].buf = msg;
+ tr->msgs[idx].buf_len = size;
+ }
+
+ }
+
+ // Winners
+ {
+ json_t *winners;
+ size_t idx;
+ json_t *val;
+
+ winners = json_object_get (jtr, "winners");
+
+ if (!json_is_array (winners))
+ {
+ // TODO: json-warning
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "winners not provided, continuing without\n");
+ goto CONT;
+ }
+
+ tr->expected_len = json_array_size (winners);
+ tr->expected = GNUNET_new_array (tr->expected_len,
+ struct result);
+
+ json_array_foreach (winners, idx, val) {
+ char *error;
+
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint16 ("bidder",
+ &(tr->expected[idx].bidder)),
+ GNUNET_JSON_spec_uint16 ("price_idx",
+ &(tr->expected[idx].price_idx)),
+ GNUNET_JSON_spec_string ("price",
+ &(tr->expected[idx].price)),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse(val,
+ spec,
+ (const char**) &error,
+ NULL))
+ {
+ // TODO: json-error
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "error parsing winners[%ld] in transcript: %s\njson:\n%s\n",
+ idx,
+ error,
+ json_dumps (val, JSON_INDENT (2)));
+ _exit (1);
+ }
+
+ }
+
+CONT:
+ }
+
+ return GNUNET_OK;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ int ret = 0;
+ struct transcript tr = {0};
+
+ if (GNUNET_OK != GNUNET_log_setup ("replay", "INFO", NULL))
+ return 1;
+
+ BRANDT_init ();
+
+ GNUNET_assert (GNUNET_OK ==
+ parse_json_stdin (&tr));
+ // TODO: error as json-output if failure
+ //
+ tr.edc = GNUNET_CRYPTO_ecc_dlog_prepare (1024 * 1024 * 40, 1024);
+ GNUNET_SCHEDULER_run (&replay_transcript, &tr);
+ GNUNET_CRYPTO_ecc_dlog_release (tr.edc);
+
+ return ret;
+}