From 15956f47c08603a4eb3fd9490d568377faa60488 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 4 Jul 2015 17:30:38 +0200 Subject: [PATCH] skeleton for the interpreter loop to write tests for the mint --- src/mint-lib/test_mint_api.c | 270 ++++++++++++++++++++++++++++++++++- 1 file changed, 268 insertions(+), 2 deletions(-) diff --git a/src/mint-lib/test_mint_api.c b/src/mint-lib/test_mint_api.c index 7252337f9..42e69db06 100644 --- a/src/mint-lib/test_mint_api.c +++ b/src/mint-lib/test_mint_api.c @@ -50,6 +50,248 @@ static struct GNUNET_SCHEDULER_Task *ctx_task; static int result; +/** + * Opcodes for the interpreter. + */ +enum OpCode +{ + /** + * Termination code, stops the interpreter loop (with success). + */ + OC_END = 0, + + /** + * Add funds to a reserve by (faking) incoming wire transfer. + */ + OC_ADMIN_ADD_INCOMING, + + /** + * Withdraw a coin from a reserve. + */ + OC_WITHDRAW_SIGN, + + /** + * Deposit a coin (pay with it). + */ + OC_DEPOSIT + +}; + + +/** + * Details for a mint operation to execute. + */ +struct Command +{ + /** + * Opcode of the command. + */ + enum OpCode oc; + + /** + * Label for the command, can be NULL. + */ + const char *label; + + /** + * Details about the command. + */ + union + { + + struct + { + + /** + * Label to another admin_add_incoming command if we + * should deposit into an existing reserve, NULL if + * a fresh reserve should be created. + */ + const char *reserve_reference; + + /** + * String describing the amount to add to the reserve. + */ + const char *amount; + + /** + * Set (by the interpreter) to the reserve's private key + * we used to fill the reserve. + */ + struct TALER_ReservePrivateKeyP reserve_priv; + + } admin_add_incoming; + + struct + { + /** + * Which reserve should we withdraw from? + */ + const char *reserve_reference; + + /** + * String describing the denomination value we should withdraw. + * A corresponding denomination key must exist in the mint's + * offerings. Can be NULL if @e pk is set instead. + */ + const char *amount; + + /** + * If @e amount is NULL, this specifies the denomination key to + * use. Otherwise, this will be set (by the interpreter) to the + * denomination PK matching @e amount. + */ + const struct TALER_MINT_DenomPublicKey *pk; + + /** + * Set (by the interpreter) to the mint's signature over the + * coin's public key. + */ + struct TALER_DenominationSignature sig; + + /** + * Set (by the interpreter) to the coin's private key. + */ + struct TALER_CoinSpendPrivateKeyP coin_priv; + + } withdraw_sign; + + struct + { + + /** + * Amount to deposit. + */ + const char *amount; + + /** + * Reference to a withdraw_sign operation for a coin to + * be used for the /deposit operation. + */ + const char *coin_ref; + + /** + * JSON string describing the merchant's "wire details". + */ + const char *wire_details; + + /** + * JSON string describing the contract between the two parties. + */ + const char *contract; + + /** + * Transaction ID to use. + */ + uint64_t transaction_id; + + /** + * Relative time (to add to 'now') to compute the refund deadline. + * Zero for no refunds. + */ + struct GNUNET_TIME_Relative refund_deadline; + + /** + * Set (by the interpreter) to a fresh private key of the merchant, + * if @e refund_deadline is non-zero. + */ + struct TALER_MerchantPublicKeyP merchant_priv; + + } deposit; + + } details; + +}; + + +/** + * State of the interpreter loop. + */ +struct InterpreterState +{ + /** + * Keys from the mint. + */ + const struct TALER_MINT_Keys *keys; + + /** + * Commands the interpreter will run. + */ + struct Command *commands; + + /** + * Instruction pointer. Tells #interpreter_run() which + * instruction to run next. + */ + unsigned int ip; + +}; + + +/** + * The testcase failed, return with an error code. + * + * @param is interpreter state to clean up + */ +static void +fail (struct InterpreterState *is) +{ + result = GNUNET_SYSERR; + GNUNET_free (is); + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Run the main interpreter loop that performs mint operations. + * + * @param cls contains the `struct InterpreterState` + * @param tc scheduler context + */ +static void +interpreter_run (void *cls, + const struct GNUNET_SCHEDULER_TaskContext *tc) +{ + struct InterpreterState *is = cls; + struct Command *cmd = &is->commands[is->ip++]; + + if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) + { + fprintf (stderr, + "Test aborted by shutdown request\n"); + fail (is); + return; + } + switch (cmd->oc) + { + case OC_END: + result = GNUNET_OK; + GNUNET_free (is); + GNUNET_SCHEDULER_shutdown (); + return; + case OC_ADMIN_ADD_INCOMING: + GNUNET_break (0); // to be implemented! + break; + case OC_WITHDRAW_SIGN: + GNUNET_break (0); // to be implemented! + break; + case OC_DEPOSIT: + GNUNET_break (0); // to be implemented! + break; + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unknown instruction %d at %u (%s)\n", + cmd->oc, + is->ip - 1, + cmd->label); + fail (is); + return; + } + GNUNET_SCHEDULER_add_now (&interpreter_run, + is); +} + + /** * Function run when the test terminates (good or bad). * Cleans up our state. @@ -92,6 +334,26 @@ static void cert_cb (void *cls, const struct TALER_MINT_Keys *keys) { + struct InterpreterState *is; + static struct Command commands[] = + { + { .oc = OC_ADMIN_ADD_INCOMING, + .label = "create-reserve-1", + .details.admin_add_incoming.amount = "EUR:5" }, + { .oc = OC_WITHDRAW_SIGN, + .label = "withdraw-coin-1", + .details.withdraw_sign.reserve_reference = "create-reserve-1", + .details.withdraw_sign.amount = "EUR:5" }, + { .oc = OC_DEPOSIT, + .label = "deposit-simple", + .details.deposit.amount = "EUR:5", + .details.deposit.coin_ref = "withdraw-coin-1", + .details.deposit.wire_details = "{ bank=\"my bank\", account=\"42\" }", + .details.deposit.contract = "{ items={ name=\"ice cream\", value=1 } }", + .details.deposit.transaction_id = 1 }, + { .oc = OC_END } + }; + GNUNET_assert (NULL == cls); #define ERR(cond) do { if(!(cond)) break; GNUNET_break (0); GNUNET_SCHEDULER_shutdown(); return; } while (0) ERR (NULL == keys); @@ -105,8 +367,12 @@ cert_cb (void *cls, keys->num_denom_keys); #undef ERR /* TODO: start running rest of test suite here! */ - result = GNUNET_OK; - GNUNET_SCHEDULER_shutdown (); + + is = GNUNET_new (struct InterpreterState); + is->keys = keys; + is->commands = commands; + GNUNET_SCHEDULER_add_now (&interpreter_run, + is); }