Skip to content

Commit da5de3c

Browse files
deletion is working and tested
1 parent e276806 commit da5de3c

File tree

3 files changed

+206
-6
lines changed

3 files changed

+206
-6
lines changed

src/forest_test.c

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ typedef struct {
1616
size_t preimage_count;
1717
} add_test_data;
1818

19+
typedef struct {
20+
uint8_t expected_roots[10][32];
21+
size_t expected_roots_len;
22+
uint64_t *leaf_preimages;
23+
size_t preimage_count;
24+
uint64_t *target_values;
25+
size_t n_target_values;
26+
} deletion_test_data;
27+
1928
#define True 1
2029
#define False 0
2130

@@ -137,6 +146,7 @@ void test_add_single() {
137146
ASSERT_ARRAY_EQ(root->hash.hash, leaf.hash, 32);
138147
TEST_END;
139148
}
149+
140150
void test_add_two() {
141151
TEST_BEGIN("add_two");
142152
utreexo_node_hash leaf = {.hash = {0}};
@@ -230,6 +240,7 @@ void test_from_test_cases(void) {
230240
}
231241

232242
void test_grab_node() {
243+
TEST_BEGIN("grab node");
233244
struct utreexo_forest_file *file = NULL;
234245
utreexo_forest_file_init(&file, "test_grab_node.bin");
235246
const unsigned char *expected = (unsigned char[]){
@@ -251,6 +262,170 @@ void test_grab_node() {
251262
utreexo_forest_node *node = NULL, *sibling = NULL, *parent = NULL;
252263
grab_node(&p, &node, &sibling, &parent, 5);
253264
ASSERT_ARRAY_EQ(node->hash.hash, expected, 32);
265+
TEST_END;
266+
}
267+
268+
void test_delete_some() {
269+
TEST_BEGIN("delete single");
270+
struct utreexo_forest_file *file = NULL;
271+
utreexo_forest_file_init(&file, "test_delete_some.bin");
272+
const uint8_t expected_root[32] = {
273+
0x55, 0xe9, 0x91, 0x3e, 0xda, 0xc7, 0x5c, 0xbf, 0x92, 0x30, 0x1c,
274+
0xe5, 0xf9, 0x95, 0xdf, 0x40, 0xd1, 0xe9, 0x3c, 0x0d, 0xde, 0x87,
275+
0x91, 0xbd, 0x75, 0x7a, 0x0f, 0x28, 0xbc, 0x02, 0xf4, 0xa5};
276+
struct utreexo_forest p = {
277+
.data = file,
278+
.roots = {0},
279+
.nLeaf = 0,
280+
};
281+
282+
for (size_t i = 0; i < 8; ++i) {
283+
utreexo_node_hash leaf = {.hash = {0}};
284+
hash_from_u8(leaf.hash, i);
285+
utreexo_forest_add(&p, leaf);
286+
}
287+
288+
delete_single(&p, 0);
289+
delete_single(&p, 2);
290+
delete_single(&p, 9);
291+
ASSERT_ARRAY_EQ(p.roots[3]->hash.hash, expected_root, 32);
292+
TEST_END;
293+
}
294+
295+
static deletion_test_data test_cases[] =
296+
{{
297+
.expected_roots = {{0x33, 0x2c, 0x30, 0x61, 0x88, 0xd3, 0x5e, 0xb2,
298+
0x2e, 0xcb, 0x05, 0xd8, 0xc0, 0x04, 0x46, 0xcd,
299+
0x6a, 0x7a, 0x47, 0x5f, 0x66, 0x15, 0xf4, 0x62,
300+
0x07, 0xcf, 0xaa, 0x71, 0x3b, 0xb3, 0xe6, 0x2c}},
301+
.expected_roots_len = 1,
302+
.leaf_preimages = (uint64_t[]){0, 1, 2, 3, 4, 5, 6, 7},
303+
.preimage_count = 8,
304+
.target_values = (uint64_t[]){1, 7},
305+
.n_target_values = 2,
306+
},
307+
{
308+
.expected_roots = {{0x3b, 0x8b, 0x6e, 0xb2, 0x31, 0x43, 0x70, 0x92,
309+
0xf6, 0xd9, 0xfb, 0xf8, 0xa0, 0x69, 0x6b, 0x7c,
310+
0xb4, 0x46, 0xe4, 0x0f, 0x1b, 0xf8, 0x1d, 0xdb,
311+
0x23, 0xd3, 0xea, 0xbb, 0x30, 0x80, 0xb0, 0xdd}},
312+
.expected_roots_len = 1,
313+
.leaf_preimages = (uint64_t[]){0, 1, 2, 3, 4, 5, 6, 7},
314+
.preimage_count = 8,
315+
.target_values = (uint64_t[]){1, 5, 7},
316+
.n_target_values = 3,
317+
},
318+
{
319+
.expected_roots = {{0x37, 0x96, 0x8e, 0xf7, 0x3d, 0x30, 0xdd, 0xa3,
320+
0x8e, 0xde, 0x83, 0x57, 0xd6, 0x65, 0x93, 0xc7,
321+
0x2a, 0xcd, 0x4f, 0x0e, 0xb9, 0xf7, 0xa1, 0xa9,
322+
0xac, 0xfe, 0xb7, 0xde, 0x85, 0x0c, 0x05, 0xb4},
323+
{0x3c, 0xb9, 0x20, 0xc1, 0x13, 0xe8, 0xce, 0x3a,
324+
0xce, 0x35, 0xfc, 0x83, 0x5e, 0x6f, 0xf8, 0x3a,
325+
0x65, 0x66, 0xc4, 0xc1, 0x27, 0xea, 0x67, 0xee,
326+
0xbc, 0x0f, 0x5d, 0x25, 0xd2, 0x29, 0x5e, 0xa2}},
327+
.expected_roots_len = 2,
328+
.leaf_preimages = (uint64_t[]){0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
329+
10, 11, 12, 13, 14, 15, 16, 17, 18, 19},
330+
.preimage_count = 20,
331+
.target_values = (uint64_t[]){1, 10},
332+
.n_target_values = 2,
333+
},
334+
{
335+
.expected_roots = {{0x37, 0x96, 0x8e, 0xf7, 0x3d, 0x30, 0xdd, 0xa3,
336+
0x8e, 0xde, 0x83, 0x57, 0xd6, 0x65, 0x93, 0xc7,
337+
0x2a, 0xcd, 0x4f, 0x0e, 0xb9, 0xf7, 0xa1, 0xa9,
338+
0xac, 0xfe, 0xb7, 0xde, 0x85, 0x0c, 0x05, 0xb4},
339+
{0x21, 0x32, 0x6d, 0x8a, 0xeb, 0xeb, 0x6e, 0xf7,
340+
0xbc, 0x02, 0xf4, 0x0b, 0xdf, 0x77, 0x8a, 0x02,
341+
0xba, 0x1c, 0x83, 0x6b, 0x25, 0x7f, 0x94, 0x6a,
342+
0xe2, 0x1c, 0xab, 0x2a, 0x6f, 0x95, 0xfa, 0x18}},
343+
.expected_roots_len = 2,
344+
.leaf_preimages = (uint64_t[]){0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
345+
10, 11, 12, 13, 14, 15, 16, 17, 18, 19},
346+
.preimage_count = 20,
347+
.target_values = (uint64_t[]){1, 10, 16},
348+
.n_target_values = 3,
349+
},
350+
{
351+
.expected_roots =
352+
{{0xe4, 0x67, 0x6b, 0xa6, 0x3c, 0x94, 0x58, 0x8b, 0xcb, 0x40, 0x83,
353+
0xe5, 0x47, 0x40, 0x63, 0xb6, 0x33, 0xaa, 0x63, 0x18, 0x97, 0xdd,
354+
0xaa, 0xbd, 0xe7, 0xa4, 0xda, 0x45, 0x93, 0x68, 0x90, 0xcb},
355+
{0xca, 0xe9, 0x21, 0xbb, 0xf6, 0x49, 0xd4, 0xdd, 0x84, 0xc2, 0x52,
356+
0xc5, 0x5c, 0x54, 0x0e, 0x2e, 0x30, 0xc6, 0xc0, 0x0c, 0xb0, 0x89,
357+
0xd9, 0x70, 0x4b, 0xd6, 0x13, 0xec, 0xea, 0x30, 0x86, 0x43},
358+
{0x55, 0xd0, 0xa0, 0xef, 0x8f, 0x5c, 0x25, 0xa9, 0xda, 0x26, 0x6b,
359+
0x36, 0xc0, 0xc5, 0xf4, 0xb3, 0x10, 0x08, 0xec, 0xe8, 0x2d, 0xf2,
360+
0x51, 0x2c, 0x89, 0x66, 0xbd, 0xdc, 0xc2, 0x7a, 0x66, 0xa0},
361+
{0x4d, 0x7b, 0x3e, 0xf7, 0x30, 0x0a, 0xcf, 0x70, 0xc8, 0x92, 0xd8,
362+
0x32, 0x7d, 0xb8, 0x27, 0x2f, 0x54, 0x43, 0x4a, 0xdb, 0xc6, 0x1a,
363+
0x4e, 0x13, 0x0a, 0x56, 0x3c, 0xb5, 0x9a, 0x0d, 0x0f, 0x47}},
364+
.expected_roots_len = 4,
365+
.leaf_preimages =
366+
(uint64_t[]){0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
367+
.preimage_count = 15,
368+
.target_values = (uint64_t[]){1, 10, 5},
369+
.n_target_values = 3,
370+
},
371+
{
372+
.expected_roots =
373+
{{0x35, 0x2d, 0x0d, 0x5e, 0x17, 0x23, 0x16, 0xe7, 0x3b, 0x6d, 0x0d,
374+
0x40, 0x60, 0x5a, 0xd4, 0x11, 0xc7, 0x9b, 0x7e, 0x7c, 0x1e, 0xd0,
375+
0xb4, 0x52, 0x9c, 0x56, 0x5f, 0x08, 0x05, 0x7b, 0xc4, 0xa8},
376+
{0xca, 0xe9, 0x21, 0xbb, 0xf6, 0x49, 0xd4, 0xdd, 0x84, 0xc2, 0x52,
377+
0xc5, 0x5c, 0x54, 0x0e, 0x2e, 0x30, 0xc6, 0xc0, 0x0c, 0xb0, 0x89,
378+
0xd9, 0x70, 0x4b, 0xd6, 0x13, 0xec, 0xea, 0x30, 0x86, 0x43},
379+
{0x55, 0xd0, 0xa0, 0xef, 0x8f, 0x5c, 0x25, 0xa9, 0xda, 0x26, 0x6b,
380+
0x36, 0xc0, 0xc5, 0xf4, 0xb3, 0x10, 0x08, 0xec, 0xe8, 0x2d, 0xf2,
381+
0x51, 0x2c, 0x89, 0x66, 0xbd, 0xdc, 0xc2, 0x7a, 0x66, 0xa0},
382+
{0x4d, 0x7b, 0x3e, 0xf7, 0x30, 0x0a, 0xcf, 0x70, 0xc8, 0x92, 0xd8,
383+
0x32, 0x7d, 0xb8, 0x27, 0x2f, 0x54, 0x43, 0x4a, 0xdb, 0xc6, 0x1a,
384+
0x4e, 0x13, 0x0a, 0x56, 0x3c, 0xb5, 0x9a, 0x0d, 0x0f, 0x47}},
385+
.expected_roots_len = 4,
386+
.leaf_preimages =
387+
(uint64_t[]){0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14},
388+
.preimage_count = 15,
389+
.target_values = (uint64_t[]){10, 5, 16},
390+
.n_target_values = 3,
391+
}};
392+
393+
void test_deletion_cases() {
394+
deletion_test_data *test_case;
395+
size_t n_tests = sizeof(test_cases) / sizeof(deletion_test_data);
396+
for (test_case = &test_cases[0]; test_case != (test_cases + n_tests);
397+
++test_case) {
398+
struct utreexo_forest_file *file = NULL;
399+
utreexo_forest_file_init(&file, "test_deletion_cases.bin");
400+
struct utreexo_forest p = {
401+
.data = file,
402+
.roots = {0},
403+
.nLeaf = 0,
404+
};
405+
for (size_t i = 0; i < test_case->preimage_count; ++i) {
406+
utreexo_node_hash leaf = {.hash = {0}};
407+
hash_from_u8(leaf.hash, test_case->leaf_preimages[i]);
408+
utreexo_forest_add(&p, leaf);
409+
}
410+
for (size_t i = 0; i < test_case->n_target_values; ++i) {
411+
delete_single(&p, test_case->target_values[i]);
412+
}
413+
size_t n_mached = 0;
414+
size_t expected_root_ctr = 0;
415+
for (int root = 63; root >= 0; --root) {
416+
if (expected_root_ctr > test_case->expected_roots_len)
417+
break;
418+
if (p.roots[root] == NULL)
419+
continue;
420+
if (memcmp(test_case->expected_roots[expected_root_ctr],
421+
p.roots[root]->hash.hash, 32) == 0) {
422+
++n_mached;
423+
++expected_root_ctr;
424+
}
425+
}
426+
427+
assert(test_case->expected_roots_len == n_mached);
428+
}
254429
}
255430

256431
int main() {
@@ -260,5 +435,7 @@ int main() {
260435
test_add_many();
261436
test_from_test_cases();
262437
test_grab_node();
438+
test_delete_some();
439+
test_deletion_cases();
263440
return 0;
264441
}

src/map_forest_impl.h

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ static inline void grab_node(struct utreexo_forest *f,
7777

7878
pparent = pnode;
7979

80-
if (pnode->right_child == NULL)
80+
if (pnode->right_child == NULL) {
81+
pnode = NULL;
8182
break;
82-
83+
}
8384
if (mask & pos) {
8485
pnode = pparent->right_child;
8586
psibling = pparent->left_child;
@@ -108,23 +109,30 @@ static inline void recompute_parent_hash(utreexo_forest_node *origin) {
108109
}
109110
}
110111

111-
static inline void delete_single(struct utreexo_forest *f, uint64_t pos) {
112+
static inline int delete_single(struct utreexo_forest *f, uint64_t pos) {
112113
utreexo_forest_node *pnode, *psibling, *pparent;
113114

114115
node_offset offset = detect_offset(pos, f->nLeaf);
115116
grab_node(f, &pnode, &psibling, &pparent, pos);
116117

117-
if (pparent == NULL)
118+
if (!pnode)
119+
return -1;
120+
121+
if (pparent == NULL) {
118122
f->roots[offset.tree] = NULL;
123+
return 0;
124+
}
119125

120126
if (pparent->parent != NULL) {
121127
if (pparent->parent->right_child == pparent)
122128
pparent->parent->right_child = psibling;
123129
else
124130
pparent->parent->left_child = psibling;
125-
return;
131+
} else {
132+
f->roots[offset.tree] = psibling;
126133
}
127-
f->roots[offset.tree] = psibling;
134+
recompute_parent_hash(psibling);
135+
return 0;
128136
}
129137

130138
#endif

src/mmap_forest.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,19 @@ static inline void utreexo_forest_add(struct utreexo_forest *p,
2828
/* Frees a forest. */
2929
static inline void utreexo_forest_free(struct utreexo_forest *p);
3030

31+
/* Deletes a single node from a forest.
32+
*
33+
* This function returns an integer representing whether the operations was
34+
* successful. 0 means success, -1 means this node doesn't exist in the current
35+
* forest
36+
*/
37+
static inline int delete_single(struct utreexo_forest *f, uint64_t pos);
38+
39+
/* Walks up the tree and recompute the node hashes */
40+
static inline void recompute_parent_hash(utreexo_forest_node *origin);
41+
42+
static inline void grab_node(struct utreexo_forest *f,
43+
utreexo_forest_node **node,
44+
utreexo_forest_node **sibling,
45+
utreexo_forest_node **parent, uint64_t pos);
3146
#endif // MMAP_FOREST_H

0 commit comments

Comments
 (0)