GNUnet 0.26.2-106-g126384b46
 
Loading...
Searching...
No Matches
gnunet-service-consensus.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2013, 2017, 2020 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet 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 GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_set_service.h"
31#include "consensus_protocol.h"
32#include "consensus.h"
33
34
51
52
59
60
77
78
90
98
106
107
109
114{
119
125
130
135
142};
143
144
157
158
160{
161 struct SetKey key;
163
169};
170
171
180
187
188
190
191
206
207
209{
211};
212
218{
221};
222
223
224struct TaskEntry;
225
226
227typedef void
228(*TaskFunc) (struct TaskEntry *task);
229
230
231/*
232 * Node in the consensus task graph.
233 */
235{
236 struct TaskKey key;
237
238 struct Step *step;
239
241
243
246
248};
249
250
251struct Step
252{
257 struct Step *prev;
258
263 struct Step *next;
264
266
270 struct TaskEntry **tasks;
271 unsigned int tasks_len;
272 unsigned int tasks_cap;
273
274 unsigned int finished_tasks;
275
276 /*
277 * Tasks that have this task as dependency.
278 *
279 * We store pointers to subordinates rather
280 * than to prerequisites since it makes
281 * tracking the readiness of a task easier.
282 */
284 unsigned int subordinates_len;
285 unsigned int subordinates_cap;
286
291
296
297 unsigned int is_running;
298
299 unsigned int is_finished;
300
304 unsigned int round;
305
310
320};
321
322
324{
326
330 int *votes;
331
336};
337
338
340{
341 struct RfnKey key;
342
343 /*
344 * Elements where there is at least one proposed change.
345 *
346 * Maps the hash of the GNUNET_SET_Element
347 * to 'struct RfnElementInfo'.
348 */
350
351 unsigned int num_peers;
352
364
365
372};
373
374
376{
378
384};
385
386
395
397{
400
402};
403
404
409{
414
419
421
425
430
431 /*
432 * Mapping from (hashed) TaskKey to TaskEntry.
433 *
434 * We map the application_id for a round to the task that should be
435 * executed, so we don't have to go through all task whenever we get
436 * an incoming set op request.
437 */
439
442
444
446
452
457
462
467
474
476
480 unsigned int num_peers;
481
485 unsigned int local_peer_idx;
486
492
497
501 uint64_t first_size;
502
504
508 uint64_t lower_bound;
509
512};
513
518
523
527static const struct GNUNET_CONFIGURATION_Handle *cfg;
528
533
538
539
540static void
541finish_task (struct TaskEntry *task);
542
543
544static void
545run_ready_steps (struct ConsensusSession *session);
546
547
548static const char *
549phasename (uint16_t phase)
550{
551 switch (phase)
552 {
553 case PHASE_KIND_ALL_TO_ALL: return "ALL_TO_ALL";
554
555 case PHASE_KIND_ALL_TO_ALL_2: return "ALL_TO_ALL_2";
556
557 case PHASE_KIND_FINISH: return "FINISH";
558
559 case PHASE_KIND_GRADECAST_LEADER: return "GRADECAST_LEADER";
560
561 case PHASE_KIND_GRADECAST_ECHO: return "GRADECAST_ECHO";
562
563 case PHASE_KIND_GRADECAST_ECHO_GRADE: return "GRADECAST_ECHO_GRADE";
564
565 case PHASE_KIND_GRADECAST_CONFIRM: return "GRADECAST_CONFIRM";
566
567 case PHASE_KIND_GRADECAST_CONFIRM_GRADE: return "GRADECAST_CONFIRM_GRADE";
568
569 case PHASE_KIND_APPLY_REP: return "APPLY_REP";
570
571 default: return "(unknown)";
572 }
573}
574
575
576static const char *
577setname (uint16_t kind)
578{
579 switch (kind)
580 {
581 case SET_KIND_CURRENT: return "CURRENT";
582
583 case SET_KIND_LEADER_PROPOSAL: return "LEADER_PROPOSAL";
584
585 case SET_KIND_NONE: return "NONE";
586
587 default: return "(unknown)";
588 }
589}
590
591
592static const char *
593rfnname (uint16_t kind)
594{
595 switch (kind)
596 {
597 case RFN_KIND_NONE: return "NONE";
598
599 case RFN_KIND_ECHO: return "ECHO";
600
601 case RFN_KIND_CONFIRM: return "CONFIRM";
602
603 default: return "(unknown)";
604 }
605}
606
607
608static const char *
609diffname (uint16_t kind)
610{
611 switch (kind)
612 {
613 case DIFF_KIND_NONE: return "NONE";
614
615 case DIFF_KIND_LEADER_CONSENSUS: return "LEADER_CONSENSUS";
616
617 case DIFF_KIND_GRADECAST_RESULT: return "GRADECAST_RESULT";
618
619 case DIFF_KIND_LEADER_PROPOSAL: return "LEADER_PROPOSAL";
620
621 default: return "(unknown)";
622 }
623}
624
625
626#ifdef GNUNET_EXTRA_LOGGING
627
628
629static const char *
630debug_str_element (const struct GNUNET_SET_Element *el)
631{
632 struct GNUNET_HashCode hash;
633
635
636 return GNUNET_h2s (&hash);
637}
638
639
640static const char *
641debug_str_task_key (const struct TaskKey *tk)
642{
643 static char buf[256];
644
645 snprintf (buf, sizeof(buf),
646 "TaskKey kind=%s, p1=%d, p2=%d, l=%d, rep=%d",
647 phasename (tk->kind), tk->peer1, tk->peer2,
648 tk->leader, tk->repetition);
649
650 return buf;
651}
652
653
654static const char *
655debug_str_diff_key (const struct DiffKey *dk)
656{
657 static char buf[256];
658
659 snprintf (buf, sizeof(buf),
660 "DiffKey kind=%s, k1=%d, k2=%d",
661 diffname (dk->diff_kind), dk->k1, dk->k2);
662
663 return buf;
664}
665
666
667static const char *
668debug_str_set_key (const struct SetKey *sk)
669{
670 static char buf[256];
671
672 snprintf (buf, sizeof(buf),
673 "SetKey kind=%s, k1=%d, k2=%d",
674 setname (sk->set_kind),
675 sk->k1,
676 sk->k2);
677 return buf;
678}
679
680
681static const char *
682debug_str_rfn_key (const struct RfnKey *rk)
683{
684 static char buf[256];
685
686 snprintf (buf, sizeof(buf),
687 "RfnKey kind=%s, k1=%d, k2=%d",
688 rfnname (rk->rfn_kind),
689 rk->k1,
690 rk->k2);
691 return buf;
692}
693
694
695#endif /* GNUNET_EXTRA_LOGGING */
696
697
707static int
709 const struct GNUNET_SET_Element *element)
710{
711 struct TaskEntry *task = (struct TaskEntry *) cls;
712 struct ConsensusSession *session = task->step->session;
713 struct GNUNET_MQ_Envelope *ev;
714
715 if (NULL != element)
716 {
718 const struct ConsensusElement *ce;
719
721 element->element_type);
722 ce = element->data;
723
724 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "marker is %u\n",
725 (unsigned) ce->marker);
726
727 if (0 != ce->marker)
728 return GNUNET_YES;
729
731 "P%d: sending element %s to client\n",
732 session->local_peer_idx,
733 debug_str_element (element));
734
736 element->size - sizeof(struct ConsensusElement),
738 m->element_type = ce->payload_type;
739 GNUNET_memcpy (&m[1],
740 &ce[1],
741 element->size - sizeof(struct ConsensusElement));
742 GNUNET_MQ_send (session->client_mq,
743 ev);
744 }
745 else
746 {
748 "P%d: finished iterating elements for client\n",
749 session->local_peer_idx);
752 GNUNET_MQ_send (session->client_mq,
753 ev);
754 }
755 return GNUNET_YES;
756}
757
758
759static struct SetEntry *
761 const struct SetKey *key)
762{
763 struct GNUNET_HashCode hash;
764
766 "P%u: looking up set {%s}\n",
767 session->local_peer_idx,
768 debug_str_set_key (key));
769
770 GNUNET_assert (SET_KIND_NONE != key->set_kind);
772 sizeof(struct SetKey),
773 &hash);
775 &hash);
776}
777
778
779static struct DiffEntry *
781 const struct DiffKey *key)
782{
783 struct GNUNET_HashCode hash;
784
786 "P%u: looking up diff {%s}\n",
787 session->local_peer_idx,
788 debug_str_diff_key (key));
789 GNUNET_assert (DIFF_KIND_NONE != key->diff_kind);
791 sizeof(struct DiffKey),
792 &hash);
794 &hash);
795}
796
797
798static struct ReferendumEntry *
800 const struct RfnKey *key)
801{
802 struct GNUNET_HashCode hash;
803
805 "P%u: looking up rfn {%s}\n",
806 session->local_peer_idx,
807 debug_str_rfn_key (key));
808 GNUNET_assert (RFN_KIND_NONE != key->rfn_kind);
810 sizeof(struct RfnKey),
811 &hash);
813 &hash);
814}
815
816
817static void
818diff_insert (struct DiffEntry *diff,
819 int weight,
820 const struct GNUNET_SET_Element *element)
821{
822 struct DiffElementInfo *di;
823 struct GNUNET_HashCode hash;
824
825 GNUNET_assert ((1 == weight) || (-1 == weight));
826
828 "diff_insert with element size %u\n",
829 element->size);
830
832 "hashing element\n");
833
834 GNUNET_SET_element_hash (element, &hash);
835
837 "hashed element\n");
838
839 di = GNUNET_CONTAINER_multihashmap_get (diff->changes, &hash);
840
841 if (NULL == di)
842 {
843 di = GNUNET_new (struct DiffElementInfo);
844 di->element = GNUNET_SET_element_dup (element);
847 &hash,
848 di,
850 }
851
852 di->weight = weight;
853}
854
855
856static void
858 uint16_t commit_peer)
859{
860 GNUNET_assert (commit_peer < rfn->num_peers);
861
862 rfn->peer_commited[commit_peer] = GNUNET_YES;
863}
864
865
866static void
868 uint16_t contested_peer)
869{
870 GNUNET_assert (contested_peer < rfn->num_peers);
871
872 rfn->peer_contested[contested_peer] = GNUNET_YES;
873}
874
875
876static uint16_t
878{
879 uint16_t ret;
880
881 ret = 0;
882 for (uint16_t i = 0; i < rfn->num_peers; i++)
883 if ((GNUNET_YES == rfn->peer_commited[i]) && (GNUNET_NO ==
884 rfn->peer_contested[i]))
885 ret++;
886
887 return ret;
888}
889
890
891static void
893 uint16_t voting_peer,
894 enum ReferendumVote vote,
895 const struct GNUNET_SET_Element *element)
896{
897 struct RfnElementInfo *ri;
898 struct GNUNET_HashCode hash;
899
900 GNUNET_assert (voting_peer < rfn->num_peers);
901
902 /* Explicit voting only makes sense with VOTE_ADD or VOTE_REMOTE,
903 since VOTE_KEEP is implicit in not voting. */
904 GNUNET_assert ((VOTE_ADD == vote) || (VOTE_REMOVE == vote));
905
906 GNUNET_SET_element_hash (element, &hash);
908
909 if (NULL == ri)
910 {
911 ri = GNUNET_new (struct RfnElementInfo);
912 ri->element = GNUNET_SET_element_dup (element);
913 ri->votes = GNUNET_new_array (rfn->num_peers, int);
916 &hash, ri,
918 }
919
920 ri->votes[voting_peer] = GNUNET_YES;
921 ri->proposal = vote;
922}
923
924
925static uint16_t
927{
928 uint16_t me = task->step->session->local_peer_idx;
929
930 if (task->key.peer1 == me)
931 return task->key.peer2;
932 return task->key.peer1;
933}
934
935
936static int
937cmp_uint64_t (const void *pa, const void *pb)
938{
939 uint64_t a = *(uint64_t *) pa;
940 uint64_t b = *(uint64_t *) pb;
941
942 if (a == b)
943 return 0;
944 if (a < b)
945 return -1;
946 return 1;
947}
948
949
959static void
960set_result_cb (void *cls,
961 const struct GNUNET_SET_Element *element,
962 uint64_t current_size,
964{
965 struct TaskEntry *task = cls;
966 struct ConsensusSession *session = task->step->session;
967 struct SetEntry *output_set = NULL;
968 struct DiffEntry *output_diff = NULL;
969 struct ReferendumEntry *output_rfn = NULL;
970 unsigned int other_idx;
971 struct SetOpCls *setop;
972 const struct ConsensusElement *consensus_element = NULL;
973
974 if (NULL != element)
975 {
977 "P%u: got element of type %u, status %u\n",
978 session->local_peer_idx,
979 (unsigned) element->element_type,
980 (unsigned) status);
982 element->element_type);
983 consensus_element = element->data;
984 }
985
986 setop = &task->cls.setop;
987
988
990 "P%u: got set result for {%s}, status %u\n",
991 session->local_peer_idx,
992 debug_str_task_key (&task->key),
993 status);
994
995 if (GNUNET_NO == task->is_started)
996 {
997 GNUNET_break_op (0);
998 return;
999 }
1000
1001 if (GNUNET_YES == task->is_finished)
1002 {
1003 GNUNET_break_op (0);
1004 return;
1005 }
1006
1007 other_idx = task_other_peer (task);
1008
1009 if (SET_KIND_NONE != setop->output_set.set_kind)
1010 {
1011 output_set = lookup_set (session,
1012 &setop->output_set);
1013 GNUNET_assert (NULL != output_set);
1014 }
1015
1016 if (DIFF_KIND_NONE != setop->output_diff.diff_kind)
1017 {
1018 output_diff = lookup_diff (session, &setop->output_diff);
1019 GNUNET_assert (NULL != output_diff);
1020 }
1021
1022 if (RFN_KIND_NONE != setop->output_rfn.rfn_kind)
1023 {
1024 output_rfn = lookup_rfn (session, &setop->output_rfn);
1025 GNUNET_assert (NULL != output_rfn);
1026 }
1027
1028 if (GNUNET_YES == session->peers_blacklisted[other_idx])
1029 {
1030 /* Peer might have been blacklisted
1031 by a gradecast running in parallel, ignore elements from now */
1033 return;
1035 return;
1036 }
1037
1038 if ((NULL != consensus_element) && (0 != consensus_element->marker))
1039 {
1041 "P%u: got some marker\n",
1042 session->local_peer_idx);
1043 if ((GNUNET_YES == setop->transceive_contested) &&
1044 (CONSENSUS_MARKER_CONTESTED == consensus_element->marker))
1045 {
1046 GNUNET_assert (NULL != output_rfn);
1047 rfn_contest (output_rfn, task_other_peer (task));
1048 return;
1049 }
1050
1051 if (CONSENSUS_MARKER_SIZE == consensus_element->marker)
1052 {
1054 "P%u: got size marker\n",
1055 session->local_peer_idx);
1056
1057 {
1058 struct ConsensusSizeElement *cse = (void *) consensus_element;
1059 uint64_t *copy;
1060
1061 if (cse->sender_index == other_idx)
1062 {
1063 if (NULL == session->first_sizes_received)
1065 ,
1066 uint64_t);
1067 session->first_sizes_received[other_idx] = GNUNET_ntohll (cse->size);
1068
1069 copy = GNUNET_memdup (session->first_sizes_received,
1070 sizeof(uint64_t) * session->num_peers);
1071 qsort (copy, session->num_peers, sizeof(uint64_t), cmp_uint64_t);
1072 session->lower_bound = copy[session->num_peers / 3 + 1];
1074 "P%u: lower bound %llu\n",
1075 session->local_peer_idx,
1076 (long long) session->lower_bound);
1077 GNUNET_free (copy);
1078 }
1079 return;
1080 }
1081 }
1082
1083 return;
1084 }
1085
1086 switch (status)
1087 {
1089 GNUNET_assert (NULL != consensus_element);
1091 "Adding element in Task {%s}\n",
1092 debug_str_task_key (&task->key));
1093 if (NULL != output_set)
1094 {
1095 // FIXME: record pending adds, use callback
1096 GNUNET_SET_add_element (output_set->h,
1097 element,
1098 NULL,
1099 NULL);
1100#ifdef GNUNET_EXTRA_LOGGING
1102 "P%u: adding element %s into set {%s} of task {%s}\n",
1103 session->local_peer_idx,
1104 debug_str_element (element),
1105 debug_str_set_key (&setop->output_set),
1106 debug_str_task_key (&task->key));
1107#endif
1108 }
1109 if (NULL != output_diff)
1110 {
1111 diff_insert (output_diff, 1, element);
1112#ifdef GNUNET_EXTRA_LOGGING
1114 "P%u: adding element %s into diff {%s} of task {%s}\n",
1115 session->local_peer_idx,
1116 debug_str_element (element),
1117 debug_str_diff_key (&setop->output_diff),
1118 debug_str_task_key (&task->key));
1119#endif
1120 }
1121 if (NULL != output_rfn)
1122 {
1123 rfn_vote (output_rfn, task_other_peer (task), VOTE_ADD, element);
1124#ifdef GNUNET_EXTRA_LOGGING
1126 "P%u: adding element %s into rfn {%s} of task {%s}\n",
1127 session->local_peer_idx,
1128 debug_str_element (element),
1129 debug_str_rfn_key (&setop->output_rfn),
1130 debug_str_task_key (&task->key));
1131#endif
1132 }
1133 // XXX: add result to structures in task
1134 break;
1135
1137 GNUNET_assert (NULL != consensus_element);
1138 if (GNUNET_YES == setop->do_not_remove)
1139 break;
1140 if (CONSENSUS_MARKER_CONTESTED == consensus_element->marker)
1141 break;
1143 "Removing element in Task {%s}\n",
1144 debug_str_task_key (&task->key));
1145 if (NULL != output_set)
1146 {
1147 // FIXME: record pending adds, use callback
1148 GNUNET_SET_remove_element (output_set->h,
1149 element,
1150 NULL,
1151 NULL);
1152#ifdef GNUNET_EXTRA_LOGGING
1154 "P%u: removing element %s from set {%s} of task {%s}\n",
1155 session->local_peer_idx,
1156 debug_str_element (element),
1157 debug_str_set_key (&setop->output_set),
1158 debug_str_task_key (&task->key));
1159#endif
1160 }
1161 if (NULL != output_diff)
1162 {
1163 diff_insert (output_diff, -1, element);
1164#ifdef GNUNET_EXTRA_LOGGING
1166 "P%u: removing element %s from diff {%s} of task {%s}\n",
1167 session->local_peer_idx,
1168 debug_str_element (element),
1169 debug_str_diff_key (&setop->output_diff),
1170 debug_str_task_key (&task->key));
1171#endif
1172 }
1173 if (NULL != output_rfn)
1174 {
1175 rfn_vote (output_rfn, task_other_peer (task), VOTE_REMOVE, element);
1176#ifdef GNUNET_EXTRA_LOGGING
1178 "P%u: removing element %s from rfn {%s} of task {%s}\n",
1179 session->local_peer_idx,
1180 debug_str_element (element),
1181 debug_str_rfn_key (&setop->output_rfn),
1182 debug_str_task_key (&task->key));
1183#endif
1184 }
1185 break;
1186
1188 // XXX: check first if any changes to the underlying
1189 // set are still pending
1191 "P%u: Finishing setop in Task {%s} (%u/%u)\n",
1192 session->local_peer_idx,
1193 debug_str_task_key (&task->key),
1194 (unsigned int) task->step->finished_tasks,
1195 (unsigned int) task->step->tasks_len);
1196 if (NULL != output_rfn)
1197 {
1198 rfn_commit (output_rfn, task_other_peer (task));
1199 }
1200 if (PHASE_KIND_ALL_TO_ALL == task->key.kind)
1201 {
1202 session->first_size = current_size;
1203 }
1204 finish_task (task);
1205 break;
1206
1208 // XXX: cleanup
1209 GNUNET_break_op (0);
1210 finish_task (task);
1211 return;
1212
1213 default:
1214 /* not reached */
1215 GNUNET_assert (0);
1216 }
1217}
1218
1219
1220#ifdef EVIL
1221
1222enum EvilnessType
1223{
1224 EVILNESS_NONE,
1225 EVILNESS_CRAM_ALL,
1226 EVILNESS_CRAM_LEAD,
1227 EVILNESS_CRAM_ECHO,
1228 EVILNESS_SLACK,
1229 EVILNESS_SLACK_A2A,
1230};
1231
1232enum EvilnessSubType
1233{
1234 EVILNESS_SUB_NONE,
1235 EVILNESS_SUB_REPLACEMENT,
1236 EVILNESS_SUB_NO_REPLACEMENT,
1237};
1238
1239struct Evilness
1240{
1241 enum EvilnessType type;
1242 enum EvilnessSubType subtype;
1243 unsigned int num;
1244};
1245
1246
1247static int
1248parse_evilness_cram_subtype (const char *evil_subtype_str,
1249 struct Evilness *evil)
1250{
1251 if (0 == strcmp ("replace", evil_subtype_str))
1252 {
1253 evil->subtype = EVILNESS_SUB_REPLACEMENT;
1254 }
1255 else if (0 == strcmp ("noreplace", evil_subtype_str))
1256 {
1257 evil->subtype = EVILNESS_SUB_NO_REPLACEMENT;
1258 }
1259 else
1260 {
1262 "Malformed field '%s' in EVIL_SPEC (unknown subtype), behaving like a good peer.\n",
1263 evil_subtype_str);
1264 return GNUNET_SYSERR;
1265 }
1266 return GNUNET_OK;
1267}
1268
1269
1270static void
1271get_evilness (struct ConsensusSession *session, struct Evilness *evil)
1272{
1273 char *evil_spec;
1274 char *field;
1275 char *evil_type_str = NULL;
1276 char *evil_subtype_str = NULL;
1277
1278 GNUNET_assert (NULL != evil);
1279
1281 "EVIL_SPEC",
1282 &evil_spec))
1283 {
1285 "P%u: no evilness\n",
1286 session->local_peer_idx);
1287 evil->type = EVILNESS_NONE;
1288 return;
1289 }
1291 "P%u: got evilness spec\n",
1292 session->local_peer_idx);
1293
1294 for (field = strtok (evil_spec, "/");
1295 NULL != field;
1296 field = strtok (NULL, "/"))
1297 {
1298 unsigned int peer_num;
1299 unsigned int evil_num;
1300 int ret;
1301
1302 evil_type_str = NULL;
1303 evil_subtype_str = NULL;
1304
1305 ret = sscanf (field, "%u;%m[a-z-];%m[a-z-];%u", &peer_num, &evil_type_str,
1306 &evil_subtype_str, &evil_num);
1307
1308 if (ret != 4)
1309 {
1311 "Malformed field '%s' in EVIL_SPEC (expected 4 components got %d), behaving like a good peer.\n",
1312 field,
1313 ret);
1314 goto not_evil;
1315 }
1316
1317 GNUNET_assert (NULL != evil_type_str);
1318 GNUNET_assert (NULL != evil_subtype_str);
1319
1320 if (peer_num == session->local_peer_idx)
1321 {
1322 if (0 == strcmp ("slack", evil_type_str))
1323 {
1324 evil->type = EVILNESS_SLACK;
1325 }
1326 if (0 == strcmp ("slack-a2a", evil_type_str))
1327 {
1328 evil->type = EVILNESS_SLACK_A2A;
1329 }
1330 else if (0 == strcmp ("cram-all", evil_type_str))
1331 {
1332 evil->type = EVILNESS_CRAM_ALL;
1333 evil->num = evil_num;
1334 if (GNUNET_OK != parse_evilness_cram_subtype (evil_subtype_str, evil))
1335 goto not_evil;
1336 }
1337 else if (0 == strcmp ("cram-lead", evil_type_str))
1338 {
1339 evil->type = EVILNESS_CRAM_LEAD;
1340 evil->num = evil_num;
1341 if (GNUNET_OK != parse_evilness_cram_subtype (evil_subtype_str, evil))
1342 goto not_evil;
1343 }
1344 else if (0 == strcmp ("cram-echo", evil_type_str))
1345 {
1346 evil->type = EVILNESS_CRAM_ECHO;
1347 evil->num = evil_num;
1348 if (GNUNET_OK != parse_evilness_cram_subtype (evil_subtype_str, evil))
1349 goto not_evil;
1350 }
1351 else
1352 {
1354 "Malformed field '%s' in EVIL_SPEC (unknown type), behaving like a good peer.\n",
1355 evil_type_str);
1356 goto not_evil;
1357 }
1358 goto cleanup;
1359 }
1360 /* No GNUNET_free since memory was allocated by libc */
1361 free (evil_type_str);
1362 evil_type_str = NULL;
1363 evil_subtype_str = NULL;
1364 }
1365not_evil:
1366 evil->type = EVILNESS_NONE;
1367cleanup:
1368 GNUNET_free (evil_spec);
1369 /* no GNUNET_free since it wasn't
1370 * allocated with GNUNET_malloc */
1371 if (NULL != evil_type_str)
1372 free (evil_type_str);
1373 if (NULL != evil_subtype_str)
1374 free (evil_subtype_str);
1375}
1376
1377
1378#endif
1379
1380
1384static void
1386 struct TaskEntry *task)
1387{
1388 struct SetEntry *set;
1389 struct SetOpCls *setop = &task->cls.setop;
1390
1391 GNUNET_assert (NULL != setop->op);
1392 set = lookup_set (session, &setop->input_set);
1393 GNUNET_assert (NULL != set);
1394
1395 if ((GNUNET_YES == setop->transceive_contested) && (GNUNET_YES ==
1396 set->is_contested))
1397 {
1398 struct GNUNET_SET_Element element;
1399 struct ConsensusElement ce = { 0 };
1400
1402 element.data = &ce;
1403 element.size = sizeof(struct ConsensusElement);
1405 GNUNET_SET_add_element (set->h, &element, NULL, NULL);
1406 }
1407
1408 if (PHASE_KIND_ALL_TO_ALL_2 == task->key.kind)
1409 {
1410 struct GNUNET_SET_Element element;
1411 struct ConsensusSizeElement cse = {
1412 .size = 0,
1413 .sender_index = 0
1414 };
1415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "inserting size marker\n");
1417 cse.size = GNUNET_htonll (session->first_size);
1418 cse.sender_index = session->local_peer_idx;
1419 element.data = &cse;
1420 element.size = sizeof(struct ConsensusSizeElement);
1422 GNUNET_SET_add_element (set->h, &element, NULL, NULL);
1423 }
1424
1425#ifdef EVIL
1426 {
1427 struct Evilness evil;
1428
1429 get_evilness (session, &evil);
1430 if (EVILNESS_NONE != evil.type)
1431 {
1432 /* Useful for evaluation */
1434 "is evil",
1435 1,
1436 GNUNET_NO);
1437 }
1438 switch (evil.type)
1439 {
1440 case EVILNESS_CRAM_ALL:
1441 case EVILNESS_CRAM_LEAD:
1442 case EVILNESS_CRAM_ECHO:
1443 /* We're not cramming elements in the
1444 all-to-all round, since that would just
1445 add more elements to the result set, but
1446 wouldn't test robustness. */
1447 if (PHASE_KIND_ALL_TO_ALL == task->key.kind)
1448 {
1449 GNUNET_SET_commit (setop->op, set->h);
1450 break;
1451 }
1452 if ((EVILNESS_CRAM_LEAD == evil.type) &&
1453 ((PHASE_KIND_GRADECAST_LEADER != task->key.kind) ||
1454 (SET_KIND_CURRENT != set->key.set_kind) ))
1455 {
1456 GNUNET_SET_commit (setop->op, set->h);
1457 break;
1458 }
1459 if ((EVILNESS_CRAM_ECHO == evil.type) && (PHASE_KIND_GRADECAST_ECHO !=
1460 task->key.kind))
1461 {
1462 GNUNET_SET_commit (setop->op, set->h);
1463 break;
1464 }
1465 for (unsigned int i = 0; i < evil.num; i++)
1466 {
1467 struct GNUNET_SET_Element element;
1468 struct ConsensusStuffedElement se = {
1469 .ce.payload_type = 0,
1470 .ce.marker = 0,
1471 };
1472 element.data = &se;
1473 element.size = sizeof(struct ConsensusStuffedElement);
1475
1476 if (EVILNESS_SUB_REPLACEMENT == evil.subtype)
1477 {
1478 /* Always generate a new element. */
1480 &se.rand);
1481 }
1482 else if (EVILNESS_SUB_NO_REPLACEMENT == evil.subtype)
1483 {
1484 /* Always cram the same elements, derived from counter. */
1485 GNUNET_CRYPTO_hash (&i, sizeof(i), &se.rand);
1486 }
1487 else
1488 {
1489 GNUNET_assert (0);
1490 }
1491 GNUNET_SET_add_element (set->h, &element, NULL, NULL);
1492#ifdef GNUNET_EXTRA_LOGGING
1494 "P%u: evil peer: cramming element %s into set {%s} of task {%s}\n",
1495 session->local_peer_idx,
1496 debug_str_element (&element),
1497 debug_str_set_key (&setop->input_set),
1498 debug_str_task_key (&task->key));
1499#endif
1500 }
1502 "# stuffed elements",
1503 evil.num,
1504 GNUNET_NO);
1505 GNUNET_SET_commit (setop->op, set->h);
1506 break;
1507
1508 case EVILNESS_SLACK:
1510 "P%u: evil peer: slacking\n",
1511 (unsigned int) session->local_peer_idx);
1512
1513 /* Do nothing. */
1514 case EVILNESS_SLACK_A2A:
1515 if ((PHASE_KIND_ALL_TO_ALL_2 == task->key.kind) ||
1516 (PHASE_KIND_ALL_TO_ALL == task->key.kind))
1517 {
1518 struct GNUNET_SET_Handle *empty_set;
1520 GNUNET_SET_commit (setop->op, empty_set);
1521 GNUNET_SET_destroy (empty_set);
1522 }
1523 else
1524 {
1525 GNUNET_SET_commit (setop->op,
1526 set->h);
1527 }
1528 break;
1529
1530 case EVILNESS_NONE:
1531 GNUNET_SET_commit (setop->op,
1532 set->h);
1533 break;
1534 }
1535 }
1536#else
1537 if (GNUNET_NO == session->peers_blacklisted[task_other_peer (task)])
1538 {
1539 GNUNET_SET_commit (setop->op, set->h);
1540 }
1541 else
1542 {
1543 /* For our testcases, we don't want the blacklisted
1544 peers to wait. */
1546 setop->op = NULL;
1547 finish_task (task);
1548 }
1549#endif
1550}
1551
1552
1553static void
1555 struct DiffEntry *diff)
1556{
1557 struct GNUNET_HashCode hash;
1558
1559 GNUNET_CRYPTO_hash (&diff->key,
1560 sizeof(struct DiffKey),
1561 &hash);
1564 &hash,
1565 diff,
1567}
1568
1569
1570static void
1571put_set (struct ConsensusSession *session,
1572 struct SetEntry *set)
1573{
1574 struct GNUNET_HashCode hash;
1575
1576 GNUNET_assert (NULL != set->h);
1578 "Putting set %s\n",
1579 debug_str_set_key (&set->key));
1580 GNUNET_CRYPTO_hash (&set->key,
1581 sizeof(struct SetKey),
1582 &hash);
1585 &hash,
1586 set,
1588}
1589
1590
1591static void
1592put_rfn (struct ConsensusSession *session,
1593 struct ReferendumEntry *rfn)
1594{
1595 struct GNUNET_HashCode hash;
1596
1597 GNUNET_CRYPTO_hash (&rfn->key, sizeof(struct RfnKey), &hash);
1600 &hash,
1601 rfn,
1603}
1604
1605
1606static void
1608{
1609 /* not implemented yet */
1610 GNUNET_assert (0);
1611}
1612
1613
1614static void
1616 struct ReferendumEntry *rfn,
1617 uint16_t voting_peer,
1618 uint16_t num_peers)
1619{
1621 struct DiffElementInfo *di;
1622
1624
1625 while (GNUNET_YES ==
1627 NULL,
1628 (const void **) &di))
1629 {
1630 if (di->weight > 0)
1631 {
1632 rfn_vote (rfn, voting_peer, VOTE_ADD, di->element);
1633 }
1634 if (di->weight < 0)
1635 {
1636 rfn_vote (rfn, voting_peer, VOTE_REMOVE, di->element);
1637 }
1638 }
1639
1641}
1642
1643
1644static struct DiffEntry *
1646{
1647 struct DiffEntry *d = GNUNET_new (struct DiffEntry);
1648
1650 GNUNET_NO);
1651
1652 return d;
1653}
1654
1655
1656#if 0
1657static struct DiffEntry *
1658diff_compose (struct DiffEntry *diff_1,
1659 struct DiffEntry *diff_2)
1660{
1661 struct DiffEntry *diff_new;
1663 struct DiffElementInfo *di;
1664
1665 diff_new = diff_create ();
1666
1668 while (GNUNET_YES ==
1670 NULL,
1671 (const void **) &di))
1672 {
1673 diff_insert (diff_new,
1674 di->weight,
1675 di->element);
1676 }
1678
1680 while (GNUNET_YES ==
1682 NULL,
1683 (const void **) &di))
1684 {
1685 diff_insert (diff_new,
1686 di->weight,
1687 di->element);
1688 }
1690
1691 return diff_new;
1692}
1693
1694
1695#endif
1696
1697
1698static struct ReferendumEntry *
1700{
1701 struct ReferendumEntry *rfn;
1702
1703 rfn = GNUNET_new (struct ReferendumEntry);
1705 rfn->peer_commited = GNUNET_new_array (size, int);
1706 rfn->peer_contested = GNUNET_new_array (size, int);
1707 rfn->num_peers = size;
1708
1709 return rfn;
1710}
1711
1712
1713#if UNUSED
1714static void
1715diff_destroy (struct DiffEntry *diff)
1716{
1718 GNUNET_free (diff);
1719}
1720
1721
1722#endif
1723
1724
1730static void
1732 const struct RfnElementInfo *ri,
1733 uint16_t *ret_majority,
1734 enum ReferendumVote *ret_vote)
1735{
1736 uint16_t votes_yes = 0;
1737 uint16_t num_commited = 0;
1738
1740 "Computing rfn majority for element %s of rfn {%s}\n",
1741 debug_str_element (ri->element),
1742 debug_str_rfn_key (&rfn->key));
1743
1744 for (uint16_t i = 0; i < rfn->num_peers; i++)
1745 {
1746 if (GNUNET_NO == rfn->peer_commited[i])
1747 continue;
1748 num_commited++;
1749
1750 if (GNUNET_YES == ri->votes[i])
1751 votes_yes++;
1752 }
1753
1754 if (votes_yes > (num_commited) / 2)
1755 {
1756 *ret_vote = ri->proposal;
1757 *ret_majority = votes_yes;
1758 }
1759 else
1760 {
1761 *ret_vote = VOTE_STAY;
1762 *ret_majority = num_commited - votes_yes;
1763 }
1764}
1765
1766
1768{
1771};
1772
1773
1774static void
1775set_copy_cb (void *cls,
1776 struct GNUNET_SET_Handle *copy)
1777{
1778 struct SetCopyCls *scc = cls;
1779 struct TaskEntry *task = scc->task;
1780 struct SetKey dst_set_key = scc->dst_set_key;
1781 struct SetEntry *set;
1782 struct SetHandle *sh = GNUNET_new (struct SetHandle);
1783
1784 sh->h = copy;
1787 sh);
1788
1789 GNUNET_free (scc);
1790 set = GNUNET_new (struct SetEntry);
1791 set->h = copy;
1792 set->key = dst_set_key;
1793 put_set (task->step->session, set);
1794
1795 task->start (task);
1796}
1797
1798
1803static void
1805 struct SetKey *src_set_key,
1806 struct SetKey *dst_set_key)
1807{
1808 struct SetEntry *src_set;
1809 struct SetCopyCls *scc = GNUNET_new (struct SetCopyCls);
1810
1812 "Copying set {%s} to {%s} for task {%s}\n",
1813 debug_str_set_key (src_set_key),
1814 debug_str_set_key (dst_set_key),
1815 debug_str_task_key (&task->key));
1816
1817 scc->task = task;
1818 scc->dst_set_key = *dst_set_key;
1819 src_set = lookup_set (task->step->session, src_set_key);
1820 GNUNET_assert (NULL != src_set);
1821 GNUNET_SET_copy_lazy (src_set->h,
1823 scc);
1824}
1825
1826
1835
1836
1837static void
1839{
1840 struct SetMutationProgressCls *pc = cls;
1841
1842 GNUNET_assert (pc->num_pending > 0);
1843
1844 pc->num_pending--;
1845
1846 if (0 == pc->num_pending)
1847 {
1848 struct TaskEntry *task = pc->task;
1849 GNUNET_free (pc);
1850 finish_task (task);
1851 }
1852}
1853
1854
1855static void
1857{
1858 if (GNUNET_YES == step->is_running)
1859 return;
1860 if (GNUNET_YES == step->is_finished)
1861 return;
1863 return;
1864
1866
1867#ifdef GNUNET_EXTRA_LOGGING
1869 "Finishing step `%s' early.\n",
1870 step->debug_name);
1871#endif
1872
1873 for (unsigned int i = 0; i < step->subordinates_len; i++)
1874 {
1877#ifdef GNUNET_EXTRA_LOGGING
1879 "Decreased pending_prereq to %u for step `%s'.\n",
1880 (unsigned int) step->subordinates[i]->pending_prereq,
1882#endif
1884 }
1885
1886 // XXX: maybe schedule as task to avoid recursion?
1888}
1889
1890
1891static void
1893{
1897
1898#ifdef GNUNET_EXTRA_LOGGING
1900 "All tasks of step `%s' with %u subordinates finished.\n",
1903#endif
1904
1905 for (unsigned int i = 0; i < step->subordinates_len; i++)
1906 {
1909#ifdef GNUNET_EXTRA_LOGGING
1911 "Decreased pending_prereq to %u for step `%s'.\n",
1912 (unsigned int) step->subordinates[i]->pending_prereq,
1914#endif
1915 }
1916
1918
1919 // XXX: maybe schedule as task to avoid recursion?
1921}
1922
1923
1930static void
1932{
1933 struct ConsensusSession *session = task->step->session;
1934 struct SetKey sk_in;
1935 struct SetKey sk_out;
1936 struct RfnKey rk_in;
1937 struct SetEntry *set_out;
1938 struct ReferendumEntry *rfn_in;
1940 struct RfnElementInfo *ri;
1941 struct SetMutationProgressCls *progress_cls;
1942 uint16_t worst_majority = UINT16_MAX;
1943
1944 sk_in = (struct SetKey) { SET_KIND_CURRENT, task->key.repetition };
1945 rk_in = (struct RfnKey) { RFN_KIND_GRADECAST_RESULT, task->key.repetition };
1946 sk_out = (struct SetKey) { SET_KIND_CURRENT, task->key.repetition + 1 };
1947
1948 set_out = lookup_set (session, &sk_out);
1949 if (NULL == set_out)
1950 {
1952 &sk_in,
1953 &sk_out);
1954 return;
1955 }
1956
1957 rfn_in = lookup_rfn (session, &rk_in);
1958 GNUNET_assert (NULL != rfn_in);
1959
1960 progress_cls = GNUNET_new (struct SetMutationProgressCls);
1961 progress_cls->task = task;
1962
1964
1965 while (GNUNET_YES ==
1967 NULL,
1968 (const void **) &ri))
1969 {
1970 uint16_t majority_num;
1971 enum ReferendumVote majority_vote;
1972
1973 rfn_majority (rfn_in, ri, &majority_num, &majority_vote);
1974
1975 if (worst_majority > majority_num)
1976 worst_majority = majority_num;
1977
1978 switch (majority_vote)
1979 {
1980 case VOTE_ADD:
1981 progress_cls->num_pending++;
1983 GNUNET_SET_add_element (set_out->h,
1984 ri->element,
1986 progress_cls));
1988 "P%u: apply round: adding element %s with %u-majority.\n",
1989 session->local_peer_idx,
1990 debug_str_element (ri->element), majority_num);
1991 break;
1992
1993 case VOTE_REMOVE:
1994 progress_cls->num_pending++;
1996 GNUNET_SET_remove_element (set_out->h,
1997 ri->element,
1999 progress_cls));
2001 "P%u: apply round: deleting element %s with %u-majority.\n",
2002 session->local_peer_idx,
2003 debug_str_element (ri->element), majority_num);
2004 break;
2005
2006 case VOTE_STAY:
2008 "P%u: apply round: keeping element %s with %u-majority.\n",
2009 session->local_peer_idx,
2010 debug_str_element (ri->element), majority_num);
2011 // do nothing
2012 break;
2013
2014 default:
2015 GNUNET_assert (0);
2016 break;
2017 }
2018 }
2019
2020 if (0 == progress_cls->num_pending)
2021 {
2022 // call closure right now, no pending ops
2023 GNUNET_free (progress_cls);
2024 finish_task (task);
2025 }
2026
2027 {
2028 uint16_t thresh = (session->num_peers / 3) * 2;
2029
2030 if (worst_majority >= thresh)
2031 {
2032 switch (session->early_stopping)
2033 {
2037 "P%u: Stopping early (after one more superround)\n",
2038 session->local_peer_idx);
2039 break;
2040
2043 "P%u: finishing steps due to early finish\n",
2044 session->local_peer_idx);
2046 {
2047 struct Step *step;
2048 for (step = session->steps_head; NULL != step; step = step->next)
2049 try_finish_step_early (step);
2050 }
2051 break;
2052
2054 /* We shouldn't be here anymore after early stopping */
2055 GNUNET_break (0);
2056 break;
2057
2058 default:
2059 GNUNET_assert (0);
2060 break;
2061 }
2062 }
2064 {
2065 // Our assumption about the number of bad peers
2066 // has been broken.
2067 GNUNET_break_op (0);
2068 }
2069 else
2070 {
2072 "P%u: NOT finishing early (majority not good enough)\n",
2074 }
2075 }
2077}
2078
2079
2080static void
2082{
2083 struct ConsensusSession *session = task->step->session;
2084 struct ReferendumEntry *output_rfn;
2085 struct ReferendumEntry *input_rfn;
2086 struct DiffEntry *input_diff;
2087 struct RfnKey rfn_key;
2088 struct DiffKey diff_key;
2090 struct RfnElementInfo *ri;
2091 unsigned int gradecast_confidence = 2;
2092
2093 rfn_key = (struct RfnKey) { RFN_KIND_GRADECAST_RESULT, task->key.repetition };
2094 output_rfn = lookup_rfn (session, &rfn_key);
2095 if (NULL == output_rfn)
2096 {
2097 output_rfn = rfn_create (session->num_peers);
2098 output_rfn->key = rfn_key;
2099 put_rfn (session, output_rfn);
2100 }
2101
2102 diff_key = (struct DiffKey) { DIFF_KIND_LEADER_PROPOSAL, task->key.repetition,
2103 task->key.leader };
2104 input_diff = lookup_diff (session, &diff_key);
2105 GNUNET_assert (NULL != input_diff);
2106
2107 rfn_key = (struct RfnKey) { RFN_KIND_ECHO, task->key.repetition,
2108 task->key.leader };
2109 input_rfn = lookup_rfn (session, &rfn_key);
2110 GNUNET_assert (NULL != input_rfn);
2111
2113 input_rfn->rfn_elements);
2114
2115 apply_diff_to_rfn (input_diff, output_rfn, task->key.leader,
2116 session->num_peers);
2117
2118 while (GNUNET_YES ==
2120 NULL,
2121 (const void **) &ri))
2122 {
2123 uint16_t majority_num;
2124 enum ReferendumVote majority_vote;
2125
2126 // XXX: we need contested votes and non-contested votes here
2127 rfn_majority (input_rfn, ri, &majority_num, &majority_vote);
2128
2129 if (majority_num <= session->num_peers / 3)
2130 majority_vote = VOTE_REMOVE;
2131
2132 switch (majority_vote)
2133 {
2134 case VOTE_STAY:
2135 break;
2136
2137 case VOTE_ADD:
2138 rfn_vote (output_rfn, task->key.leader, VOTE_ADD, ri->element);
2139 break;
2140
2141 case VOTE_REMOVE:
2142 rfn_vote (output_rfn, task->key.leader, VOTE_REMOVE, ri->element);
2143 break;
2144
2145 default:
2146 GNUNET_assert (0);
2147 break;
2148 }
2149 }
2151
2152 {
2153 uint16_t noncontested;
2154 noncontested = rfn_noncontested (input_rfn);
2155 if (noncontested < (session->num_peers / 3) * 2)
2156 {
2157 gradecast_confidence = GNUNET_MIN (1, gradecast_confidence);
2158 }
2159 if (noncontested < (session->num_peers / 3) + 1)
2160 {
2161 gradecast_confidence = 0;
2162 }
2163 }
2164
2165 if (gradecast_confidence >= 1)
2166 rfn_commit (output_rfn, task->key.leader);
2167
2168 if (gradecast_confidence <= 1)
2169 session->peers_blacklisted[task->key.leader] = GNUNET_YES;
2170
2171 finish_task (task);
2172}
2173
2174
2175static void
2177{
2178 struct SetEntry *input;
2179 struct SetOpCls *setop = &task->cls.setop;
2180 struct ConsensusSession *session = task->step->session;
2181
2182 input = lookup_set (session, &setop->input_set);
2183 GNUNET_assert (NULL != input);
2184 GNUNET_assert (NULL != input->h);
2185
2186 /* We create the outputs for the operation here
2187 (rather than in the set operation callback)
2188 because we want something valid in there, even
2189 if the other peer doesn't talk to us */
2190
2191 if (SET_KIND_NONE != setop->output_set.set_kind)
2192 {
2193 /* If we don't have an existing output set,
2194 we clone the input set. */
2195 if (NULL == lookup_set (session, &setop->output_set))
2196 {
2198 &setop->input_set,
2199 &setop->output_set);
2200 return;
2201 }
2202 }
2203
2204 if (RFN_KIND_NONE != setop->output_rfn.rfn_kind)
2205 {
2206 if (NULL == lookup_rfn (session, &setop->output_rfn))
2207 {
2208 struct ReferendumEntry *rfn;
2209
2211 "P%u: output rfn <%s> missing, creating.\n",
2212 session->local_peer_idx,
2213 debug_str_rfn_key (&setop->output_rfn));
2214
2215 rfn = rfn_create (session->num_peers);
2216 rfn->key = setop->output_rfn;
2217 put_rfn (session, rfn);
2218 }
2219 }
2220
2221 if (DIFF_KIND_NONE != setop->output_diff.diff_kind)
2222 {
2223 if (NULL == lookup_diff (session, &setop->output_diff))
2224 {
2225 struct DiffEntry *diff;
2226
2227 diff = diff_create ();
2228 diff->key = setop->output_diff;
2229 put_diff (session, diff);
2230 }
2231 }
2232
2233 if ((task->key.peer1 == session->local_peer_idx) && (task->key.peer2 ==
2234 session->local_peer_idx))
2235 {
2236 /* XXX: mark the corresponding rfn as committed if necessary */
2237 finish_task (task);
2238 return;
2239 }
2240
2241 if (task->key.peer1 == session->local_peer_idx)
2242 {
2244
2246 "P%u: Looking up set {%s} to run remote union\n",
2247 session->local_peer_idx,
2248 debug_str_set_key (&setop->input_set));
2250 rcm.header.size = htons (sizeof(rcm));
2251 rcm.kind = htons (task->key.kind);
2252 rcm.peer1 = htons (task->key.peer1);
2253 rcm.peer2 = htons (task->key.peer2);
2254 rcm.leader = htons (task->key.leader);
2255 rcm.repetition = htons (task->key.repetition);
2256 rcm.is_contested = htons (0);
2257
2258 GNUNET_assert (NULL == setop->op);
2260 "P%u: initiating set op with P%u, our set is %s\n",
2261 session->local_peer_idx,
2262 task->key.peer2,
2263 debug_str_set_key (&setop->input_set));
2264
2265 {
2266 struct GNUNET_SET_Option opts[] = {
2267 { GNUNET_SET_OPTION_BYZANTINE, { .num = session->lower_bound } },
2269 };
2270
2271 // XXX: maybe this should be done while
2272 // setting up tasks alreays?
2273 setop->op = GNUNET_SET_prepare (&session->peers[task->key.peer2],
2274 &session->global_id,
2275 &rcm.header,
2277 opts,
2279 task);
2280
2281 commit_set (session, task);
2282 }
2283 }
2284 else if (task->key.peer2 == session->local_peer_idx)
2285 {
2286 /* Wait for the other peer to contact us */
2287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: waiting set op with P%u\n",
2288 session->local_peer_idx, task->key.peer1);
2289
2290 if (NULL != setop->op)
2291 {
2292 commit_set (session, task);
2293 }
2294 }
2295 else
2296 {
2297 /* We made an error while constructing the task graph. */
2298 GNUNET_assert (0);
2299 }
2300}
2301
2302
2303static void
2305{
2307 struct ReferendumEntry *input_rfn;
2308 struct RfnElementInfo *ri;
2309 struct SetEntry *output_set;
2310 struct SetMutationProgressCls *progress_cls;
2311 struct ConsensusSession *session = task->step->session;
2312 struct SetKey sk_in;
2313 struct SetKey sk_out;
2314 struct RfnKey rk_in;
2315
2316 sk_in = (struct SetKey) { SET_KIND_LEADER_PROPOSAL, task->key.repetition,
2317 task->key.leader };
2318 sk_out = (struct SetKey) { SET_KIND_ECHO_RESULT, task->key.repetition,
2319 task->key.leader };
2320 output_set = lookup_set (session, &sk_out);
2321 if (NULL == output_set)
2322 {
2324 &sk_in,
2325 &sk_out);
2326 return;
2327 }
2328
2329 {
2330 // FIXME: should be marked as a shallow copy, so
2331 // we can destroy everything correctly
2332 struct SetEntry *last_set = GNUNET_new (struct SetEntry);
2333
2334 last_set->h = output_set->h;
2335 last_set->key = (struct SetKey) { SET_KIND_LAST_GRADECAST };
2336 put_set (session, last_set);
2337 }
2338
2340 "Evaluating referendum in Task {%s}\n",
2341 debug_str_task_key (&task->key));
2342
2343 progress_cls = GNUNET_new (struct SetMutationProgressCls);
2344 progress_cls->task = task;
2345 rk_in = (struct RfnKey) { RFN_KIND_ECHO, task->key.repetition,
2346 task->key.leader };
2347 input_rfn = lookup_rfn (session, &rk_in);
2348 GNUNET_assert (NULL != input_rfn);
2350 input_rfn->rfn_elements);
2351 GNUNET_assert (NULL != iter);
2352
2353 while (GNUNET_YES ==
2355 NULL,
2356 (const void **) &ri))
2357 {
2358 enum ReferendumVote majority_vote;
2359 uint16_t majority_num;
2360
2361 rfn_majority (input_rfn, ri, &majority_num, &majority_vote);
2362
2363 if (majority_num < session->num_peers / 3)
2364 {
2365 /* It is not the case that all nonfaulty peers
2366 echoed the same value. Since we're doing a set reconciliation, we
2367 can't simply send "nothing" for the value. Thus we mark our 'confirm'
2368 reconciliation as contested. Other peers might not know that the
2369 leader is faulty, thus we still re-distribute in the confirmation
2370 round. *///
2371 output_set->is_contested = GNUNET_YES;
2372 }
2373
2374 switch (majority_vote)
2375 {
2376 case VOTE_ADD:
2377 progress_cls->num_pending++;
2379 GNUNET_SET_add_element (output_set->h,
2380 ri->element,
2382 progress_cls));
2383 break;
2384
2385 case VOTE_REMOVE:
2386 progress_cls->num_pending++;
2388 GNUNET_SET_remove_element (output_set->h,
2389 ri->element,
2391 progress_cls));
2392 break;
2393
2394 case VOTE_STAY:
2395 /* Nothing to do. */
2396 break;
2397
2398 default:
2399 /* not reached */
2400 GNUNET_assert (0);
2401 }
2402 }
2403
2405
2406 if (0 == progress_cls->num_pending)
2407 {
2408 // call closure right now, no pending ops
2409 GNUNET_free (progress_cls);
2410 finish_task (task);
2411 }
2412}
2413
2414
2415static void
2417{
2418 struct SetEntry *final_set;
2419 struct ConsensusSession *session = task->step->session;
2420
2421 final_set = lookup_set (session,
2422 &task->cls.finish.input_set);
2423 GNUNET_assert (NULL != final_set);
2424 GNUNET_SET_iterate (final_set->h,
2426 task);
2427}
2428
2429
2430static void
2432 struct TaskEntry *task)
2433{
2435 "P%u: starting task {%s}\n",
2436 session->local_peer_idx,
2437 debug_str_task_key (&task->key));
2440 GNUNET_assert (NULL != task->start);
2441 task->start (task);
2442 task->is_started = GNUNET_YES;
2443}
2444
2445
2446/*
2447 * Run all steps of the session that don't any
2448 * more dependencies.
2449 */
2450static void
2452{
2453 struct Step *step;
2454
2455 step = session->steps_head;
2456
2457 while (NULL != step)
2458 {
2459 if ((GNUNET_NO == step->is_running) && (0 == step->pending_prereq) &&
2460 (GNUNET_NO == step->is_finished))
2461 {
2462 GNUNET_assert (0 == step->finished_tasks);
2463
2464#ifdef GNUNET_EXTRA_LOGGING
2466 "P%u: Running step `%s' of round %d with %d tasks and %d subordinates\n",
2468 step->debug_name,
2469 step->round, step->tasks_len, step->subordinates_len);
2470#endif
2471
2472 step->is_running = GNUNET_YES;
2473 for (size_t i = 0; i < step->tasks_len; i++)
2474 start_task (session, step->tasks[i]);
2475
2476 /* Sometimes there is no task to trigger finishing the step, so we have to do it here. */
2477 if ((step->finished_tasks == step->tasks_len) && (GNUNET_NO ==
2478 step->is_finished))
2479 finish_step (step);
2480
2481 /* Running the next ready steps will be triggered by task completion */
2482 return;
2483 }
2484 step = step->next;
2485 }
2486
2487 return;
2488}
2489
2490
2491static void
2493{
2495 task->is_finished = GNUNET_YES;
2496 task->step->finished_tasks++;
2498 "P%u: Finishing Task {%s} (now %u/%u tasks finished in step)\n",
2499 task->step->session->local_peer_idx,
2500 debug_str_task_key (&task->key),
2501 (unsigned int) task->step->finished_tasks,
2502 (unsigned int) task->step->tasks_len);
2503
2504 if (task->step->finished_tasks == task->step->tasks_len)
2505 finish_step (task->step);
2506}
2507
2508
2516static int
2518 const struct ConsensusSession *session)
2519{
2520 for (int i = 0; i < session->num_peers; i++)
2521 if (0 == GNUNET_memcmp (peer, &session->peers[i]))
2522 return i;
2523 return -1;
2524}
2525
2526
2536static void
2538 const struct GNUNET_HashCode *local_session_id)
2539{
2540 const char *salt = "gnunet-service-consensus/session_id";
2541
2545 sizeof(struct GNUNET_HashCode),
2546 salt,
2547 strlen (salt),
2548 session->peers,
2549 session->num_peers * sizeof(struct
2551 GNUNET_CRYPTO_kdf_arg_auto (local_session_id)));
2552}
2553
2554
2562static int
2563peer_id_cmp (const void *h1,
2564 const void *h2)
2565{
2566 return memcmp (h1, h2, sizeof(struct GNUNET_PeerIdentity));
2567}
2568
2569
2577static void
2579 struct ConsensusSession *session,
2580 const struct GNUNET_CONSENSUS_JoinMessage *join_msg)
2581{
2582 const struct GNUNET_PeerIdentity *msg_peers
2583 = (const struct GNUNET_PeerIdentity *) &join_msg[1];
2584 int local_peer_in_list;
2585
2586 session->num_peers = ntohl (join_msg->num_peers);
2587
2588 /* Peers in the join message, may or may not include the local peer,
2589 Add it if it is missing. */
2590 local_peer_in_list = GNUNET_NO;
2591 for (unsigned int i = 0; i < session->num_peers; i++)
2592 {
2593 if (0 == GNUNET_memcmp (&msg_peers[i],
2594 &my_peer))
2595 {
2596 local_peer_in_list = GNUNET_YES;
2597 break;
2598 }
2599 }
2600 if (GNUNET_NO == local_peer_in_list)
2601 session->num_peers++;
2602
2603 session->peers = GNUNET_new_array (session->num_peers,
2604 struct GNUNET_PeerIdentity);
2605 if (GNUNET_NO == local_peer_in_list)
2606 session->peers[session->num_peers - 1] = my_peer;
2607 GNUNET_memcpy (session->peers,
2608 msg_peers,
2609 ntohl (join_msg->num_peers)
2610 * sizeof(struct GNUNET_PeerIdentity));
2611 qsort (session->peers,
2612 session->num_peers,
2613 sizeof (struct GNUNET_PeerIdentity),
2614 &peer_id_cmp);
2615}
2616
2617
2618static struct TaskEntry *
2619lookup_task (const struct ConsensusSession *session,
2620 const struct TaskKey *key)
2621{
2622 struct GNUNET_HashCode hash;
2623
2625 sizeof(struct TaskKey),
2626 &hash);
2628 "Looking up task hash %s\n",
2629 GNUNET_h2s (&hash));
2631 &hash);
2632}
2633
2634
2650static void
2651set_listen_cb (void *cls,
2652 const struct GNUNET_PeerIdentity *other_peer,
2653 const struct GNUNET_MessageHeader *context_msg,
2655{
2656 struct ConsensusSession *session = cls;
2657 struct TaskKey tk;
2658 struct TaskEntry *task;
2660
2661 if (NULL == context_msg)
2662 {
2663 GNUNET_break_op (0);
2664 return;
2665 }
2666
2668 context_msg->type))
2669 {
2670 GNUNET_break_op (0);
2671 return;
2672 }
2673
2674 if (sizeof(struct GNUNET_CONSENSUS_RoundContextMessage) != ntohs (
2675 context_msg->size))
2676 {
2677 GNUNET_break_op (0);
2678 return;
2679 }
2680
2681 cm = (struct GNUNET_CONSENSUS_RoundContextMessage *) context_msg;
2682
2683 tk = ((struct TaskKey) {
2684 .kind = ntohs (cm->kind),
2685 .peer1 = ntohs (cm->peer1),
2686 .peer2 = ntohs (cm->peer2),
2687 .repetition = ntohs (cm->repetition),
2688 .leader = ntohs (cm->leader),
2689 });
2690
2691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "P%u: got req for task %s\n",
2692 session->local_peer_idx, debug_str_task_key (&tk));
2693
2694 task = lookup_task (session, &tk);
2695
2696 if (NULL == task)
2697 {
2698 GNUNET_break_op (0);
2699 return;
2700 }
2701
2702 if (GNUNET_YES == task->is_finished)
2703 {
2704 GNUNET_break_op (0);
2705 return;
2706 }
2707
2708 if (task->key.peer2 != session->local_peer_idx)
2709 {
2710 /* We're being asked, so we must be the 2nd peer. */
2711 GNUNET_break_op (0);
2712 return;
2713 }
2714
2715 GNUNET_assert (! ((task->key.peer1 == session->local_peer_idx) &&
2716 (task->key.peer2 == session->local_peer_idx)));
2717
2718 {
2719 struct GNUNET_SET_Option opts[] = {
2720 { GNUNET_SET_OPTION_BYZANTINE, { .num = session->lower_bound } },
2722 };
2723
2726 opts,
2728 task);
2729 }
2730 /* If the task hasn't been started yet,
2731 we wait for that until we commit. */
2732
2733 if (GNUNET_YES == task->is_started)
2734 {
2735 commit_set (session, task);
2736 }
2737}
2738
2739
2740static void
2742 struct TaskEntry *t)
2743{
2744 struct GNUNET_HashCode round_hash;
2745 struct Step *s;
2746
2747 GNUNET_assert (NULL != t->step);
2748 t = GNUNET_memdup (t, sizeof(struct TaskEntry));
2749 s = t->step;
2750 if (s->tasks_len == s->tasks_cap)
2751 {
2752 unsigned int target_size = 3 * (s->tasks_cap + 1) / 2;
2754 s->tasks_cap,
2755 target_size);
2756 }
2757
2758#ifdef GNUNET_EXTRA_LOGGING
2759 GNUNET_assert (NULL != s->debug_name);
2760 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting task <%s> into step `%s'\n",
2761 debug_str_task_key (&t->key),
2762 s->debug_name);
2763#endif
2764
2765 s->tasks[s->tasks_len] = t;
2766 s->tasks_len++;
2767
2768 GNUNET_CRYPTO_hash (&t->key,
2769 sizeof(struct TaskKey),
2770 &round_hash);
2773 &round_hash,
2774 t,
2776}
2777
2778
2779static void
2781{
2782 /* Given the fully constructed task graph
2783 with rounds for tasks, we can give the tasks timeouts. */
2784
2785 // unsigned int max_round;
2786
2787 /* XXX: implement! */
2788}
2789
2790
2791/*
2792 * Arrange two peers in some canonical order.
2793 */
2794static void
2795arrange_peers (uint16_t *p1,
2796 uint16_t *p2,
2797 uint16_t n)
2798{
2799 uint16_t a;
2800 uint16_t b;
2801
2802 GNUNET_assert (*p1 < n);
2803 GNUNET_assert (*p2 < n);
2804
2805 if (*p1 < *p2)
2806 {
2807 a = *p1;
2808 b = *p2;
2809 }
2810 else
2811 {
2812 a = *p2;
2813 b = *p1;
2814 }
2815
2816 /* For uniformly random *p1, *p2,
2817 this condition is true with 50% chance */
2818 if (((b - a) + n) % n <= n / 2)
2819 {
2820 *p1 = a;
2821 *p2 = b;
2822 }
2823 else
2824 {
2825 *p1 = b;
2826 *p2 = a;
2827 }
2828}
2829
2830
2834static void
2835step_depend_on (struct Step *step,
2836 struct Step *dep)
2837{
2838 /* We're not checking for cyclic dependencies,
2839 but this is a cheap sanity check. */
2840 GNUNET_assert (step != dep);
2841 GNUNET_assert (NULL != step);
2842 GNUNET_assert (NULL != dep);
2843 GNUNET_assert (dep->round <= step->round);
2844
2845#ifdef GNUNET_EXTRA_LOGGING
2846 /* Make sure we have complete debugging information.
2847 Also checks that we don't screw up too badly
2848 constructing the task graph. */
2849 GNUNET_assert (NULL != step->debug_name);
2850 GNUNET_assert (NULL != dep->debug_name);
2852 "Making step `%s' depend on `%s'\n",
2853 step->debug_name,
2854 dep->debug_name);
2855#endif
2856
2857 if (dep->subordinates_cap == dep->subordinates_len)
2858 {
2859 unsigned int target_size = 3 * (dep->subordinates_cap + 1) / 2;
2861 dep->subordinates_cap,
2862 target_size);
2863 }
2864
2866
2867 dep->subordinates[dep->subordinates_len] = step;
2868 dep->subordinates_len++;
2869
2870 step->pending_prereq++;
2871}
2872
2873
2874static struct Step *
2876 int round,
2877 int early_finishable)
2878{
2879 struct Step *step;
2880
2881 step = GNUNET_new (struct Step);
2882 step->session = session;
2883 step->round = round;
2887 step);
2888 return step;
2889}
2890
2891
2895static void
2897 uint16_t rep,
2898 uint16_t lead,
2899 struct Step *step_before,
2900 struct Step *step_after)
2901{
2902 uint16_t n = session->num_peers;
2903 uint16_t me = session->local_peer_idx;
2904 uint16_t p1;
2905 uint16_t p2;
2906 /* The task we're currently setting up. */
2907 struct TaskEntry task;
2908 struct Step *step;
2909 struct Step *prev_step;
2910 uint16_t round;
2911
2912 round = step_before->round + 1;
2913
2914 /* gcast step 1: leader disseminates */
2915 step = create_step (session,
2916 round,
2917 GNUNET_YES);
2918#ifdef GNUNET_EXTRA_LOGGING
2920 "disseminate leader %u rep %u",
2921 lead,
2922 rep);
2923#endif
2924 step_depend_on (step,
2925 step_before);
2926
2927 if (lead == me)
2928 {
2929 for (unsigned int k = 0; k < n; k++)
2930 {
2931 if (k == me)
2932 continue;
2933 p1 = me;
2934 p2 = k;
2935 arrange_peers (&p1, &p2, n);
2936 task = ((struct TaskEntry) {
2937 .step = step,
2938 .start = task_start_reconcile,
2939 .cancel = task_cancel_reconcile,
2940 .key = (struct TaskKey) { PHASE_KIND_GRADECAST_LEADER, p1, p2, rep,
2941 me },
2942 });
2943 task.cls.setop.input_set = (struct SetKey) { SET_KIND_CURRENT, rep };
2944 put_task (session->taskmap, &task);
2945 }
2946 /* We run this task to make sure that the leader
2947 has the stored the SET_KIND_LEADER set of himself,
2948 so it can participate in the rest of the gradecast
2949 without the code having to handle any special cases. */
2950 task = ((struct TaskEntry) {
2951 .step = step,
2952 .key = (struct TaskKey) { PHASE_KIND_GRADECAST_LEADER, me, me, rep, me },
2953 .start = task_start_reconcile,
2954 .cancel = task_cancel_reconcile,
2955 });
2956 task.cls.setop.input_set = (struct SetKey) { SET_KIND_CURRENT, rep };
2957 task.cls.setop.output_set = (struct SetKey) { SET_KIND_LEADER_PROPOSAL, rep,
2958 me };
2960 rep, me };
2961 put_task (session->taskmap, &task);
2962 }
2963 else
2964 {
2965 p1 = me;
2966 p2 = lead;
2967 arrange_peers (&p1, &p2, n);
2968 task = ((struct TaskEntry) {
2969 .step = step,
2970 .key = (struct TaskKey) { PHASE_KIND_GRADECAST_LEADER, p1, p2, rep,
2971 lead },
2972 .start = task_start_reconcile,
2973 .cancel = task_cancel_reconcile,
2974 });
2975 task.cls.setop.input_set = (struct SetKey) { SET_KIND_CURRENT, rep };
2976 task.cls.setop.output_set = (struct SetKey) { SET_KIND_LEADER_PROPOSAL, rep,
2977 lead };
2979 rep, lead };
2980 put_task (session->taskmap, &task);
2981 }
2982
2983 /* gcast phase 2: echo */
2984 prev_step = step;
2985 round += 1;
2986 step = create_step (session,
2987 round,
2988 GNUNET_YES);
2989#ifdef GNUNET_EXTRA_LOGGING
2991 "echo leader %u rep %u",
2992 lead,
2993 rep);
2994#endif
2995 step_depend_on (step,
2996 prev_step);
2997
2998 for (unsigned int k = 0; k < n; k++)
2999 {
3000 p1 = k;
3001 p2 = me;
3002 arrange_peers (&p1, &p2, n);
3003 task = ((struct TaskEntry) {
3004 .step = step,
3005 .key = (struct TaskKey) { PHASE_KIND_GRADECAST_ECHO, p1, p2, rep, lead },
3006 .start = task_start_reconcile,
3007 .cancel = task_cancel_reconcile,
3008 });
3009 task.cls.setop.input_set = (struct SetKey) { SET_KIND_LEADER_PROPOSAL, rep,
3010 lead };
3011 task.cls.setop.output_rfn = (struct RfnKey) { RFN_KIND_ECHO, rep, lead };
3012 put_task (session->taskmap, &task);
3013 }
3014
3015 prev_step = step;
3016 /* Same round, since step only has local tasks */
3017 step = create_step (session, round, GNUNET_YES);
3018#ifdef GNUNET_EXTRA_LOGGING
3019 GNUNET_asprintf (&step->debug_name, "echo grade leader %u rep %u", lead, rep);
3020#endif
3021 step_depend_on (step, prev_step);
3022
3023 arrange_peers (&p1, &p2, n);
3024 task = ((struct TaskEntry) {
3025 .key = (struct TaskKey) { PHASE_KIND_GRADECAST_ECHO_GRADE, -1, -1, rep,
3026 lead },
3027 .step = step,
3028 .start = task_start_eval_echo
3029 });
3030 put_task (session->taskmap, &task);
3031
3032 prev_step = step;
3033 round += 1;
3034 step = create_step (session, round, GNUNET_YES);
3035#ifdef GNUNET_EXTRA_LOGGING
3036 GNUNET_asprintf (&step->debug_name, "confirm leader %u rep %u", lead, rep);
3037#endif
3038 step_depend_on (step, prev_step);
3039
3040 /* gcast phase 3: confirmation and grading */
3041 for (unsigned int k = 0; k < n; k++)
3042 {
3043 p1 = k;
3044 p2 = me;
3045 arrange_peers (&p1, &p2, n);
3046 task = ((struct TaskEntry) {
3047 .step = step,
3048 .start = task_start_reconcile,
3049 .cancel = task_cancel_reconcile,
3050 .key = (struct TaskKey) { PHASE_KIND_GRADECAST_CONFIRM, p1, p2, rep,
3051 lead },
3052 });
3053 task.cls.setop.input_set = (struct SetKey) { SET_KIND_ECHO_RESULT, rep,
3054 lead };
3055 task.cls.setop.output_rfn = (struct RfnKey) { RFN_KIND_CONFIRM, rep, lead };
3056 /* If there was at least one element in the echo round that was
3057 contested (i.e. it had no n-t majority), then we let the other peers
3058 know, and other peers let us know. The contested flag for each peer is
3059 stored in the rfn. */
3061 put_task (session->taskmap, &task);
3062 }
3063
3064 prev_step = step;
3065 /* Same round, since step only has local tasks */
3066 step = create_step (session, round, GNUNET_YES);
3067#ifdef GNUNET_EXTRA_LOGGING
3068 GNUNET_asprintf (&step->debug_name, "confirm grade leader %u rep %u", lead,
3069 rep);
3070#endif
3071 step_depend_on (step, prev_step);
3072
3073 task = ((struct TaskEntry) {
3074 .step = step,
3075 .key = (struct TaskKey) { PHASE_KIND_GRADECAST_CONFIRM_GRADE, -1, -1, rep,
3076 lead },
3077 .start = task_start_grade,
3078 });
3079 put_task (session->taskmap, &task);
3080
3081 step_depend_on (step_after, step);
3082}
3083
3084
3085static void
3087{
3088 uint16_t n = session->num_peers;
3089 uint16_t t = n / 3;
3090 uint16_t me = session->local_peer_idx;
3091 /* The task we're currently setting up. */
3092 struct TaskEntry task;
3093 /* Current leader */
3094 unsigned int lead;
3095 struct Step *step;
3096 struct Step *prev_step;
3097 unsigned int round = 0;
3098
3099 // XXX: introduce first step,
3100 // where we wait for all insert acks
3101 // from the set service
3102
3103 /* faster but brittle all-to-all */
3104
3105 // XXX: Not implemented yet
3106
3107 /* all-to-all step */
3108
3110
3111#ifdef GNUNET_EXTRA_LOGGING
3112 step->debug_name = GNUNET_strdup ("all to all");
3113#endif
3114
3115 for (unsigned int i = 0; i < n; i++)
3116 {
3117 uint16_t p1;
3118 uint16_t p2;
3119
3120 p1 = me;
3121 p2 = i;
3122 arrange_peers (&p1, &p2, n);
3123 task = ((struct TaskEntry) {
3124 .key = (struct TaskKey) { PHASE_KIND_ALL_TO_ALL, p1, p2, -1, -1 },
3125 .step = step,
3126 .start = task_start_reconcile,
3127 .cancel = task_cancel_reconcile,
3128 });
3129 task.cls.setop.input_set = (struct SetKey) { SET_KIND_CURRENT, 0 };
3130 task.cls.setop.output_set = task.cls.setop.input_set;
3132 put_task (session->taskmap, &task);
3133 }
3134
3135 round += 1;
3136 prev_step = step;
3137 step = create_step (session, round, GNUNET_NO);;
3138#ifdef GNUNET_EXTRA_LOGGING
3139 step->debug_name = GNUNET_strdup ("all to all 2");
3140#endif
3141 step_depend_on (step, prev_step);
3142
3143
3144 for (unsigned int i = 0; i < n; i++)
3145 {
3146 uint16_t p1;
3147 uint16_t p2;
3148
3149 p1 = me;
3150 p2 = i;
3151 arrange_peers (&p1, &p2, n);
3152 task = ((struct TaskEntry) {
3153 .key = (struct TaskKey) { PHASE_KIND_ALL_TO_ALL_2, p1, p2, -1, -1 },
3154 .step = step,
3155 .start = task_start_reconcile,
3156 .cancel = task_cancel_reconcile,
3157 });
3158 task.cls.setop.input_set = (struct SetKey) { SET_KIND_CURRENT, 0 };
3159 task.cls.setop.output_set = task.cls.setop.input_set;
3161 put_task (session->taskmap, &task);
3162 }
3163
3164 round += 1;
3165
3166 prev_step = step;
3167 step = NULL;
3168
3169
3170 /* Byzantine union */
3171
3172 /* sequential repetitions of the gradecasts */
3173 for (unsigned int i = 0; i < t + 1; i++)
3174 {
3175 struct Step *step_rep_start;
3176 struct Step *step_rep_end;
3177
3178 /* Every repetition is in a separate round. */
3179 step_rep_start = create_step (session, round, GNUNET_YES);
3180#ifdef GNUNET_EXTRA_LOGGING
3181 GNUNET_asprintf (&step_rep_start->debug_name, "gradecast start rep %u", i);
3182#endif
3183
3184 step_depend_on (step_rep_start, prev_step);
3185
3186 /* gradecast has three rounds */
3187 round += 3;
3188 step_rep_end = create_step (session, round, GNUNET_YES);
3189#ifdef GNUNET_EXTRA_LOGGING
3190 GNUNET_asprintf (&step_rep_end->debug_name, "gradecast end rep %u", i);
3191#endif
3192
3193 /* parallel gradecasts */
3194 for (lead = 0; lead < n; lead++)
3195 construct_task_graph_gradecast (session, i, lead, step_rep_start,
3196 step_rep_end);
3197
3198 task = ((struct TaskEntry) {
3199 .step = step_rep_end,
3200 .key = (struct TaskKey) { PHASE_KIND_APPLY_REP, -1, -1, i, -1 },
3201 .start = task_start_apply_round,
3202 });
3203 put_task (session->taskmap, &task);
3204
3205 prev_step = step_rep_end;
3206 }
3207
3208 /* There is no next gradecast round, thus the final
3209 start step is the overall end step of the gradecasts */
3210 round += 1;
3211 step = create_step (session, round, GNUNET_NO);
3212#ifdef GNUNET_EXTRA_LOGGING
3213 GNUNET_asprintf (&step->debug_name, "finish");
3214#endif
3215 step_depend_on (step, prev_step);
3216
3217 task = ((struct TaskEntry) {
3218 .step = step,
3219 .key = (struct TaskKey) { PHASE_KIND_FINISH, -1, -1, -1, -1 },
3220 .start = task_start_finish,
3221 });
3223
3224 put_task (session->taskmap, &task);
3225}
3226
3227
3235static int
3237 const struct GNUNET_CONSENSUS_JoinMessage *m)
3238{
3239 uint32_t listed_peers = ntohl (m->num_peers);
3240
3241 if ((ntohs (m->header.size) - sizeof(*m)) !=
3242 listed_peers * sizeof(struct GNUNET_PeerIdentity))
3243 {
3244 GNUNET_break (0);
3245 return GNUNET_SYSERR;
3246 }
3247 return GNUNET_OK;
3248}
3249
3250
3257static void
3259 const struct GNUNET_CONSENSUS_JoinMessage *m)
3260{
3261 struct ConsensusSession *session = cls;
3262 struct ConsensusSession *other_session;
3263
3265 m);
3266 compute_global_id (session,
3267 &m->session_id);
3268
3269 /* Check if some local client already owns the session.
3270 It is only legal to have a session with an existing global id
3271 if all other sessions with this global id are finished.*/
3272 for (other_session = sessions_head;
3273 NULL != other_session;
3274 other_session = other_session->next)
3275 {
3276 if ( (other_session != session) &&
3277 (0 == GNUNET_CRYPTO_hash_cmp (&session->global_id,
3278 &other_session->global_id)) )
3279 break;
3280 }
3281
3282 session->conclude_deadline
3283 = GNUNET_TIME_absolute_ntoh (m->deadline);
3284 session->conclude_start
3285 = GNUNET_TIME_absolute_ntoh (m->start);
3286 session->local_peer_idx = get_peer_idx (&my_peer,
3287 session);
3288 GNUNET_assert (-1 != session->local_peer_idx);
3289
3291 "Joining consensus session %s containing %u peers as %u with timeout %s\n",
3292 GNUNET_h2s (&m->session_id),
3293 session->num_peers,
3294 session->local_peer_idx,
3297 session->conclude_deadline)
3298 ,
3299 GNUNET_YES));
3300
3301 session->set_listener
3304 &session->global_id,
3306 session);
3307
3309 GNUNET_NO);
3311 GNUNET_NO);
3313 GNUNET_NO);
3315 GNUNET_NO);
3316
3317 {
3318 struct SetEntry *client_set = GNUNET_new (struct SetEntry);
3319 struct SetHandle *sh = GNUNET_new (struct SetHandle);
3320
3321 client_set->h = GNUNET_SET_create (cfg,
3323 sh->h = client_set->h;
3325 session->set_handles_tail,
3326 sh);
3327 client_set->key = ((struct SetKey) { SET_KIND_CURRENT, 0, 0 });
3328 put_set (session,
3329 client_set);
3330 }
3331
3332 session->peers_blacklisted = GNUNET_new_array (session->num_peers,
3333 int);
3334
3335 /* Just construct the task graph,
3336 but don't run anything until the client calls conclude. */
3337 construct_task_graph (session);
3339}
3340
3341
3349static int
3352{
3353 return GNUNET_OK;
3354}
3355
3356
3363static void
3366{
3367 struct ConsensusSession *session = cls;
3368 ssize_t element_size;
3369 struct GNUNET_SET_Handle *initial_set;
3370 struct ConsensusElement *ce;
3371
3372 if (GNUNET_YES == session->conclude_started)
3373 {
3374 GNUNET_break (0);
3376 return;
3377 }
3378 element_size = ntohs (msg->header.size) - sizeof(*msg);
3379 ce = GNUNET_malloc (sizeof(struct ConsensusElement) + element_size);
3380 GNUNET_memcpy (&ce[1],
3381 &msg[1],
3382 element_size);
3383 ce->payload_type = msg->element_type;
3384
3385 {
3386 struct SetKey key = { SET_KIND_CURRENT, 0, 0 };
3387 struct SetEntry *entry;
3388
3389 entry = lookup_set (session,
3390 &key);
3391 GNUNET_assert (NULL != entry);
3392 initial_set = entry->h;
3393 }
3394
3395 session->num_client_insert_pending++;
3396
3397 {
3398 struct GNUNET_SET_Element element = {
3400 .size = sizeof(struct ConsensusElement) + element_size,
3401 .data = ce,
3402 };
3403
3404 GNUNET_SET_add_element (initial_set,
3405 &element,
3406 NULL,
3407 NULL);
3408#ifdef GNUNET_EXTRA_LOGGING
3410 "P%u: element %s added\n",
3411 session->local_peer_idx,
3412 debug_str_element (&element));
3413#endif
3414 }
3415 GNUNET_free (ce);
3417}
3418
3419
3426static void
3428 const struct GNUNET_MessageHeader *message)
3429{
3430 struct ConsensusSession *session = cls;
3431
3432 if (GNUNET_YES == session->conclude_started)
3433 {
3434 /* conclude started twice */
3435 GNUNET_break (0);
3437 return;
3438 }
3440 "conclude requested\n");
3441 session->conclude_started = GNUNET_YES;
3442 install_step_timeouts (session);
3443 run_ready_steps (session);
3445}
3446
3447
3453static void
3454shutdown_task (void *cls)
3455{
3457 "shutting down\n");
3459 GNUNET_NO);
3460 statistics = NULL;
3461}
3462
3463
3471static void
3472run (void *cls,
3473 const struct GNUNET_CONFIGURATION_Handle *c,
3475{
3476 cfg = c;
3477 if (GNUNET_OK !=
3479 &my_peer))
3480 {
3482 "Could not retrieve host identity\n");
3484 return;
3485 }
3486 statistics = GNUNET_STATISTICS_create ("consensus",
3487 cfg);
3489 NULL);
3490}
3491
3492
3501static void *
3503 struct GNUNET_SERVICE_Client *c,
3504 struct GNUNET_MQ_Handle *mq)
3505{
3506 struct ConsensusSession *session = GNUNET_new (struct ConsensusSession);
3507
3508 session->client = c;
3509 session->client_mq = mq;
3512 session);
3513 return session;
3514}
3515
3516
3524static void
3526 struct GNUNET_SERVICE_Client *c,
3527 void *internal_cls)
3528{
3529 struct ConsensusSession *session = internal_cls;
3530
3531 if (NULL != session->set_listener)
3532 {
3534 session->set_listener = NULL;
3535 }
3538 session);
3539 while (session->set_handles_head)
3540 {
3541 struct SetHandle *sh = session->set_handles_head;
3542
3543 session->set_handles_head = sh->next;
3545 GNUNET_free (sh);
3546 }
3547 GNUNET_free (session);
3548}
3549
3550
3556 "consensus",
3558 &run,
3561 NULL,
3562 GNUNET_MQ_hd_fixed_size (client_conclude,
3564 struct GNUNET_MessageHeader,
3565 NULL),
3566 GNUNET_MQ_hd_var_size (client_insert,
3569 NULL),
3570 GNUNET_MQ_hd_var_size (client_join,
3573 NULL),
3575
3576/* end of gnunet-service-consensus.c */
struct GNUNET_MessageHeader * msg
Definition 005.c:2
p2p message definitions for consensus
@ CONSENSUS_MARKER_CONTESTED
@ CONSENSUS_MARKER_SIZE
static mp_limb_t d[(((256)+GMP_NUMB_BITS - 1)/GMP_NUMB_BITS)]
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition gnunet-arm.c:103
static int ret
Final status code.
Definition gnunet-arm.c:93
static unsigned int phase
Processing stage that we are in.
Definition gnunet-arm.c:113
static GNUNET_NETWORK_STRUCT_END struct GNUNET_PeerIdentity me
Our own peer identity.
static char * data
The data to insert into the dht.
struct GNUNET_HashCode key
The key used in the DHT.
static struct GNUNET_IDENTITY_Handle * sh
Handle to IDENTITY service.
struct GNUNET_SCHEDULER_Task * shutdown_task
static struct GNUNET_SCHEDULER_Task * t
Main task.
static uint32_t type
Type string converted to DNS type value.
static int status
The program status; 0 for success.
Definition gnunet-nse.c:39
static struct GNUNET_FS_PublishContext * pc
Handle to FS-publishing operation.
static struct GNUNET_IDENTITY_EgoLookup * el
Handle for our ego lookup.
static struct GNUNET_CRYPTO_PowSalt salt
Salt for PoW calculations.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static void rfn_contest(struct ReferendumEntry *rfn, uint16_t contested_peer)
static void rfn_vote(struct ReferendumEntry *rfn, uint16_t voting_peer, enum ReferendumVote vote, const struct GNUNET_SET_Element *element)
static void handle_client_join(void *cls, const struct GNUNET_CONSENSUS_JoinMessage *m)
Called when a client wants to join a consensus session.
static int get_peer_idx(const struct GNUNET_PeerIdentity *peer, const struct ConsensusSession *session)
Search peer in the list of peers in session.
static void task_start_grade(struct TaskEntry *task)
static struct ConsensusSession * sessions_head
Linked list of sessions this peer participates in.
static uint16_t task_other_peer(struct TaskEntry *task)
static void handle_client_insert(void *cls, const struct GNUNET_CONSENSUS_ElementMessage *msg)
Called when a client performs an insert operation.
static struct SetEntry * lookup_set(struct ConsensusSession *session, const struct SetKey *key)
static void apply_diff_to_rfn(struct DiffEntry *diff, struct ReferendumEntry *rfn, uint16_t voting_peer, uint16_t num_peers)
static struct Step * create_step(struct ConsensusSession *session, int round, int early_finishable)
static void arrange_peers(uint16_t *p1, uint16_t *p2, uint16_t n)
static void start_task(struct ConsensusSession *session, struct TaskEntry *task)
static void initialize_session_peer_list(struct ConsensusSession *session, const struct GNUNET_CONSENSUS_JoinMessage *join_msg)
Create the sorted list of peers for the session, add the local peer if not in the join message.
@ DIFF_KIND_LEADER_PROPOSAL
@ DIFF_KIND_LEADER_CONSENSUS
@ DIFF_KIND_GRADECAST_RESULT
static void compute_global_id(struct ConsensusSession *session, const struct GNUNET_HashCode *local_session_id)
Compute a global, (hopefully) unique consensus session id, from the local id of the consensus session...
static void set_listen_cb(void *cls, const struct GNUNET_PeerIdentity *other_peer, const struct GNUNET_MessageHeader *context_msg, struct GNUNET_SET_Request *request)
Called when another peer wants to do a set operation with the local peer.
@ PHASE_KIND_GRADECAST_CONFIRM
@ PHASE_KIND_GRADECAST_ECHO
@ PHASE_KIND_ALL_TO_ALL_2
@ PHASE_KIND_APPLY_REP
Apply a repetition of the all-to-all gradecast to the current set.
@ PHASE_KIND_GRADECAST_LEADER
@ PHASE_KIND_GRADECAST_ECHO_GRADE
@ PHASE_KIND_GRADECAST_CONFIRM_GRADE
@ PHASE_KIND_ALL_TO_ALL
static struct DiffEntry * lookup_diff(struct ConsensusSession *session, const struct DiffKey *key)
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration of the consensus service.
static void finish_step(struct Step *step)
static int peer_id_cmp(const void *h1, const void *h2)
Compare two peer identities (for qsort()).
static void put_rfn(struct ConsensusSession *session, struct ReferendumEntry *rfn)
static void put_diff(struct ConsensusSession *session, struct DiffEntry *diff)
static void try_finish_step_early(struct Step *step)
static void put_set(struct ConsensusSession *session, struct SetEntry *set)
struct GNUNET_STATISTICS_Handle * statistics
Statistics handle.
static void task_cancel_reconcile(struct TaskEntry *task)
static const char * setname(uint16_t kind)
static void construct_task_graph(struct ConsensusSession *session)
@ VOTE_ADD
Vote that an element should be added.
@ VOTE_REMOVE
Vote that an element should be removed.
@ VOTE_STAY
Vote that nothing should change.
static void diff_insert(struct DiffEntry *diff, int weight, const struct GNUNET_SET_Element *element)
static void put_task(struct GNUNET_CONTAINER_MultiHashMap *taskmap, struct TaskEntry *t)
static void finish_task(struct TaskEntry *task)
static void construct_task_graph_gradecast(struct ConsensusSession *session, uint16_t rep, uint16_t lead, struct Step *step_before, struct Step *step_after)
Construct the task graph for a single gradecast.
static int check_client_join(void *cls, const struct GNUNET_CONSENSUS_JoinMessage *m)
Check join message.
@ RFN_KIND_GRADECAST_RESULT
static void task_start_finish(struct TaskEntry *task)
static void rfn_majority(const struct ReferendumEntry *rfn, const struct RfnElementInfo *ri, uint16_t *ret_majority, enum ReferendumVote *ret_vote)
For a given majority, count what the outcome is (add/remove/keep), and give the number of peers that ...
static void run_ready_steps(struct ConsensusSession *session)
static const char * phasename(uint16_t phase)
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *c, struct GNUNET_SERVICE_Handle *service)
Start processing consensus requests.
static struct ConsensusSession * sessions_tail
Linked list of sessions this peer participates in.
static void task_start_reconcile(struct TaskEntry *task)
static void step_depend_on(struct Step *step, struct Step *dep)
Record dep as a dependency of step.
static void install_step_timeouts(struct ConsensusSession *session)
static struct ReferendumEntry * lookup_rfn(struct ConsensusSession *session, const struct RfnKey *key)
static struct TaskEntry * lookup_task(const struct ConsensusSession *session, const struct TaskKey *key)
static void set_copy_cb(void *cls, struct GNUNET_SET_Handle *copy)
static void create_set_copy_for_task(struct TaskEntry *task, struct SetKey *src_set_key, struct SetKey *dst_set_key)
Call the start function of the given task again after we created a copy of the given set.
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq)
Callback called when a client connects to the service.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
Callback called when a client disconnected from the service.
static uint16_t rfn_noncontested(struct ReferendumEntry *rfn)
static void set_result_cb(void *cls, const struct GNUNET_SET_Element *element, uint64_t current_size, enum GNUNET_SET_Status status)
Callback for set operation results.
@ SET_KIND_ECHO_RESULT
@ SET_KIND_LEADER_PROPOSAL
@ SET_KIND_LAST_GRADECAST
Last result set from a gradecast.
static int cmp_uint64_t(const void *pa, const void *pb)
static const char * rfnname(uint16_t kind)
static void commit_set(struct ConsensusSession *session, struct TaskEntry *task)
Commit the appropriate set for a task.
static struct ReferendumEntry * rfn_create(uint16_t size)
static const char * diffname(uint16_t kind)
static struct DiffEntry * diff_create(void)
static void rfn_commit(struct ReferendumEntry *rfn, uint16_t commit_peer)
static void task_start_apply_round(struct TaskEntry *task)
Apply the result from one round of gradecasts (i.e.
static int check_client_insert(void *cls, const struct GNUNET_CONSENSUS_ElementMessage *msg)
Called when a client performs an insert operation.
@ EARLY_STOPPING_DONE
@ EARLY_STOPPING_NONE
@ EARLY_STOPPING_ONE_MORE
static int send_to_client_iter(void *cls, const struct GNUNET_SET_Element *element)
Send the final result set of the consensus to the client, element by element.
static struct GNUNET_PeerIdentity my_peer
Peer that runs this service.
void(* TaskFunc)(struct TaskEntry *task)
static void set_mutation_done(void *cls)
static void task_start_eval_echo(struct TaskEntry *task)
static void handle_client_conclude(void *cls, const struct GNUNET_MessageHeader *message)
Called when a client performs the conclude operation.
static void cleanup()
Cleanup task.
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition gnunet-vpn.c:40
@ GNUNET_BLOCK_TYPE_CONSENSUS_ELEMENT
Block type for consensus elements.
static unsigned int num_peers
Number of peers.
Constants for network protocols.
Two-peer set operations.
API to create, modify and access statistics.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_get_peer_identity(const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_PeerIdentity *dst)
Retrieve the identity of the host's peer.
@ GNUNET_CRYPTO_QUALITY_WEAK
No good quality of the operation is needed (i.e., random numbers can be pseudo-random).
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition crypto_hash.c:41
void GNUNET_CRYPTO_hash_create_random(enum GNUNET_CRYPTO_Quality mode, struct GNUNET_HashCode *result)
Create a random hash code.
#define GNUNET_CRYPTO_hkdf_gnunet(result, out_len, xts, xts_len, skm, skm_len,...)
A peculiar HKDF instantiation that tried to mimic Truncated NMAC.
int GNUNET_CRYPTO_hash_cmp(const struct GNUNET_HashCode *h1, const struct GNUNET_HashCode *h2)
Compare function for HashCodes, producing a total ordering of all hashcodes.
void * GNUNET_CONTAINER_multihashmap_get(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Given a key find a value in the map matching the key.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_iterator_next(struct GNUNET_CONTAINER_MultiHashMapIterator *iter, struct GNUNET_HashCode *key, const void **value)
Retrieve the next element from the hash map at the iterator's position.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
void GNUNET_CONTAINER_multihashmap_iterator_destroy(struct GNUNET_CONTAINER_MultiHashMapIterator *iter)
Destroy a multihashmap iterator.
struct GNUNET_CONTAINER_MultiHashMapIterator * GNUNET_CONTAINER_multihashmap_iterator_create(const struct GNUNET_CONTAINER_MultiHashMap *map)
Create an iterator for a multihashmap.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST
, ' bother checking if a value already exists (faster than GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE...
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY
There must only be one value per key; storing a value should fail if a value under the same key alrea...
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE
If a value with the given key exists, replace it.
#define GNUNET_NETWORK_STRUCT_BEGIN
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
#define GNUNET_NETWORK_STRUCT_END
Define as empty, GNUNET_PACKED should suffice, but this won't work on W32;.
#define GNUNET_memcmp(a, b)
Compare memory in a and b, where both must be of the same pointer type.
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
#define GNUNET_CRYPTO_kdf_arg_auto(d)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_MIN(a, b)
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
#define GNUNET_PACKED
gcc-ism to get packed structs.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
const char * GNUNET_h2s(const struct GNUNET_HashCode *hc)
Convert a hash value to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_memdup(buf, size)
Allocate and initialize a block of memory.
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:305
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
#define GNUNET_MQ_msg_header(type)
Allocate a GNUNET_MQ_Envelope, where the message only consists of a header.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
const struct GNUNET_OS_ProjectData * GNUNET_OS_project_data_gnunet(void)
Return default project data used by 'libgnunetutil' for GNUnet.
#define GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_JOIN
Join a consensus session.
#define GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE_DONE
Sent by service to client in order to signal a completed consensus conclusion.
#define GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_RECEIVED_ELEMENT
Sent by service when a new element is added.
#define GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_INSERT
Insert an element.
#define GNUNET_MESSAGE_TYPE_CONSENSUS_CLIENT_CONCLUDE
Sent by client to service in order to start the consensus conclusion.
#define GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_ROUND_CONTEXT
Provide context for a consensus round.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition scheduler.c:572
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition scheduler.c:1345
#define GNUNET_SERVICE_MAIN(pd, service_name, service_options, init_cb, connect_cb, disconnect_cb, cls,...)
Creates the "main" function for a GNUnet service.
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition service.c:2463
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2434
@ GNUNET_SERVICE_OPTION_NONE
Use defaults.
GNUNET_SET_Status
Status for the result callback.
void GNUNET_SET_destroy(struct GNUNET_SET_Handle *set)
Destroy the set handle if no operations are left, mark the set for destruction otherwise.
Definition set_api.c:745
void GNUNET_SET_copy_lazy(struct GNUNET_SET_Handle *set, GNUNET_SET_CopyReadyCallback cb, void *cls)
Definition set_api.c:1139
struct GNUNET_SET_Element * GNUNET_SET_element_dup(const struct GNUNET_SET_Element *element)
Create a copy of an element.
Definition set_api.c:1168
void GNUNET_SET_listen_cancel(struct GNUNET_SET_ListenHandle *lh)
Cancel the given listen operation.
Definition set_api.c:1010
int GNUNET_SET_remove_element(struct GNUNET_SET_Handle *set, const struct GNUNET_SET_Element *element, GNUNET_SET_Continuation cont, void *cont_cls)
Remove an element to the given set.
Definition set_api.c:707
int GNUNET_SET_iterate(struct GNUNET_SET_Handle *set, GNUNET_SET_ElementIterator iter, void *iter_cls)
Iterate over all elements in the given set.
Definition set_api.c:1117
void GNUNET_SET_operation_cancel(struct GNUNET_SET_OperationHandle *oh)
Cancel the given set operation.
Definition set_api.c:516
struct GNUNET_SET_Handle * GNUNET_SET_create(const struct GNUNET_CONFIGURATION_Handle *cfg, enum GNUNET_SET_OperationType op)
Create an empty set, supporting the specified operation.
Definition set_api.c:656
int GNUNET_SET_commit(struct GNUNET_SET_OperationHandle *oh, struct GNUNET_SET_Handle *set)
Commit a set to be used with a set operation.
Definition set_api.c:1073
struct GNUNET_SET_ListenHandle * GNUNET_SET_listen(const struct GNUNET_CONFIGURATION_Handle *cfg, enum GNUNET_SET_OperationType operation, const struct GNUNET_HashCode *app_id, GNUNET_SET_ListenCallback listen_cb, void *listen_cls)
Wait for set operation requests for the given application id.
Definition set_api.c:976
struct GNUNET_SET_OperationHandle * GNUNET_SET_prepare(const struct GNUNET_PeerIdentity *other_peer, const struct GNUNET_HashCode *app_id, const struct GNUNET_MessageHeader *context_msg, enum GNUNET_SET_ResultMode result_mode, struct GNUNET_SET_Option options[], GNUNET_SET_ResultIterator result_cb, void *result_cls)
Prepare a set operation to be evaluated with another peer.
Definition set_api.c:772
struct GNUNET_SET_OperationHandle * GNUNET_SET_accept(struct GNUNET_SET_Request *request, enum GNUNET_SET_ResultMode result_mode, struct GNUNET_SET_Option options[], GNUNET_SET_ResultIterator result_cb, void *result_cls)
Accept a request we got via GNUNET_SET_listen().
Definition set_api.c:1030
int GNUNET_SET_add_element(struct GNUNET_SET_Handle *set, const struct GNUNET_SET_Element *element, GNUNET_SET_Continuation cont, void *cont_cls)
Add an element to the given set.
Definition set_api.c:673
void GNUNET_SET_element_hash(const struct GNUNET_SET_Element *element, struct GNUNET_HashCode *ret_hash)
Hash a set element.
Definition set_api.c:1184
@ GNUNET_SET_STATUS_FAILURE
The other peer refused to to the operation with us, or something went wrong.
@ GNUNET_SET_STATUS_ADD_REMOTE
Element should be added to the result set of the remote peer, i.e.
@ GNUNET_SET_STATUS_DONE
Success, all elements have been sent (and received).
@ GNUNET_SET_STATUS_ADD_LOCAL
Element should be added to the result set of the local peer, i.e.
@ GNUNET_SET_OPTION_END
List terminator.
@ GNUNET_SET_OPTION_BYZANTINE
Fail set operations when the other peer shows weird behavior that might by a Byzantine fault.
@ GNUNET_SET_RESULT_SYMMETRIC
Client gets notified of the required changes for both the local and the remote set.
@ GNUNET_SET_OPERATION_UNION
Set union, return all elements that are in at least one of the sets.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
void GNUNET_STATISTICS_set(struct GNUNET_STATISTICS_Handle *handle, const char *name, uint64_t value, int make_persistent)
Set statistic value for the peer.
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition strings.c:604
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_ntoh(struct GNUNET_TIME_AbsoluteNBO a)
Convert absolute time from network byte order.
Definition time.c:737
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_difference(struct GNUNET_TIME_Absolute start, struct GNUNET_TIME_Absolute end)
Compute the time difference between the given start and end times.
Definition time.c:423
static unsigned int size
Size of the "table".
Definition peer.c:68
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
Consensus element, either marker or payload.
uint16_t payload_type
Payload element_type, only valid if this is not a marker element.
uint8_t marker
Is this a marker element?
A consensus session consists of one local client and the remote authorities.
struct GNUNET_HashCode global_id
Global consensus identification, computed from the session id and participating authorities.
struct GNUNET_TIME_Absolute conclude_start
Time when the conclusion of the consensus should begin.
struct GNUNET_CONTAINER_MultiHashMap * diffmap
struct SetHandle * set_handles_tail
struct GNUNET_CONTAINER_MultiHashMap * rfnmap
unsigned int local_peer_idx
Index of the local peer in the peers array.
unsigned int num_peers
Number of other peers in the consensus.
struct ConsensusSession * prev
Consensus sessions are kept in a DLL.
struct GNUNET_PeerIdentity * peers
struct GNUNET_TIME_Absolute conclude_deadline
Timeout for all rounds together, single rounds will schedule a timeout task with a fraction of the co...
struct GNUNET_MQ_Handle * client_mq
Queued messages to the client.
uint64_t first_size
Our set size from the first round.
struct GNUNET_SERVICE_Client * client
Client that inhabits the session.
struct GNUNET_SET_ListenHandle * set_listener
Listener for requests from other peers.
struct ConsensusSession * next
Consensus sessions are kept in a DLL.
int * peers_blacklisted
Array of peers with length 'num_peers'.
unsigned int num_client_insert_pending
uint64_t lower_bound
Bounded Eppstein lower bound.
struct SetHandle * set_handles_head
int early_stopping
State of our early stopping scheme.
struct GNUNET_CONTAINER_MultiHashMap * setmap
struct GNUNET_CONTAINER_MultiHashMap * taskmap
struct ConsensusElement ce
struct GNUNET_HashCode rand
struct ConsensusElement ce
int weight
Positive weight for 'add', negative weights for 'remove'.
const struct GNUNET_SET_Element * element
struct GNUNET_CONTAINER_MultiHashMap * changes
enum DiffKind diff_kind
struct SetKey input_set
Message with an element.
Definition consensus.h:73
Sent by the client to the service, when the client wants the service to join a consensus session.
Definition consensus.h:38
uint32_t num_peers
Number of peers (at the end of this message) that want to participate in the consensus.
Definition consensus.h:48
Sent as context message for set reconciliation.
int16_t repetition
Repetition of the gradecast phase.
int16_t peer1
Number of the first peer in canonical order.
int16_t leader
Leader in the gradecast phase.
int16_t peer2
Number of the second peer in canonical order.
struct GNUNET_MessageHeader header
Type: GNUNET_MESSAGE_TYPE_CONSENSUS_P2P_ROUND_CONTEXT.
uint16_t kind
A value from 'enum PhaseKind'.
uint16_t is_contested
Non-zero if this set reconciliation had elements removed because they were contested.
Internal representation of the hash map.
A 512-bit hashcode.
Handle to a message queue.
Definition mq.c:87
Header for all communications.
The identity of the host (wraps the signing key of the peer).
Entry in list of pending tasks.
Definition scheduler.c:141
Handle to a client that is connected to a service.
Definition service.c:249
Handle to a service.
Definition service.c:116
Element stored in a set.
uint16_t size
Number of bytes in the buffer pointed to by data.
const void * data
Actual data of the element.
uint16_t element_type
Application-specific element type.
Opaque handle to a set.
Definition set_api.c:50
Opaque handle to a listen operation.
Definition set_api.c:187
Handle to an operation.
Definition set_api.c:136
Option for set operations.
Handle for a set operation request from another peer.
Definition set_api.c:116
Handle for the service.
Time for absolute times used by GNUnet, in microseconds.
int * peer_commited
Stores, for every peer in the session, whether the peer finished the whole referendum.
struct GNUNET_CONTAINER_MultiHashMap * rfn_elements
int * peer_contested
Contestation state of the peer.
enum ReferendumVote proposal
Proposal for this element, can only be VOTE_ADD or VOTE_REMOVE.
int * votes
GNUNET_YES if the peer votes for the proposal.
const struct GNUNET_SET_Element * element
enum RfnKind rfn_kind
struct SetKey dst_set_key
struct TaskEntry * task
int is_contested
GNUNET_YES if the set resulted from applying a referendum with contested elements.
struct GNUNET_SET_Handle * h
struct SetHandle * prev
struct SetHandle * next
struct GNUNET_SET_Handle * h
int k1
Repetition counter.
int k2
Leader (or 0).
enum SetKind set_kind
struct TaskEntry * task
Task to finish once all changes are through.
struct SetKey output_set
struct DiffKey output_diff
struct RfnKey output_rfn
struct GNUNET_SET_OperationHandle * op
struct SetKey input_set
unsigned int subordinates_cap
unsigned int round
Synchrony round of the task.
int early_finishable
When we're doing an early finish, how should this step be treated? If GNUNET_YES, the step will be ma...
unsigned int tasks_len
unsigned int is_finished
struct GNUNET_SCHEDULER_Task * timeout_task
Task that will run this step despite any pending prerequisites.
size_t pending_prereq
Counter for the prerequisites of this step.
char * debug_name
Human-readable name for the task, used for debugging.
struct Step * next
All steps of one session are in a linked list for easier deallocation.
struct ConsensusSession * session
struct TaskEntry ** tasks
Tasks that this step is composed of.
unsigned int is_running
struct Step ** subordinates
unsigned int tasks_cap
unsigned int finished_tasks
struct Step * prev
All steps of one session are in a linked list for easier deallocation.
unsigned int subordinates_len
union TaskFuncCls cls
Tuple of integers that together identify a task uniquely.
uint16_t kind
A value from 'enum PhaseKind'.
int16_t peer1
Number of the first peer in canonical order.
int16_t peer2
Number of the second peer in canonical order.
int16_t repetition
Repetition of the gradecast phase.
int16_t leader
Leader in the gradecast phase.
enum GNUNET_TIME_RounderInterval ri
Definition time.c:1251
Closure for both start_task and cancel_task.
struct FinishCls finish
struct SetOpCls setop