2026-01-18 10:56:52 +01:00
|
|
|
#include "amduat/fed/replay.h"
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
static amduat_reference_t make_ref(amduat_hash_id_t hash_id,
|
|
|
|
|
const uint8_t *bytes,
|
|
|
|
|
size_t len) {
|
|
|
|
|
return amduat_reference(hash_id, amduat_octets(bytes, len));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static amduat_fed_record_t make_record(uint32_t domain_id,
|
|
|
|
|
uint64_t logseq,
|
|
|
|
|
uint64_t snapshot_id,
|
|
|
|
|
uint64_t log_prefix,
|
|
|
|
|
amduat_fed_record_type_t type,
|
|
|
|
|
amduat_reference_t ref) {
|
|
|
|
|
amduat_fed_record_t record;
|
|
|
|
|
|
|
|
|
|
memset(&record, 0, sizeof(record));
|
|
|
|
|
record.meta.domain_id = domain_id;
|
|
|
|
|
record.meta.visibility = 1;
|
|
|
|
|
record.meta.has_source = 0;
|
|
|
|
|
record.id.type = type;
|
|
|
|
|
record.id.ref = ref;
|
|
|
|
|
record.logseq = logseq;
|
|
|
|
|
record.snapshot_id = snapshot_id;
|
|
|
|
|
record.log_prefix = log_prefix;
|
|
|
|
|
return record;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test_ordering(void) {
|
|
|
|
|
uint8_t d0[] = {0x00};
|
|
|
|
|
uint8_t d1[] = {0x01};
|
|
|
|
|
uint8_t d2[] = {0x02};
|
|
|
|
|
amduat_fed_record_t records[3];
|
|
|
|
|
amduat_fed_replay_view_t view;
|
|
|
|
|
|
|
|
|
|
records[0] = make_record(1, 5, 1, 10, AMDUAT_FED_REC_ARTIFACT,
|
|
|
|
|
make_ref(1, d1, sizeof(d1)));
|
|
|
|
|
records[1] = make_record(1, 5, 1, 10, AMDUAT_FED_REC_ARTIFACT,
|
|
|
|
|
make_ref(1, d0, sizeof(d0)));
|
|
|
|
|
records[2] = make_record(1, 4, 1, 10, AMDUAT_FED_REC_ARTIFACT,
|
|
|
|
|
make_ref(1, d2, sizeof(d2)));
|
|
|
|
|
|
2026-01-18 12:07:43 +01:00
|
|
|
if (!amduat_fed_replay_build(records, 3, 1, 1, 10, &view)) {
|
2026-01-18 10:56:52 +01:00
|
|
|
fprintf(stderr, "replay failed\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (view.len != 3) {
|
|
|
|
|
fprintf(stderr, "ordering length mismatch\n");
|
|
|
|
|
amduat_fed_replay_view_free(&view);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (view.records[0].logseq != 4 ||
|
|
|
|
|
view.records[1].id.ref.digest.data[0] != 0x00 ||
|
|
|
|
|
view.records[2].id.ref.digest.data[0] != 0x01) {
|
|
|
|
|
fprintf(stderr, "ordering mismatch\n");
|
|
|
|
|
amduat_fed_replay_view_free(&view);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
amduat_fed_replay_view_free(&view);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test_tombstone_scope(void) {
|
|
|
|
|
uint8_t key[] = {0xaa};
|
|
|
|
|
amduat_reference_t ref = make_ref(1, key, sizeof(key));
|
|
|
|
|
amduat_fed_record_t records[3];
|
|
|
|
|
amduat_fed_replay_view_t view;
|
|
|
|
|
|
|
|
|
|
records[0] = make_record(1, 1, 1, 10, AMDUAT_FED_REC_ARTIFACT, ref);
|
|
|
|
|
records[1] = make_record(1, 2, 1, 10, AMDUAT_FED_REC_TOMBSTONE, ref);
|
|
|
|
|
records[2] = make_record(2, 1, 1, 10, AMDUAT_FED_REC_ARTIFACT, ref);
|
|
|
|
|
|
2026-01-18 12:07:43 +01:00
|
|
|
if (!amduat_fed_replay_build(records, 3, 1, 1, 10, &view)) {
|
2026-01-18 10:56:52 +01:00
|
|
|
fprintf(stderr, "replay domain 1 failed\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (view.len != 0) {
|
|
|
|
|
fprintf(stderr, "tombstone scope mismatch (domain 1)\n");
|
|
|
|
|
amduat_fed_replay_view_free(&view);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
amduat_fed_replay_view_free(&view);
|
|
|
|
|
|
2026-01-18 12:07:43 +01:00
|
|
|
if (!amduat_fed_replay_build(records, 3, 2, 1, 10, &view)) {
|
2026-01-18 10:56:52 +01:00
|
|
|
fprintf(stderr, "replay domain 2 failed\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (view.len != 1) {
|
|
|
|
|
fprintf(stderr, "tombstone scope mismatch (domain 2)\n");
|
|
|
|
|
amduat_fed_replay_view_free(&view);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
amduat_fed_replay_view_free(&view);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int test_bounds(void) {
|
|
|
|
|
uint8_t key[] = {0xbb};
|
|
|
|
|
amduat_reference_t ref = make_ref(1, key, sizeof(key));
|
|
|
|
|
amduat_fed_record_t records[2];
|
|
|
|
|
amduat_fed_replay_view_t view;
|
|
|
|
|
|
|
|
|
|
records[0] = make_record(3, 1, 2, 10, AMDUAT_FED_REC_ARTIFACT, ref);
|
|
|
|
|
records[1] = make_record(3, 5, 1, 4, AMDUAT_FED_REC_ARTIFACT, ref);
|
|
|
|
|
|
2026-01-18 12:07:43 +01:00
|
|
|
if (!amduat_fed_replay_build(records, 2, 3, 1, 4, &view)) {
|
2026-01-18 10:56:52 +01:00
|
|
|
fprintf(stderr, "replay bounds failed\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (view.len != 0) {
|
|
|
|
|
fprintf(stderr, "bounds mismatch\n");
|
|
|
|
|
amduat_fed_replay_view_free(&view);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
amduat_fed_replay_view_free(&view);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-18 11:43:03 +01:00
|
|
|
static int test_multi_domain_ordering(void) {
|
|
|
|
|
uint8_t d0[] = {0x00};
|
|
|
|
|
uint8_t d1[] = {0x01};
|
|
|
|
|
uint8_t d2[] = {0x02};
|
|
|
|
|
amduat_fed_record_t records[4];
|
|
|
|
|
amduat_fed_replay_view_t view_a;
|
|
|
|
|
amduat_fed_replay_view_t view_b;
|
|
|
|
|
|
|
|
|
|
records[0] = make_record(1, 2, 1, 10, AMDUAT_FED_REC_ARTIFACT,
|
|
|
|
|
make_ref(1, d2, sizeof(d2)));
|
|
|
|
|
records[1] = make_record(1, 1, 1, 10, AMDUAT_FED_REC_ARTIFACT,
|
|
|
|
|
make_ref(1, d1, sizeof(d1)));
|
|
|
|
|
records[2] = make_record(2, 1, 1, 10, AMDUAT_FED_REC_ARTIFACT,
|
|
|
|
|
make_ref(1, d0, sizeof(d0)));
|
|
|
|
|
records[3] = make_record(2, 2, 1, 10, AMDUAT_FED_REC_ARTIFACT,
|
|
|
|
|
make_ref(1, d2, sizeof(d2)));
|
|
|
|
|
|
2026-01-18 12:07:43 +01:00
|
|
|
if (!amduat_fed_replay_build(records, 4, 1, 1, 10, &view_a)) {
|
2026-01-18 11:43:03 +01:00
|
|
|
fprintf(stderr, "replay domain 1 failed\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-01-18 12:07:43 +01:00
|
|
|
if (!amduat_fed_replay_build(records, 4, 2, 1, 10, &view_b)) {
|
2026-01-18 11:43:03 +01:00
|
|
|
fprintf(stderr, "replay domain 2 failed\n");
|
|
|
|
|
amduat_fed_replay_view_free(&view_a);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (view_a.len != 2 || view_b.len != 2) {
|
|
|
|
|
fprintf(stderr, "multi-domain lengths mismatch\n");
|
|
|
|
|
amduat_fed_replay_view_free(&view_a);
|
|
|
|
|
amduat_fed_replay_view_free(&view_b);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (view_a.records[0].logseq != 1 || view_a.records[1].logseq != 2) {
|
|
|
|
|
fprintf(stderr, "domain 1 ordering mismatch\n");
|
|
|
|
|
amduat_fed_replay_view_free(&view_a);
|
|
|
|
|
amduat_fed_replay_view_free(&view_b);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (view_b.records[0].logseq != 1 || view_b.records[1].logseq != 2) {
|
|
|
|
|
fprintf(stderr, "domain 2 ordering mismatch\n");
|
|
|
|
|
amduat_fed_replay_view_free(&view_a);
|
|
|
|
|
amduat_fed_replay_view_free(&view_b);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
amduat_fed_replay_view_free(&view_a);
|
|
|
|
|
amduat_fed_replay_view_free(&view_b);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-18 10:56:52 +01:00
|
|
|
int main(void) {
|
|
|
|
|
if (test_ordering() != 0) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (test_tombstone_scope() != 0) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
if (test_bounds() != 0) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-01-18 11:43:03 +01:00
|
|
|
if (test_multi_domain_ordering() != 0) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2026-01-18 10:56:52 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|