-
Notifications
You must be signed in to change notification settings - Fork 1
/
lunes.c
executable file
·1272 lines (1139 loc) · 59.2 KB
/
lunes.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* ##############################################################################################
* Advanced RTI System, ARTÌS http://pads.cs.unibo.it
* Large Unstructured NEtwork Simulator (LUNES)
*
* Description:
* For a general introduction to LUNES implmentation please see the
* file: mig-agents.c
*
* Authors:
* First version by Gabriele D'Angelo <g.dangelo@unibo.it>
*
############################################################################################### */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <math.h>
#include <ctype.h>
#include <assert.h>
#include <ini.h>
#include <ts.h>
#include <rnd.h>
#include <gaia.h>
#include <rnd.h>
#include <values.h>
#include "utils.h"
#include "user_event_handlers.h"
#include "lunes.h"
#include "lunes_constants.h"
#include "entity_definition.h"
/* ************************************************************************ */
/* L O C A L V A R I A B L E S */
/* ************************************************************************ */
FILE * fp_print_trace; // File descriptor for simulation trace file
unsigned short env_max_ttl = MAX_TTL; // TTL of newly created messages
/* ************************************************************************ */
/* E X T E R N A L V A R I A B L E S */
/* ************************************************************************ */
extern hash_t hash_table, *table; /* Global hash table of simulated entities */
extern hash_t sim_table, *stable; /* Hash table of locally simulated entities */
extern double simclock; /* Time management, simulated time */
extern TSeed Seed, *S; /* Seed used for the random generator */
extern char * TESTNAME; /* Test name */
extern int NSIMULATE; /* Number of Interacting Agents (Simulated Entities) per LP */
extern int NLP; /* Number of Logical Processes */
// Simulation control
extern unsigned short env_dissemination_mode; /* Dissemination mode */
extern float env_broadcast_prob_threshold; /* Dissemination: conditional broadcast, probability threshold */
extern unsigned int env_cache_size; /* Cache size of each node */
extern float env_freerider_prob; /* Probability that a given node is a free-rider */
extern float env_fixed_prob_threshold; /* Dissemination: fixed probability, probability threshold */
extern float env_dandelion_fluff_steps; /* Dissemination: dandelion, number of stem steps */
#ifdef DEGREE_DEPENDENT_GOSSIP_SUPPORT
extern unsigned int env_probability_function; /* Probability function for Degree Dependent Gossip */
extern double env_function_coefficient; /* Coefficient of the probability function */
#endif
extern float env_global_hashrate; /* Total Hashrate of Bitcoin Network in H/min */
extern double env_difficulty; /* Actual blockchain network difficulty */
extern int * selfish; /* Used for the selfish mining */
extern int number_of_heads; /* Number of forks is kept track in the system. The head is the last block of a chain */
extern int number_dos_nodes; /* dos attackers that don't forward victim messages */
extern int victim;
extern unsigned short env_max_ttl; /* TTL of new messages */
int dand_plus_waiting = 5;
int actual_dos_nodes;
/* ************************************************************************ */
/* S U P P O R T F U N C T I O N S */
/* ************************************************************************ */
/*if the block with the given ID is a head block of a fork his index (of the heads list) is return; otherwise -1 is returned
*
* @param[in] heads: array of pointer to head-blocks
* @param[in] id: id of the block to be found
*/
int is_in_heads (Block ** heads , int id){
int ret = -1;
for (int i =0; i<number_of_heads; i++){
if (heads[i] != NULL /*&& sizeof(heads[i])==sizeof(Block *)*/){
// fprintf(stdout, "%s\n", heads[i]);
if (heads[i]->id == id){
ret = i;
break;
}
}
else {
break;
}
}
return ret;
}
/*if the block with the given ID is in the blockchain his index (of the blocks list) is return; otherwise -1 is returned
*
* @param[in] blockchain: Pointer to the blockchain
* @param[in] id: id whose index has to be found
* @param[in] latest: index of the latest element inserted in the blockchain
*/
int getIndexById (Block* blockchain, int latest, int id){
int res = -1;
for (int i= latest; i >= 0; i--){ //starting from the latest index in the blockchain
if (blockchain[i].id == id){
res = i;
break;
}
}
return res;
}
// A new head block is declared.
void replace_heads (Block ** heads, int old, Block * newBlock ){
heads[old] = newBlock;
}
//Like replace_heads but it puts the new block as the first element of the heads list.
//That's because this way the nodes can continue the chain where their blocks appear
//(under the same position the block with the smallest index is selected first)
void replace_heads_first (Block ** heads, int old, Block * newBlock ){
heads [old] = heads [0];
heads [0] = newBlock;
}
/*once you find a block whose position is greater than parameter position, the block and his index in the blocks list is returned
*
* @param[in] blockchain: Pointer to the blockchain
* @param[in] from: index to start the iteration from
* @param[in] latest: index of the latest element inserted in the blockchain
* @param[in] position: looking for blocks whose position is >= than this int
*/
tTuple find_block_given_position (Block* blockchain, int from, int latest, int position){
Block * given_block = NULL;
int i;
for (i= from; i <= latest; i++){
if (blockchain[i].position >= position){
given_block = &blockchain[i];
break;
}
}
tTuple res = {given_block, i};
return res;
}
/*the index of the head-block with the greater position is returned
*
* @param[in] heads: array of pointers to head-blocks
*/
int heads_greater_position (Block ** heads){
int max = -1;
int res = -1;
for (int i = 0; i<number_of_heads; i++){
if (heads[i] != NULL){
if (heads[i]->position > max && heads[i]->position > 0){
max = heads[i]->position;
res = i;
}
}
else {
break;
}
}
return res;
}
/*Given an id of a block, the index of the next block is returned
*
* @param[in] blockchain: Pointer to the blockchain
* @param[in] id: id whose index of the next block has to be found
* @param[in] latest: index of the latest element inserted in the blockchain
*/
int is_next_in_blockchain (Block * blockchain, int latest, int id){
int ret = -1;
for (int i = 0; i < latest; i++){
if (blockchain[i].prevId == id){
ret = i;
break;
}
}
return ret;
}
/*The smallest fork is replaced with a new one, is not kept track anymore of the head-block of the 11th longest chain
*
* @param[in] heads: array of pointers to head-blocks
* @param[in] newBlock: candidate to become a new head-block
*/
void add_heads (Block ** heads, Block * newBlock ){
int del = minimum_pos(heads);
if (heads[del] != NULL){
if (heads[del]->position < newBlock->position){
replace_heads(heads, del, newBlock);
}
}else{
replace_heads(heads, del, newBlock);
}
}
/*return the index (in the heads list) of the head block with the smallest position
*
* @param[in] heads: array of pointers to head-blocks
*/
int minimum_pos (Block ** heads){
int position = 0;
int minimum = MAXINT;
int tmp;
for (tmp = 0; tmp < number_of_heads; tmp++){
if (heads[tmp] == NULL){
return tmp;
} else {
if (heads[tmp]->position < minimum) {
minimum = heads[tmp]->position;
position = tmp;
}
}
}
return(position);
}
/*If a block is the blockchain the index of the blocks list is returned, otherwise -1 is returned
*
* @param[in] blockchain: Pointer to the blockchain
* @param[in] id: id to find
* @param[in] latest: index of the latest element inserted in the blockchain
*/
int is_in_blockchain (Block * blockchain, int id, int latest){
int ret = -1;
for (int i =0; i < latest; i++){
if (blockchain[i].id == id){
ret = i;
break;
}
}
return ret;
}
#ifdef TXDEBUG
/*! \brief Support function to print the entire blockchain of a node
*
* @param[in] b: Pointer to the node's blockchain
* @param[in] n: Latest block
* @param[in] nodeid: ID of the node
*/
void print_blockchain(Block *b, int n, int nodeid) {
fprintf(stdout, "BLOCKCHAIN NODE %d\n", nodeid);
for (int i = 0; i <= n; ++i) {
fprintf(stdout, "BLOCK: %d, lttrans: %d\n", i, b[i].latesttrans);
for (int t = 0; t < b[i].latesttrans; ++t) {
fprintf(stdout, "\t BLOCK: %d, txid: %d\n", i, b[i].trans[t].id);
}
}
fprintf(stdout, "END BLOCKCHAIN NODE %d\n", nodeid);
fflush(stdout);
}
/*! \brief Inserts a new transaction from the network inside the latest block
*
* @param[in] b: Pointer to the node's blockchain
* @param[in] n: Index of latest block
* @param[in] from: Id of the sender (fake id)
* @param[in] to: ID of the receiver (fake id)
* @param[in] id: ID of the transaction (fake id)
*/
void lunes_trans_insert(Block *b, int n, int from, int to, int id) {
int num = b[n].latesttrans;
if (num < 1500 - 1) {
b[n].latesttrans = num + 1;
b[n].trans[num].id = id;
}
}
/*! \brief Boolean, verifies if the received transaction is already in the local cache of the node
*
* @param[in] b: Pointer to the node's blockchain
* @param[in] n: Index of latest block
* @param[in] id: ID of the transaction
* @return True or False
*/
int lunes_trans_is_known(Block *b, int n, int id) {
int retvalue = 0;
int tmp;
for (int i = 0; i <= n && retvalue == 0; ++i) {
for (tmp = 0; tmp < b[i].latesttrans; tmp++) {
if (b[i].trans[tmp].id == id) {
retvalue = 1;
break;
}
}
}
return(retvalue);
}
#endif
/*! \brief Used to calculate the forwarding probability value for a given node
*/
#ifdef DEGREE_DEPENDENT_GOSSIP_SUPPORT
double lunes_degdependent_prob(unsigned int deg) {
double prob = 0.0;
switch (env_probability_function) {
// Function 2
case 2:
prob = 1.0 / log(env_function_coefficient * deg);
break;
// Function 1
case 1:
prob = 1.0 / pow(deg, env_function_coefficient);
break;
default:
fprintf(stdout, "%12.2f FATAL ERROR, function: %d does NOT exist!\n", simclock, env_probability_function);
fflush(stdout);
exit(-1);
break;
}
/*
* The probability is defined in the range [0, 1], to get full dissemination some functions require that the negative
* results are treated as "true" (i.e. 1)
*/
if ((prob < 0) || (prob > 1)) {
prob = 1;
}
return(prob);
}
#endif
/*! \brief Used to forward a received message to all (or some of)
* the neighbors of a given node. BlockMsg have max priority
* so all node will broadcast this messages.
* Transactions are regulated by the dissemination protocol
* implementation.
*
* @param[in] node: The node doing the forwarding
* @param[in] msg: Message to forward
* @param[in] ttl: TTL of the message
* @param[in] timestamp: Timestamp of message's arrival
* @param[in] creator: Node sender
* @param[in] forwarder: Agent forwarder
*/
void lunes_real_forward(hash_node_t *node, Msg *msg, unsigned short ttl, float timestamp, unsigned int creator, unsigned int forwarder) {
// Iterator to scan the whole state hashtable of neighbors
GHashTableIter iter;
gpointer key, destination;
float threshold; // Tmp, used for probabilistic-based dissemination algorithms
hash_node_t * sender, *receiver; // Sender and receiver nodes in the global hashtable
int txid, from = 2, to = 1;
switch (msg->type) {
// BlockMsg is always disseminated to all neighbors
case 'B':
g_hash_table_iter_init(&iter, node->data->state);
// All neighbors
while (g_hash_table_iter_next(&iter, &key, &destination)) {
sender = hash_lookup(stable, node->data->key); // This node
receiver = hash_lookup(table, *(unsigned int *)destination); // The neighbor
// The original forwarder of this message and its creator are exclueded
// from this dissemination
if ((receiver->data->key != forwarder) && (receiver->data->key != creator)) {
execute_block(simclock + FLIGHT_TIME, sender, receiver, ttl, msg->block.block_static.minedblock, timestamp, creator);
}
}
break;
// TransMsg is regulated by the dissemination choise
case 'T':
// Dissemination mode for the forwarded messages (dissemination algorithm)
switch (env_dissemination_mode) {
case BROADCAST:
// The message is forwarded to ALL neighbors of this node
// NOTE: in case of probabilistic broadcast dissemination this function is called
// only if the probabilities evaluation was positive
g_hash_table_iter_init(&iter, node->data->state);
// All neighbors
while (g_hash_table_iter_next(&iter, &key, &destination)) {
sender = hash_lookup(stable, node->data->key); // This node
receiver = hash_lookup(table, *(unsigned int *)destination); // The neighbor
// The original forwarder of this message and its creator are exclueded
// from this dissemination
if ((receiver->data->key != forwarder) && (receiver->data->key != creator)) {
txid = msg->trans.trans_static.transid;
execute_trans(simclock + FLIGHT_TIME, sender, receiver, ttl, txid, from, to, timestamp, creator);
}
}
break;
case DANDELION:
case DANDELIONPLUS:
g_hash_table_iter_init (&iter, node->data->state);
txid = msg->trans.trans_static.transid;
if (ttl >= env_dandelion_fluff_steps ){ //stem phase
sender = hash_lookup(stable, node->data->key); // This node
destination = hash_table_random_key(node->data->state);
receiver = hash_lookup(table, *(unsigned int *)destination); // The neighbor
execute_trans (simclock + FLIGHT_TIME, sender, receiver, ttl, txid, from, to, timestamp, creator);
} else { //fluff phase, sending messages to everyone, except the forwarder
while (g_hash_table_iter_next (&iter, &key, &destination)) {
sender = hash_lookup(stable, node->data->key); // This node
receiver = hash_lookup(table, *(unsigned int *)destination); // The neighbor
if (receiver->data->key != forwarder )
execute_trans (simclock + FLIGHT_TIME, sender, receiver, ttl, txid, from, to, timestamp, creator);
}
}
break;
case GOSSIP_FIXED_PROB:
// In this case, all neighbors will be analyzed but the message will be
// forwarded only to some of them
g_hash_table_iter_init(&iter, node->data->state);
// All neighbors
while (g_hash_table_iter_next(&iter, &key, &destination)) {
// Probabilistic evaluation
threshold = RND_Interval(S, (double)0, (double)100);
if (threshold <= env_fixed_prob_threshold) {
sender = hash_lookup(stable, node->data->key); // This node
receiver = hash_lookup(table, *(unsigned int *)destination); // The neighbor
// The original forwarder of this message and its creator are exclueded
// from this dissemination
if ((receiver->data->key != forwarder) && (receiver->data->key != creator)) {
txid = msg->trans.trans_static.transid;
execute_trans(simclock + FLIGHT_TIME, sender, receiver, ttl, txid, from, to, timestamp, creator);
}
}
}
break;
#ifdef DEGREE_DEPENDENT_GOSSIP_SUPPORT
// Degree Dependent dissemination algorithm
case DEGREE_DEPENDENT_GOSSIP:
g_hash_table_iter_init(&iter, node->data->state);
// All neighbors
while (g_hash_table_iter_next(&iter, &key, &destination)) {
sender = hash_lookup(stable, node->data->key); // This node
receiver = hash_lookup(table, *(unsigned int *)destination); // The neighbor
// The original forwarder of this message and its creator are excluded
// from this dissemination
if ((receiver->data->key != forwarder) && (receiver->data->key != creator)) {
// Probabilistic evaluation
threshold = (RND_Interval(S, (double)0, (double)100)) / 100;
// If the eligible recipient has less than 3 neighbors, its reception probability is 1. However,
// if its value of num_neighbors is 0, it means that I don't know the dimension of
// that node's neighborhood, so the threshold is set to 1/n, being n
// the dimension of my neighborhood
if (((value_element *)destination)->num_neighbors < 3) {
// Note that, the startup phase (when the number of neighbors is not known) falls in
// this case (num_neighbors = 0)
// -> full dissemination
txid = msg->trans.trans_static.transid;
execute_trans(simclock + FLIGHT_TIME, sender, receiver, ttl, txid, from, to, timestamp, creator);
}
// Otherwise, the probability is evaluated according to the function defined by the
// environment variable env_probability_function
else{
if (threshold <= lunes_degdependent_prob(((value_element *)destination)->num_neighbors)) {
txid = msg->trans.trans_static.transid;
execute_trans(simclock + FLIGHT_TIME, sender, receiver, ttl, txid, from, to, timestamp, creator);
}
}
}
}
break;
#endif
default:
fprintf(stdout,
"%12.2f FATAL ERROR, the dissemination mode [%2d] is NOT implemented in this version of LUNES!!!\n",
simclock,
env_dissemination_mode);
fprintf(stdout,
"%12.2f NOTE: all the adaptive protocols require compile time support: see the ADAPTIVE_GOSSIP_SUPPORT define in sim-parameters.h\n",
simclock);
fflush(stdout);
exit(-1);
break;
}
break;
}
}
/*! \brief Dissemination protocol implementation.
* A new message has been received from a neighbor,
* it is necessary to forward it in some way
*
* @param[in] node: The node doing the forwarding
* @param[in] msg: Message to forward
* @param[in] ttl: TTL of the message
* @param[in] timestamp: Timestamp of message's arrival
* @param[in] creator: Node sender
* @param[in] forwarder: Agent forwarder
*/
void lunes_forward_to_neighbors(hash_node_t *node, Msg *msg, unsigned short ttl, float timestamp, unsigned int creator, unsigned int forwarder) {
float threshold; // Tmp, probabilistic evaluation
// Dissemination mode for the forwarded messages
switch (env_dissemination_mode) {
case BROADCAST:
// Probabilistic evaluation
threshold = RND_Interval(S, (double)0, (double)100);
if (threshold <= env_broadcast_prob_threshold) {
lunes_real_forward(node, msg, ttl, timestamp, creator, forwarder);
}
break;
case GOSSIP_FIXED_PROB:
case DANDELION:
case DANDELIONPLUS:
lunes_real_forward(node, msg, ttl, timestamp, creator, forwarder);
break;
#ifdef DEGREE_DEPENDENT_GOSSIP_SUPPORT
case DEGREE_DEPENDENT_GOSSIP:
lunes_real_forward(node, msg, ttl, timestamp, creator, forwarder);
break;
#endif
default:
fprintf(stdout, "%12.2f FATAL ERROR, the dissemination mode [%2d] is NOT implemented in this version of LUNES!!!\n", simclock, env_dissemination_mode);
fprintf(stdout, "%12.2f NOTE: all the adaptive protocols require compile time support: see the ADAPTIVE_GOSSIP_SUPPORT define in sim-parameters.h\n", simclock);
fflush(stdout);
exit(-1);
break;
}
}
/*! \brief Dissemination protocol implementation for transactions.
* A new message has been generated in this node
* and now it is propagated to (some) neighbors
*
* @param[in] node: The node doing the sending
* @param[in] txid: ID of the transaction
* @param[in] from: ID of the sender (fake ID)
* @param[in] to: ID of the receiver (fake ID)
*/
void lunes_send_trans_to_neighbors(hash_node_t *node, int txid, int from, int to) {
// Iterator to scan the whole state hashtable of neighbors
GHashTableIter iter;
gpointer key, destination;
// All neighbors
g_hash_table_iter_init(&iter, node->data->state);
while (g_hash_table_iter_next(&iter, &key, &destination)) {
// It's a standard trans message
execute_trans(simclock + FLIGHT_TIME, hash_lookup(stable, node->data->key), hash_lookup(table, *(unsigned int *)destination), env_dandelion_fluff_steps - 1, txid, from, to, simclock, node->data->key);
}
}
/*! \brief Dissemination protocol implementation for mined blocks.
* A new block has been mined in this node
* and now it is propagated to (some) neighbors
*
* @param[in] node: The node doing the sending
* @param[in] b: Block to forward
*/
void lunes_send_block_to_neighbors(hash_node_t *node, Block *b) {
// Iterator to scan the whole state hashtable of neighbors
GHashTableIter iter;
gpointer key, destination;
// All neighbors
g_hash_table_iter_init(&iter, node->data->state);
while (g_hash_table_iter_next(&iter, &key, &destination)) {
// It's a standard trans message
execute_block(simclock + FLIGHT_TIME, hash_lookup(stable, node->data->key), hash_lookup(table, *(unsigned int *)destination), env_max_ttl, b, simclock, node->data->key);
}
}
/*! \brief Dissemination protocol implementation for mined blocks.
* A new block has been mined in this node
* and now it is propagated to (some) neighbors
*
* @param[in] node: The node doing the sending
* @param[in] b: Blockchain pointer
* @param[in] dest: Node recipient
*/
void lunes_responde_ask_block(hash_node_t *node, Block *b, int dest) {
BlockMsg msg;
unsigned int message_size;
// Defining the message type
msg.block_static.type = 'B';
msg.block_static.timestamp = simclock;
msg.block_static.ttl = 2;
msg.block_static.minedblock = b;
msg.block_static.creator = node->data->key;
// To reduce the network overhead, only the used part of the message is really sent
message_size = sizeof(struct _block_static_part);
// Buffer checkABRABR
if (message_size > BUFFER_SIZE) {
fprintf(stdout, "%12.2f FATAL ERROR, the outgoing BUFFER_SIZE is not sufficient!\n", simclock);
fflush(stdout);
exit(-1);
}
#ifdef ASKBLOCKDEBUG
// clock - nodeid - blockid - tonode
fprintf(stdout, "ABR: %.0f,%d,%d,%d,%d\n", simclock, node->data->key, b->id, dest, b->position);
#endif
// Real send
GAIA_Send(node->data->key, dest, simclock + FLIGHT_TIME, (void *)&msg, message_size);
}
/* ----------------------- GRAPHVIZ DOT FILES SUPPORT --------------------- */
/*! \brief Support function for the parsing of graphviz dot files,
* used for loading the graphs (i.e. network topology)
*/
void lunes_dot_tokenizer(char *buffer, int *source, int *destination) {
char *token;
int i = 0;
token = strtok(buffer, "--");
do {
i++;
if (i == 1) {
*source = atoi(token);
}
if (i == 2) {
token[strlen(token) - 1] = '\0';
*destination = atoi(token);
}
} while ((token = strtok(NULL, "--")));
}
/*! \brief Parsing of graphviz dot files,
* used for loading the graphs (i.e. network topology)
*/
void lunes_load_graph_topology() {
FILE *dot_file;
char buffer[1024];
int source = 0,
destination = 0;
hash_node_t *source_node,
*destination_node;
value_element val;
// What's the file to read?
sprintf(buffer, "%s%s", TESTNAME, TOPOLOGY_GRAPH_FILE);
dot_file = fopen(buffer, "r");
// Reading all of it
while (fgets(buffer, 1024, dot_file) != NULL) {
// Parsing line by line
lunes_dot_tokenizer(buffer, &source, &destination);
// I check all the edges defined in the dot file to build up "link messages"
// between simulated entities in the simulated network model
// Is the source node a valid simulated entity?
if ((source_node = hash_lookup(stable, source))) {
// Is destination vertex a valid simulated entity?
if ((destination_node = hash_lookup(table, destination))) {
#ifdef AG_DEBUG
fprintf(stdout, "%12.2f node: [%5d] adding link to [%5d]\n", simclock, source_node->data->key, destination_node->data->key);
#endif
// Creating a link between simulated entities (i.e. sending a "link message" between them)
execute_link(simclock + FLIGHT_TIME, source_node, destination_node);
// Initializing the extra data for the new neighbor
val.value = destination;
// I've to insert the new link (and its extra data) in the neighbor table of this sender,
// the receiver will do the same when receiving the "link request" message
// Adding a new entry in the local state of the sender
// first entry = key
// second entry = value
// note: no duplicates are allowed
if (add_entity_state_entry(destination, &val, source, source_node) == -1) {
// Insertion aborted, the key is already in the hash table
fprintf(stdout, "%12.2f node: FATAL ERROR, [%5d] key %d (value %d) is a duplicate and can not be inserted in the hash table of local state\n", simclock, source, destination, destination);
fflush(stdout);
exit(-1);
}
}else {
fprintf(stdout, "%12.2f FATAL ERROR, destination: %d does NOT exist!\n", simclock, destination);
fflush(stdout);
exit(-1);
}
}
}
fclose(dot_file);
}
/* ************************************************************************ */
/* L U N E S U S E R L E V E L H A N D L E R S */
/* ************************************************************************ */
/*! \brief Calculate the probability of mining a block in time 'time_min' minutes with
* an hashrate percentage 'hashrate' of the total hashrate
*/
double mining_probability(double hashrate, double time_min) {
int t = (int)time_min % 10;
t=6;
return((((hashrate * env_global_hashrate / 100.0) * t) / (HASHPOW * env_difficulty)));
}
/****************************************************************************
*! \brief LUNES_CONTROL: node activity for the current timestep
* @param[in] node: Node that execute actions
*/
void lunes_user_control_handler(hash_node_t *node) {
if (simclock == INTERMEDIATE_STEPS){
GHashTableIter iter;
gpointer key, destination;
g_hash_table_iter_init(&iter, node->data->state);
int count = 0;
// All neighbors
while (g_hash_table_iter_next(&iter, &key, &destination)) {
count = count +1;
}
node->data->num_neighbors = count;
}
if ((int) simclock % INTERMEDIATE_STEPS == 0) {
int ltblock = node->data->latestblock; //index of latest block
// Check if the node has mined this block
if (node->data->miner) {
double random_mine = RND_Interval(S, 0.0, 1.0);
double p = mining_probability(node->data->hashrate, simclock);
// Avoid luck
if (p > random_mine /*&& node->data->internal_timer > 2*/) {
Block *b = &node->data->s_state.blockchain[ltblock];
int newId = RND_Interval(S, 0, MAXINT - 1);
if (ltblock < 3000 - 1){ //with rispect to the non-forking version the blockchain size is increased, due to foking version producing more blocks
b->id = newId;
int headPos= heads_greater_position(node->data->s_state.heads); //we want to continue the longest chain so we get its head block
if ( headPos >= 0){ //adding the block to the longest chain
Block ** heads= node->data->s_state.heads; //array of pointers to head-blocks
Block * thatBlock = heads[headPos]; //head block of the longest chain
b->prevId = thatBlock->id; //continuing the longest chain
b->position = thatBlock->position + 1; //position = position of the previous node + 1
replace_heads_first (node->data->s_state.heads, headPos, b); //update the main chain. The head is now the new mined node
} else { //in case still no chain exists
b->prevId = -1; //first block of a chain has -1 as previous block index
b-> position = 1; //and 1 as position
replace_heads_first (node->data->s_state.heads, 0, b); //new block now replaces its previous block as head-block
}
node->data->latestblock += 1; //number of blocks memorized in the blockchain increased by 1
}
if (node->data->attackerid == node->data->key && selfish[2] >= 0) {
// clock - nodeid - blockminedid - hashrate
//underscore characted added in order to facilitate the recognition of the IDs
//fprintf(stdout, "BSS: %.0f,%d,%d,%d,%f\n", simclock, node->data->key, b->id, b->position, node->data->hashrate);
// Update private chain
selfish[0] = newId;
selfish[2] += 1;
if (selfish[2] >= 3) { //2 nodes in advantages, then propagating the mined nodes through the network
//Head block and his previous block are spread through the network.
fprintf(stdout, "possible selfish successful %d %d %d %d\n", selfish[0], selfish[1], selfish[2], selfish[3]);
int ind = getIndexById (&node->data->s_state.blockchain[0], node->data->latestblock, newId);
int indToSpread = getIndexById (&node->data->s_state.blockchain[0], node->data->latestblock, b->prevId);
Block * bToSpread = &node->data->s_state.blockchain[indToSpread];
//all the blocks not revealed has to be spread
while (bToSpread->position > selfish[3]){ //to check if there are previous block in the private blockchain that were not spread
lunes_send_block_to_neighbors(node, &node->data->s_state.blockchain[indToSpread]);
fprintf(stdout, "BS: %.0f,%d,_%d,%d,%f,%d\n", simclock, node->data->key, bToSpread->id, bToSpread->prevId, node->data->hashrate, bToSpread-> position);
if (bToSpread->prevId == -1){
break;
}
else {
indToSpread = getIndexById (&node->data->s_state.blockchain[0], node->data->latestblock, bToSpread->prevId);
bToSpread = &node->data->s_state.blockchain[indToSpread];
}
}
// lunes_send_block_to_neighbors(node, &node->data->s_state.blockchain[prev]);
lunes_send_block_to_neighbors(node, &node->data->s_state.blockchain[ind]);
// fprintf(stdout, "BS: %.0f,%d,_%d,%d,%f,%d\n", simclock, node->data->key, prevBlock->id, prevBlock->prevId, node->data->hashrate, prevBlock-> position);
fprintf(stdout, "BS: %.0f,%d,_%d,%d,%f,%d\n", simclock, node->data->key, b->id, b->prevId, node->data->hashrate, b-> position);
selfish[3] = b->position;
// Reset the count
selfish[2] = 0;
}
}else {
// Broadcasting the mined ("old") block to all neighbors
lunes_send_block_to_neighbors(node, &node->data->s_state.blockchain[ltblock]);
// clock - nodeid - blockminedid - hashrate
fprintf(stdout, "BS: %.0f,%d,_%d,%d,%f,%d\n", simclock, node->data->key, newId, b->prevId, node->data->hashrate, b-> position);
}
fflush(stdout);
}else {
node->data->internal_timer += 1;
}
}
// If the timer expires we can proceed to the generation of the new message
// but this will happen only for nodes that are enabled to the generation of
// new messages (e.g. time_of_next_trans == -1 -> this node is a forwarder)
// avoid transaction spam using a probability (precision: 0.995153)
#ifdef TXDEBUG
if (((node->data->s_state.time_of_next_trans >= 0) &&
(node->data->s_state.time_of_next_trans <= simclock)) || node->data->key == 337) {
// If the node is the victim node generate always a transaction
// Reset of the timer, it is the time of the next sending
node->data->s_state.time_of_next_trans = simclock + (RND_Exponential(S, 1) * MEAN_NEW_MESSAGE * INTERMEDIATE_STEPS);
// Creating a (maybe) unique identifier for the new message
int transactionid = RND_Interval(S, 0, MAXINT - 1);
// This two fields are unused to reduce ram usage
int from = node->data->key;
int to = 10;
//int from = RND_Interval(S, 0, MAXINT / 2);
//int to = RND_Interval(S, 0, MAXINT / 2);
// The newly generated message has to be inserted in the local cache
lunes_trans_insert(node->data->s_state.blockchain, node->data->latestblock, from, to, transactionid);
// Statistics: print in the trace file all the necessary information
// a new message has been generated
#ifdef TRACE_DISSEMINATION
fprintf(fp_print_trace, "G %010u\n", value);
#endif
// obviously the generating node has "seen" (received)
// the locally generated message
#ifdef TRACE_DISSEMINATION
fprintf(fp_print_trace, "R %010u %010u %010u\n", node->data->key, value, 0);
#endif
#ifdef DEGREE_DEPENDENT_GOSSIP_SUPPORT
// Updating (or initializing) the number of my neighbors
node->data->num_neighbors = g_hash_table_size(node->data->state);
#endif
// Broadcasting the new message to all neighbors
lunes_send_trans_to_neighbors(node, transactionid, from, to);
// clock - nodeid - txid - from - to - blockid
fprintf(stdout, "TS: %.0f,%d,%d,%d,%d,%d\n",
simclock,
node->data->key,
transactionid,
from,
to,
node->data->latestblock);
}
#endif
}
}
/****************************************************************************
*! \brief LUNES_REGISTER: a new SE (in this LP) has been created, LUNES needs to
* initialize some data structures
*/
void lunes_user_register_event_handler(hash_node_t *node) {
double freerider; // Tmp variabile
float threshold; // Tmp, probabilistic evaluation
// Only a given percentage of nodes generates new messages
threshold = RND_Interval(S, (double)0, (double)100);
node->data->s_state.time_of_next_check = simclock + (RND_Exponential(S, 1) * MEAN_NEW_MESSAGE);
if (threshold <= PERC_GENERATORS) {
// Initialization of the time for the generation of new messages
node->data->s_state.time_of_next_trans = simclock + (RND_Exponential(S, 1) * MEAN_NEW_MESSAGE);
}else {
node->data->s_state.time_of_next_trans = -1; // This node will not generate messages
}
// Is this node a free-rider or not?
if (env_freerider_prob > 0) {
freerider = RND_Interval(S, (double)0, (double)100);
if (freerider <= env_freerider_prob) {
node->data->s_state.freerider = 1; // free-rider
}else {
node->data->s_state.freerider = 0; // NOT a free-rider
}
}
}
/****************************************************************************
*! \breif LUNES_TRANS: what happens in LUNES when a node receives a TRANS message?
*
* @param[in] node: The node receiving the TransMsg
* @param[in] msg: The TransMsg
*/
void lunes_user_trans_event_handler(hash_node_t *node, int forwarder, Msg *msg) {
#ifdef TXDEBUG
// Time-To-Live check
if (msg->trans.trans_static.ttl > 0) {
// The TTL is still OK
// Is this node a free-rider?
if (node->data->s_state.freerider == 0) {
// Verify the transaction is not known
if (node->data->key != msg->trans.trans_static.creator &&
lunes_trans_is_known(node->data->s_state.blockchain, node->data->latestblock, msg->trans.trans_static.transid) == 0) {
// It has not been received
lunes_trans_insert(node->data->s_state.blockchain,
node->data->latestblock,
2,
1,
msg->trans.trans_static.transid);
// clock - nodeid - originalcreartor - timestamp - txid - from - to - blockid
fprintf(stdout, "TR: %.0f,%d,%d,%.0f,%d,%d,%d,%d\n",
simclock,
node->data->key,
msg->trans.trans_static.creator,
msg->trans.trans_static.timestamp,
msg->trans.trans_static.transid,
2,
1,
node->data->latestblock);
#ifdef DEGREE_DEPENDENT_GOSSIP_SUPPORT
// Updating (or initializing) the number of my neighbors
gpointer neighbor;
node->data->num_neighbors = g_hash_table_size(node->data->state);
// Updating the number of neighbors of forwarder's neighbors
neighbor = g_hash_table_lookup(node->data->state, &forwarder);
((value_element *)neighbor)->num_neighbors = msg->trans.trans_static.num_neighbors;
#endif
// Dissemination (to some of) the neighbors
// NOTE: the TTL is being decremented here!
lunes_forward_to_neighbors(node,
msg,
--(msg->trans.trans_static.ttl),
msg->trans.trans_static.timestamp,
msg->trans.trans_static.creator,
forwarder);
}else {
// The message is already in the block
#ifdef STALETXDEBUG
// clock - nodeid - originalcreartor - timestamp - txid, from, to
fprintf(stdout, "TRS: %.0f,%d,%d,%.0f,%d,%d,%d\n",
simclock, node->data->key,
msg->block.block_static.creator,
msg->block.block_static.timestamp,
msg->trans.trans_static.transid,
2, 1);
fflush(stdout);
#endif
}
}else {
// This node is a free-rider (i.e. no cache management, no forwarding)
#ifdef FREERIDINGDEBUG
fprintf(stdout, "%12.2f node: [%5d] message [%5d] dropped for freeriding\n", simclock, node->data->key, msg->trans.trans_static.transid);
#endif
}
}
#endif
}
/****************************************************************************
*! \breif LUNES_BLOCK: what happens in LUNES when a node receives a BLOCK message?
*
* @param[in] node: The node receiving the BlockMsg
* @param[in] msg: The BlockMsg
*/
void lunes_user_block_event_handler(hash_node_t *node, int forwarder, Msg *msg) {