testing_api_cmd_block_delete.c (10718B)
1 /* 2 This file is part of SYNC 3 Copyright (C) 2014-2026 Taler Systems SA 4 5 SYNC is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as 7 published by the Free Software Foundation; either version 3, or 8 (at your option) any later version. 9 10 SYNC is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public 16 License along with SYNC; see the file COPYING. If not, see 17 <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file testing/testing_api_cmd_block_delete.c 21 * @brief command to delete a block from the sync backend service. 22 * @author Iván Ávalos 23 */ 24 #include "platform.h" 25 #include "sync/sync_service.h" 26 #include "sync/sync_testing_lib.h" 27 #include <taler/taler_util.h> 28 #include <taler/taler_signatures.h> 29 #include <taler/taler_testing_lib.h> 30 #include <gnunet/gnunet_curl_lib.h> 31 #include "testing_api_cmd_block_common.h" 32 33 34 /** 35 * State for a "block delete" CMD. 36 */ 37 struct BlockDeleteState 38 { 39 40 /** 41 * URL of the sync backend. 42 */ 43 const char *sync_url; 44 45 /** 46 * Reference to a command that provides account keys, 47 * block nonce and block hash. 48 */ 49 const char *account_reference; 50 51 /** 52 * Eddsa private key. 53 */ 54 struct SYNC_AccountPrivateKeyP sync_priv; 55 56 /** 57 * Eddsa public key. 58 */ 59 struct SYNC_AccountPublicKeyP sync_pub; 60 61 /** 62 * Nonce of the block to delete. 63 */ 64 struct SYNC_BlockNonce nonce; 65 66 /** 67 * Prev nonce (zero if first block). 68 */ 69 struct SYNC_BlockNonce prev_nonce; 70 71 /** 72 * Next nonce (zero if last block). 73 */ 74 struct SYNC_BlockNonce next_nonce; 75 76 /** 77 * Hash of the block to delete. 78 */ 79 struct GNUNET_HashCode block_hash; 80 81 /** 82 * Expected HTTP status code. 83 */ 84 unsigned int http_status; 85 86 /** 87 * The interpreter state. 88 */ 89 struct TALER_TESTING_Interpreter *is; 90 91 /** 92 * Handle for the library block delete operation. 93 */ 94 struct SYNC_BlockOperation *bop; 95 96 /** 97 * Handle for the library block list operation (first phase). 98 */ 99 struct SYNC_BlockListOperation *blop; 100 101 /** 102 * Number of entries in @e object_uids and @e object_incs. 103 */ 104 unsigned int refs_len; 105 106 /** 107 * Array of object UIDs referenced by this block (array of 108 * @e refs_len, up to #MAX_BLOCK_OBJECT_REFS). 109 */ 110 struct SYNC_ObjectUID object_uids[MAX_BLOCK_OBJECT_REFS]; 111 112 /** 113 * Array of reference count adjustments (array of @e refs_len, 114 * up to #MAX_BLOCK_OBJECT_REFS). 115 */ 116 int16_t object_incs[MAX_BLOCK_OBJECT_REFS]; 117 118 /** 119 * Entry of the preceding neighbour (for its relink signature). 120 */ 121 struct SYNC_BlockListEntry prev_entry; 122 123 /** 124 * True if @e prev_entry is set. 125 */ 126 bool have_prev_entry; 127 128 /** 129 * Entry of the succeeding neighbour (for its relink signature). 130 */ 131 struct SYNC_BlockListEntry next_entry; 132 133 /** 134 * True if @e next_entry is set. 135 */ 136 bool have_next_entry; 137 138 }; 139 140 141 /** 142 * Function called when we're done processing the 143 * block delete. 144 * 145 * @param cls the `struct BlockDeleteState` 146 * @param ud details about the delete operation 147 */ 148 static void 149 block_delete_finished (void *cls, 150 const struct SYNC_BlockOperationDetails *ud) 151 { 152 struct BlockDeleteState *bds = cls; 153 154 bds->bop = NULL; 155 if (ud->http_status != bds->http_status) 156 { 157 TALER_TESTING_unexpected_status (bds->is, 158 ud->http_status, 159 bds->http_status); 160 return; 161 } 162 TALER_TESTING_interpreter_next (bds->is); 163 } 164 165 166 /** 167 * Function called when we're done processing the 168 * block list that precedes the delete. 169 * 170 * @param cls the `struct BlockDeleteState` 171 * @param ld details about the list operation 172 */ 173 static void 174 block_delete_list_finished (void *cls, 175 const struct SYNC_BlockListDetails *ld) 176 { 177 struct BlockDeleteState *bds = cls; 178 179 bds->blop = NULL; 180 if (MHD_HTTP_OK != ld->http_status) 181 { 182 GNUNET_break_op (0); 183 TALER_TESTING_interpreter_fail (bds->is); 184 return; 185 } 186 187 /* Find the block to delete and its neighbours in the list */ 188 { 189 const struct SYNC_BlockListEntry *prev = NULL; 190 const struct SYNC_BlockListEntry *next = NULL; 191 192 for (unsigned int i = 0; i < ld->num_entries; i++) 193 { 194 const struct SYNC_BlockListEntry *e = &ld->entries[i]; 195 196 if ( (0 == GNUNET_memcmp (&e->nonce, 197 &bds->prev_nonce)) || 198 (0 == GNUNET_memcmp (&e->nonce, 199 &bds->next_nonce)) ) 200 { 201 if (0 == GNUNET_memcmp (&e->nonce, 202 &bds->prev_nonce)) 203 prev = e; 204 else 205 next = e; 206 } 207 } 208 209 if (NULL != prev) 210 { 211 bds->prev_entry = *prev; 212 bds->have_prev_entry = true; 213 } 214 if (NULL != next) 215 { 216 bds->next_entry = *next; 217 bds->have_next_entry = true; 218 } 219 } 220 221 { 222 struct SYNC_BlockOperationArgs args = { 223 .nonce = &bds->nonce, 224 .prev_nonce = GNUNET_is_zero (&bds->prev_nonce) 225 ? NULL 226 : &bds->prev_nonce, 227 .next_nonce = GNUNET_is_zero (&bds->next_nonce) 228 ? NULL 229 : &bds->next_nonce, 230 .block_hash = &bds->block_hash, 231 .refs_len = bds->refs_len, 232 .object_uids = bds->object_uids, 233 .object_incs = bds->object_incs, 234 .prev_entry = bds->have_prev_entry 235 ? &bds->prev_entry 236 : NULL, 237 .next_entry = bds->have_next_entry 238 ? &bds->next_entry 239 : NULL, 240 }; 241 242 bds->bop = SYNC_block_delete ( 243 TALER_TESTING_interpreter_get_context (bds->is), 244 bds->sync_url, 245 &bds->sync_priv, 246 &args, 247 &block_delete_finished, 248 bds); 249 if (NULL == bds->bop) 250 { 251 GNUNET_break (0); 252 TALER_TESTING_interpreter_fail (bds->is); 253 } 254 } 255 } 256 257 258 /** 259 * Run a "block delete" CMD. 260 * 261 * @param cls closure. 262 * @param cmd command currently being run. 263 * @param is interpreter state. 264 */ 265 static void 266 block_delete_run (void *cls, 267 const struct TALER_TESTING_Command *cmd, 268 struct TALER_TESTING_Interpreter *is) 269 { 270 struct BlockDeleteState *bds = cls; 271 272 (void) cmd; 273 bds->is = is; 274 275 { 276 const struct TALER_TESTING_Command *ref; 277 278 ref = TALER_TESTING_interpreter_lookup_command (is, 279 bds->account_reference); 280 if (NULL == ref) 281 { 282 GNUNET_break (0); 283 goto fail; 284 } 285 { 286 const struct SYNC_AccountPrivateKeyP *priv; 287 const struct SYNC_AccountPublicKeyP *pub; 288 289 if ( (GNUNET_OK != 290 TALER_TESTING_get_trait_sync_account_priv (ref, 291 &priv)) || 292 (GNUNET_OK != 293 TALER_TESTING_get_trait_sync_account_pub (ref, 294 &pub)) ) 295 { 296 GNUNET_break (0); 297 goto fail; 298 } 299 bds->sync_priv = *priv; 300 bds->sync_pub = *pub; 301 } 302 { 303 const struct SYNC_BlockNonce *nonce; 304 305 if (GNUNET_OK != 306 TALER_TESTING_get_trait_block_nonce (ref, 307 &nonce)) 308 { 309 GNUNET_break (0); 310 goto fail; 311 } 312 bds->nonce = *nonce; 313 } 314 { 315 const struct SYNC_BlockNonce *pn; 316 317 if (GNUNET_OK == 318 TALER_TESTING_get_trait_prev_nonce (ref, 319 &pn)) 320 { 321 bds->prev_nonce = *pn; 322 } 323 } 324 { 325 const struct SYNC_BlockNonce *nn; 326 327 if (GNUNET_OK == 328 TALER_TESTING_get_trait_next_nonce (ref, 329 &nn)) 330 { 331 bds->next_nonce = *nn; 332 } 333 } 334 { 335 const struct GNUNET_HashCode *hash; 336 337 if (GNUNET_OK != 338 TALER_TESTING_get_trait_curr_hash (ref, 339 &hash)) 340 { 341 GNUNET_break (0); 342 goto fail; 343 } 344 bds->block_hash = *hash; 345 } 346 } 347 348 /* Phase 1: fetch the linked list to learn the current state of the 349 block and its neighbours before deleting (their entries are needed 350 for the relink signatures). */ 351 bds->blop = SYNC_block_list ( 352 TALER_TESTING_interpreter_get_context (is), 353 bds->sync_url, 354 &bds->sync_pub, 355 10000, 356 NULL, 357 &block_delete_list_finished, 358 bds); 359 if (NULL == bds->blop) 360 goto fail; 361 362 return; 363 364 fail: 365 GNUNET_break (0); 366 TALER_TESTING_interpreter_fail (is); 367 } 368 369 370 /** 371 * Free the state of a "block delete" CMD, and possibly 372 * cancel it if it did not complete. 373 * 374 * @param cls closure. 375 * @param cmd command being freed. 376 */ 377 static void 378 block_delete_cleanup (void *cls, 379 const struct TALER_TESTING_Command *cmd) 380 { 381 struct BlockDeleteState *bds = cls; 382 383 if (NULL != bds->bop) 384 { 385 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 386 "Command '%s' did not complete (block delete)\n", 387 cmd->label); 388 SYNC_block_operation_cancel (bds->bop); 389 bds->bop = NULL; 390 } 391 if (NULL != bds->blop) 392 { 393 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 394 "Command '%s' did not complete (block list)\n", 395 cmd->label); 396 SYNC_block_list_cancel (bds->blop); 397 bds->blop = NULL; 398 } 399 GNUNET_free (bds); 400 } 401 402 403 struct TALER_TESTING_Command 404 SYNC_TESTING_cmd_block_delete (const char *label, 405 const char *sync_url, 406 const char *account_reference, 407 unsigned int http_status, 408 unsigned int refs_len, 409 const struct SYNC_ObjectUID *object_uids, 410 const int16_t *object_incs) 411 { 412 struct BlockDeleteState *bds; 413 414 GNUNET_assert (refs_len <= MAX_BLOCK_OBJECT_REFS); 415 bds = GNUNET_new (struct BlockDeleteState); 416 bds->sync_url = sync_url; 417 bds->account_reference = account_reference; 418 bds->http_status = http_status; 419 bds->refs_len = refs_len; 420 if (0 < refs_len) 421 { 422 GNUNET_memcpy (bds->object_uids, 423 object_uids, 424 refs_len * sizeof (struct SYNC_ObjectUID)); 425 GNUNET_memcpy (bds->object_incs, 426 object_incs, 427 refs_len * sizeof (int16_t)); 428 } 429 { 430 struct TALER_TESTING_Command cmd = { 431 .cls = bds, 432 .label = label, 433 .run = &block_delete_run, 434 .cleanup = &block_delete_cleanup, 435 }; 436 437 return cmd; 438 } 439 } 440 441 442 /* end of testing_api_cmd_block_delete.c */