Skip to content

Commit 04e9280

Browse files
committed
implement simple recoding and fix decoder uninitialized memory
1 parent 1df25ef commit 04e9280

12 files changed

Lines changed: 705 additions & 586 deletions

File tree

Makefile

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ t/00util/test_utils
2929
EXAMPLES=\
3030
examples/encode\
3131
examples/decode\
32-
examples/carousel
32+
examples/carousel\
33+
examples/tsnc_multipath\
34+
examples/tsnc_sync\
35+
examples/blockchain_gossip
3336

3437
CPPFLAGS = -D_DEFAULT_SOURCE -D_FILE_OFFSET_BITS=64
3538
CFLAGS = -O3 -g -std=c11 -Wall -I. -Iinclude -Ideps/
@@ -59,6 +62,9 @@ t/00util/test_utils: t/00util/test_utils.o $(CORE_OBJ)
5962
examples/encode: examples/encode.o $(OBJ)
6063
examples/decode: examples/decode.o $(OBJ)
6164
examples/carousel: examples/carousel.o $(OBJ)
65+
examples/tsnc_multipath: examples/tsnc_multipath.o $(OBJ)
66+
examples/tsnc_sync: examples/tsnc_sync.o $(OBJ)
67+
examples/blockchain_gossip: examples/blockchain_gossip.o $(OBJ)
6268

6369
check: CPPFLAGS=
6470
check: clean $(TEST_UTILS) $(EXAMPLES)
@@ -122,9 +128,11 @@ check-embedded:
122128
$(MAKE) clean
123129
$(MAKE) libnanorq_core.a CPPFLAGS="$(CPPFLAGS) -DNANORQ_NO_LIBC"
124130
@echo "--- Undefined symbols in libnanorq_core.a ---"
125-
@nm -u libnanorq_core.a | grep -E '\b(malloc|calloc|realloc|free|posix_memalign|__assert_fail)\b' && \
126-
(echo "FAIL: libc symbols found in embedded build" && exit 1) || \
127-
echo "PASS: no libc allocator/assert symbols found"
131+
@if nm -u libnanorq_core.a | grep -E '\b(malloc|calloc|realloc|free|posix_memalign|__assert_fail)\b'; then \
132+
echo "FAIL: libc symbols found in embedded build"; exit 1; \
133+
else \
134+
echo "PASS: no libc allocator/assert symbols found"; \
135+
fi
128136

129137
valgrind: CPPFLAGS=-Wall -Iinclude -Ideps/ -fPIC
130138
valgrind: CFLAGS = -O0 -g -std=c11

examples/blockchain_gossip.c

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#include "nanorq.h"
2+
#include <assert.h>
3+
#include <stdbool.h>
4+
#include <stdio.h>
5+
#include <stdlib.h>
6+
#include <string.h>
7+
8+
#define BLOCK_SIZE_SYMBOLS 100
9+
#define SYMBOL_SIZE 256
10+
#define NUM_NODES 5
11+
12+
typedef struct {
13+
int id;
14+
nanorq *decoder;
15+
struct ioctx *dec_io;
16+
uint8_t *decoded_payload;
17+
bool has_decoded;
18+
uint32_t rx_count;
19+
} p2p_node;
20+
21+
p2p_node *node_new(int id, uint64_t common, uint32_t specific) {
22+
p2p_node *n = calloc(1, sizeof(p2p_node));
23+
n->id = id;
24+
n->decoder = nanorq_decoder_new(common, specific);
25+
assert(n->decoder != NULL);
26+
nanorq_set_max_esi(n->decoder, 1000000);
27+
n->decoded_payload = calloc(1, BLOCK_SIZE_SYMBOLS * SYMBOL_SIZE);
28+
n->dec_io =
29+
ioctx_from_mem(n->decoded_payload, BLOCK_SIZE_SYMBOLS * SYMBOL_SIZE);
30+
return n;
31+
}
32+
33+
void node_receive(p2p_node *n, uint8_t *coefs, uint8_t *payload, uint32_t tag) {
34+
if (n->has_decoded)
35+
return; /* ignore if synced */
36+
37+
n->rx_count++;
38+
39+
/* try adding the symbol */
40+
int res = nanorq_decoder_add_recoded_symbol(n->decoder, payload, tag, coefs,
41+
n->dec_io);
42+
if (res == NANORQ_SYM_ADDED || res == NANORQ_SYM_DUP) {
43+
size_t missing = nanorq_num_missing(n->decoder, 0);
44+
size_t repair = nanorq_num_repair(n->decoder, 0);
45+
if (repair >= missing) {
46+
if (nanorq_repair_block(n->decoder, n->dec_io, 0)) {
47+
n->has_decoded = true;
48+
printf("[Node %d] BLOCK SYNCED! (Received %d packets)\n", n->id,
49+
n->rx_count);
50+
}
51+
}
52+
}
53+
}
54+
55+
int main() {
56+
uint32_t payload_len = BLOCK_SIZE_SYMBOLS * SYMBOL_SIZE;
57+
uint8_t *block_data = malloc(payload_len);
58+
for (uint32_t i = 0; i < payload_len; i++)
59+
block_data[i] = rand() % 256;
60+
61+
struct ioctx *src_io = ioctx_from_mem(block_data, payload_len);
62+
63+
/* miner who mined the block */
64+
nanorq *miner =
65+
nanorq_encoder_new_ex(payload_len, SYMBOL_SIZE, BLOCK_SIZE_SYMBOLS, 1, 1);
66+
printf("[Miner] Mined new block! Size: %d KB. Encoding with TSNC...\n\n",
67+
payload_len / 1024);
68+
69+
uint64_t common = nanorq_oti_common(miner);
70+
uint32_t specific = nanorq_oti_scheme_specific(miner);
71+
72+
/* p2p network topology */
73+
p2p_node *nodes[NUM_NODES];
74+
for (int i = 0; i < NUM_NODES; i++)
75+
nodes[i] = node_new(i, common, specific);
76+
77+
uint8_t *coef_buf = malloc(BLOCK_SIZE_SYMBOLS);
78+
uint8_t *payload_buf = malloc(SYMBOL_SIZE);
79+
80+
int rounds = 0;
81+
bool all_synced = false;
82+
83+
/* simulate network ticks */
84+
uint32_t tag_idx = 0;
85+
while (!all_synced && rounds < 500) {
86+
rounds++;
87+
uint32_t current_tag = nanorq_tag(0, tag_idx++);
88+
89+
/* miner streams to node 0 */
90+
nanorq_generate_recoded_symbol(miner, src_io, 0, rounds, coef_buf,
91+
payload_buf);
92+
node_receive(nodes[0], coef_buf, payload_buf, current_tag);
93+
94+
/* gossip recoded packets to next node */
95+
for (int i = 0; i < NUM_NODES - 1; i++) {
96+
p2p_node *sender = nodes[i];
97+
p2p_node *receiver = nodes[i + 1];
98+
99+
/* generate recoded packet if sender has buffered packets */
100+
if (sender->rx_count > 0 && !receiver->has_decoded) {
101+
/* simulate 10% packet loss */
102+
if ((rand() % 100) > 10) {
103+
uint32_t recoded_tag = nanorq_tag(0, tag_idx++);
104+
if (sender->has_decoded) {
105+
nanorq_generate_recoded_symbol(sender->decoder, sender->dec_io, 0,
106+
tag_idx, coef_buf, payload_buf);
107+
} else {
108+
nanorq_generate_recoded_symbol(sender->decoder, NULL, 0, 0,
109+
coef_buf, payload_buf);
110+
}
111+
node_receive(receiver, coef_buf, payload_buf, recoded_tag);
112+
}
113+
}
114+
}
115+
116+
/* check completion */
117+
all_synced = true;
118+
for (int i = 0; i < NUM_NODES; i++) {
119+
if (!nodes[i]->has_decoded)
120+
all_synced = false;
121+
}
122+
}
123+
124+
printf("\n[Network] Global consensus reached in %d ticks!\n", rounds);
125+
126+
/* verification */
127+
int failed = 0;
128+
for (int i = 0; i < NUM_NODES; i++) {
129+
if (memcmp(block_data, nodes[i]->decoded_payload, payload_len) != 0) {
130+
failed++;
131+
printf("[Verification] Node %d FAILED! Differences:\n", i);
132+
for (uint32_t sym = 0; sym < BLOCK_SIZE_SYMBOLS; sym++) {
133+
if (memcmp(block_data + sym * SYMBOL_SIZE,
134+
nodes[i]->decoded_payload + sym * SYMBOL_SIZE,
135+
SYMBOL_SIZE) != 0) {
136+
printf(" Symbol %d mismatch:\n", sym);
137+
printf(" Src: ");
138+
for (int k = 0; k < 16; k++)
139+
printf("%02x ", block_data[sym * SYMBOL_SIZE + k]);
140+
printf("\n Dec: ");
141+
for (int k = 0; k < 16; k++)
142+
printf("%02x ", nodes[i]->decoded_payload[sym * SYMBOL_SIZE + k]);
143+
printf("\n");
144+
break; /* only print first mismatch per node */
145+
}
146+
}
147+
}
148+
149+
nanorq_free(nodes[i]->decoder);
150+
nodes[i]->dec_io->destroy(nodes[i]->dec_io);
151+
free(nodes[i]->decoded_payload);
152+
free(nodes[i]);
153+
}
154+
155+
if (failed == 0) {
156+
printf("[Verification] SUCCESS: All nodes correctly decoded!\n");
157+
} else {
158+
printf("[Verification] FAILED on %d nodes!\n", failed);
159+
}
160+
161+
free(coef_buf);
162+
free(payload_buf);
163+
free(block_data);
164+
src_io->destroy(src_io);
165+
nanorq_free(miner);
166+
167+
return failed ? 1 : 0;
168+
}

examples/tsnc_multipath.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#include "nanorq.h"
2+
#include <assert.h>
3+
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <string.h>
6+
7+
#define SYMBOL_SIZE 128
8+
#define NUM_SYMBOLS 50
9+
10+
int main() {
11+
uint32_t payload_len = NUM_SYMBOLS * SYMBOL_SIZE;
12+
uint8_t *source_data = malloc(payload_len);
13+
for (uint32_t i = 0; i < payload_len; i++)
14+
source_data[i] = rand() % 256;
15+
16+
struct ioctx *src_io = ioctx_from_mem(source_data, payload_len);
17+
18+
printf("[Source Node] Initializing Encoder (K=%d)\n", NUM_SYMBOLS);
19+
nanorq *enc =
20+
nanorq_encoder_new_ex(payload_len, SYMBOL_SIZE, NUM_SYMBOLS, 1, 1);
21+
assert(enc != NULL);
22+
uint64_t common = nanorq_oti_common(enc);
23+
uint32_t specific = nanorq_oti_scheme_specific(enc);
24+
25+
printf("[Relay 1] Initializing Recoder\n");
26+
nanorq *relay1 = nanorq_decoder_new(common, specific);
27+
nanorq_set_max_esi(relay1, 1000000);
28+
29+
printf("[Relay 2] Initializing Recoder\n");
30+
nanorq *relay2 = nanorq_decoder_new(common, specific);
31+
nanorq_set_max_esi(relay2, 1000000);
32+
33+
printf("[Dest Node] Initializing nanorq Decoder with TSNC capabilities\n");
34+
nanorq *dec = nanorq_decoder_new(common, specific);
35+
assert(dec != NULL);
36+
nanorq_set_max_esi(dec, 1000000);
37+
38+
uint8_t *decoded_payload = calloc(1, payload_len);
39+
struct ioctx *dec_io = ioctx_from_mem(decoded_payload, payload_len);
40+
41+
uint8_t *coef_buf = malloc(NUM_SYMBOLS);
42+
uint8_t *payload_buf = malloc(SYMBOL_SIZE);
43+
44+
/* phase 1: source to relays */
45+
printf("\n--- Phase 1: Source transmitting to Relays ---\n");
46+
uint32_t esi = 0;
47+
uint32_t r1_esi = 0, r2_esi = 0;
48+
for (int i = 0; i < 60; i++) {
49+
nanorq_generate_recoded_symbol(enc, src_io, 0, esi++, coef_buf,
50+
payload_buf);
51+
/* relay 1 gets first half */
52+
if (i < 30) {
53+
uint32_t tag = nanorq_tag(0, r1_esi++);
54+
nanorq_decoder_add_recoded_symbol(relay1, payload_buf, tag, coef_buf,
55+
NULL);
56+
} else {
57+
/* relay 2 gets second half */
58+
uint32_t tag = nanorq_tag(0, r2_esi++);
59+
nanorq_decoder_add_recoded_symbol(relay2, payload_buf, tag, coef_buf,
60+
NULL);
61+
}
62+
}
63+
printf(" Relay 1 buffered packets\n");
64+
printf(" Relay 2 buffered packets\n");
65+
66+
/* phase 2: relays re-encode and transmit to destination */
67+
printf("\n--- Phase 2: Relays Multipath Re-encoding to Destination ---\n");
68+
uint32_t relay1_tx = 0, relay2_tx = 0;
69+
70+
bool has_decoded = false;
71+
uint32_t dest_tag_idx = 0;
72+
while (!has_decoded) {
73+
/* relay 1 transmits with 30% loss */
74+
nanorq_generate_recoded_symbol(relay1, NULL, 0, 0, coef_buf, payload_buf);
75+
relay1_tx++;
76+
if ((double)rand() / RAND_MAX > 0.30) {
77+
uint32_t tag = nanorq_tag(0, dest_tag_idx++);
78+
nanorq_decoder_add_recoded_symbol(dec, payload_buf, tag, coef_buf,
79+
dec_io);
80+
}
81+
82+
size_t missing = nanorq_num_missing(dec, 0);
83+
size_t repair = nanorq_num_repair(dec, 0);
84+
if (repair >= missing && missing > 0) {
85+
if (nanorq_repair_block(dec, dec_io, 0)) {
86+
has_decoded = true;
87+
break;
88+
}
89+
}
90+
91+
/* relay 2 transmits with 50% loss */
92+
nanorq_generate_recoded_symbol(relay2, NULL, 0, 0, coef_buf, payload_buf);
93+
relay2_tx++;
94+
if ((double)rand() / RAND_MAX > 0.50) {
95+
uint32_t tag = nanorq_tag(0, dest_tag_idx++);
96+
nanorq_decoder_add_recoded_symbol(dec, payload_buf, tag, coef_buf,
97+
dec_io);
98+
}
99+
100+
missing = nanorq_num_missing(dec, 0);
101+
repair = nanorq_num_repair(dec, 0);
102+
if (repair >= missing && missing > 0) {
103+
if (nanorq_repair_block(dec, dec_io, 0)) {
104+
has_decoded = true;
105+
break;
106+
}
107+
}
108+
}
109+
110+
printf("\n[Dest Node] Decoding successful!\n");
111+
printf(" Relay 1 Transmitted: %u\n", relay1_tx);
112+
printf(" Relay 2 Transmitted: %u\n", relay2_tx);
113+
114+
if (memcmp(source_data, decoded_payload, payload_len) == 0) {
115+
printf("\n[Verification] SUCCESS: Destination decoded payload exactly "
116+
"matches Source!\n");
117+
} else {
118+
printf("\n[Verification] FAILED: Payload mismatch!\n");
119+
}
120+
121+
free(coef_buf);
122+
free(payload_buf);
123+
free(source_data);
124+
free(decoded_payload);
125+
dec_io->destroy(dec_io);
126+
src_io->destroy(src_io);
127+
nanorq_free(enc);
128+
nanorq_free(dec);
129+
nanorq_free(relay1);
130+
nanorq_free(relay2);
131+
132+
return 0;
133+
}

0 commit comments

Comments
 (0)