testing_api_cmd_block_append.c (7733B)
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_append.c 21 * @brief command to append a block to the sync backend service. 22 * @author Iván Ávalos 23 */ 24 #include "testing_api_cmd_block_common.h" 25 #include <stdbool.h> 26 27 28 /** 29 * Process a reference for a retry upload: inherit keys, nonce 30 * (if not explicitly set), and old_data_hash from the ref's 31 * prev_hash trait. 32 * 33 * @param[in,out] bus state to populate 34 * @param ref reference command to inherit from 35 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure 36 */ 37 static enum GNUNET_GenericReturnValue 38 append_retry_process_ref ( 39 struct BlockUploadState *bus, 40 const struct TALER_TESTING_Command *ref) 41 { 42 if (GNUNET_OK != 43 SYNC_TESTING_inherit_account_keys_ (bus, 44 ref)) 45 return GNUNET_SYSERR; 46 47 /* Inherit block nonce if not explicitly set */ 48 if (GNUNET_is_zero (&bus->nonce)) 49 { 50 const struct SYNC_BlockNonce *nonce; 51 52 if (GNUNET_OK == 53 TALER_TESTING_get_trait_block_nonce (ref, 54 &nonce)) 55 bus->nonce = *nonce; 56 } 57 58 /* Inherit old_data_hash from prev_hash for retry */ 59 if (GNUNET_is_zero (&bus->old_data_hash)) 60 { 61 const struct GNUNET_HashCode *h; 62 63 if (GNUNET_OK == 64 TALER_TESTING_get_trait_prev_hash (ref, 65 &h)) 66 bus->old_data_hash = *h; 67 } 68 69 return GNUNET_OK; 70 } 71 72 73 /** 74 * Process a reference for an append-after: inherit keys, set 75 * prev_nonce from the ref's block_nonce (to chain the new block after 76 * the referenced one), and collect the tail's data for its relink 77 * signature. 78 * 79 * @param[in,out] bus state to populate 80 * @param ref reference command to inherit from 81 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure 82 */ 83 static enum GNUNET_GenericReturnValue 84 append_after_process_ref ( 85 struct BlockUploadState *bus, 86 const struct TALER_TESTING_Command *ref) 87 { 88 const struct SYNC_BlockNonce *nonce; 89 const struct SYNC_BlockNonce *pn; 90 const struct GNUNET_HashCode *h; 91 const struct GNUNET_HashCode *rh; 92 93 if (GNUNET_OK != 94 SYNC_TESTING_inherit_account_keys_ (bus, 95 ref)) 96 return GNUNET_SYSERR; 97 /* Set prev_nonce to chain after the referenced block. If ref has 98 no nonce trait, prev_nonce stays zero (meaning no predecessor — 99 allowed by the API) */ 100 if (GNUNET_OK == 101 TALER_TESTING_get_trait_block_nonce (ref, 102 &nonce)) 103 bus->prev_nonce = *nonce; 104 105 /* The tail's data for its relink signature */ 106 if (GNUNET_OK == 107 TALER_TESTING_get_trait_curr_hash (ref, 108 &h)) 109 { 110 bus->prev_entry.nonce = bus->prev_nonce; 111 bus->prev_entry.hash = *h; 112 bus->have_relink_target = true; 113 } 114 if (GNUNET_OK == 115 TALER_TESTING_get_trait_block_refs_hash (ref, 116 &rh)) 117 bus->prev_entry.refs_hash = *rh; 118 if (GNUNET_OK == 119 TALER_TESTING_get_trait_prev_nonce (ref, 120 &pn)) 121 { 122 bus->prev_entry.prev_nonce = *pn; 123 bus->prev_entry.have_prev_nonce = ! GNUNET_is_zero (pn); 124 } 125 126 return GNUNET_OK; 127 } 128 129 130 /** 131 * Start a block append operation. 132 * 133 * @param ctx for HTTP client request processing 134 * @param sync_url base URL of the Sync server 135 * @param sync_priv private key of the account 136 * @param nonce nonce identifying the block 137 * @param prev_nonce nonce of the preceding block, or NULL 138 * @param next_nonce unused, appends are always at the tail 139 * @param old_data_hash unused, appends have no previous data 140 * @param block_data_size number of bytes in @a block_data 141 * @param block_data the block data 142 * @param refs_len number of entries in @a object_uids and @a object_incs 143 * @param object_uids array of object UIDs referenced by this block 144 * @param object_incs array of reference count adjustments 145 * @param prev_entry the tail's entry, for its relink signature, or NULL 146 * @param cb function to call with the result 147 * @param cb_cls closure for @a cb 148 * @return handle for the operation 149 */ 150 static struct SYNC_BlockOperation * 151 append_start_upload ( 152 struct GNUNET_CURL_Context *ctx, 153 const char *sync_url, 154 const struct SYNC_AccountPrivateKeyP *sync_priv, 155 const struct SYNC_BlockNonce *nonce, 156 const struct SYNC_BlockNonce *prev_nonce, 157 const struct SYNC_BlockNonce *next_nonce, 158 const struct GNUNET_HashCode *old_data_hash, 159 size_t block_data_size, 160 const void *block_data, 161 size_t refs_len, 162 const struct SYNC_ObjectUID *object_uids, 163 const int16_t *object_incs, 164 const struct SYNC_BlockListEntry *prev_entry, 165 SYNC_BlockOperationCallback cb, 166 void *cb_cls) 167 { 168 struct SYNC_BlockOperationArgs args = { 169 .nonce = nonce, 170 .prev_nonce = prev_nonce, 171 .next_nonce = NULL, 172 .old_data_hash = NULL, 173 .block_data_size = block_data_size, 174 .block_data = block_data, 175 .refs_len = refs_len, 176 .object_uids = object_uids, 177 .object_incs = object_incs, 178 .prev_entry = prev_entry, 179 }; 180 181 (void) next_nonce; 182 (void) old_data_hash; 183 return SYNC_block_append (ctx, 184 sync_url, 185 sync_priv, 186 &args, 187 cb, 188 cb_cls); 189 } 190 191 192 struct TALER_TESTING_Command 193 SYNC_TESTING_cmd_block_append (const char *label, 194 const char *sync_url, 195 const char *upload_reference, 196 const struct SYNC_BlockNonce *nonce, 197 unsigned int http_status, 198 const void *block_data, 199 size_t block_data_size, 200 bool retry_upload, 201 unsigned int refs_len, 202 const struct SYNC_ObjectUID *object_uids, 203 const int16_t *object_incs) 204 { 205 struct BlockUploadState *bus; 206 207 GNUNET_assert (refs_len <= MAX_BLOCK_OBJECT_REFS); 208 bus = GNUNET_new (struct BlockUploadState); 209 bus->sync_url = sync_url; 210 bus->upload_reference = upload_reference; 211 if (NULL != nonce) 212 bus->nonce = *nonce; 213 bus->http_status = http_status; 214 bus->block_data = block_data; 215 bus->block_data_size = block_data_size; 216 bus->refs_len = refs_len; 217 if (0 < refs_len) 218 { 219 GNUNET_memcpy (bus->object_uids, 220 object_uids, 221 refs_len * sizeof (struct SYNC_ObjectUID)); 222 GNUNET_memcpy (bus->object_incs, 223 object_incs, 224 refs_len * sizeof (int16_t)); 225 } 226 bus->process_ref = retry_upload 227 ? &append_retry_process_ref 228 : &append_after_process_ref; 229 bus->start_upload = &append_start_upload; 230 { 231 struct TALER_TESTING_Command cmd = { 232 .cls = bus, 233 .label = label, 234 .run = &SYNC_TESTING_block_upload_run_, 235 .cleanup = &SYNC_TESTING_block_upload_cleanup_, 236 .traits = &SYNC_TESTING_block_upload_traits_ 237 }; 238 239 return cmd; 240 } 241 }