From d5d37b631495c60f2248ca51e065a452c71f567e Mon Sep 17 00:00:00 2001 From: Özgür Kesim Date: Wed, 28 Sep 2022 15:39:24 +0200 Subject: 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. --- replay.c | 407 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 replay.c (limited to 'replay.c') 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 . + */ + +/** + * @file replay.c + * @brief Replay a auction, given as transcript in json form on stdin + * @author Özgür Kesim + */ + +#include "platform.h" + +#include +#include +#include +#include + +#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; +} -- cgit v1.2.3