1 module tagion.hashgraphview.Compare; 2 3 import std.algorithm.iteration : map; 4 import std.array : array; 5 import std.range : lockstep; 6 import tagion.hashgraph.Event; 7 import tagion.hashgraph.HashGraph; 8 import tagion.hashgraph.HashGraphBasic : higher; 9 10 @safe 11 struct Compare { 12 enum ErrorCode { 13 NONE, 14 NODES_DOES_NOT_MATCH, 15 FINGERPRINT_NOT_THE_SAME, 16 MOTHER_NOT_THE_SAME, 17 FATHER_NOT_THE_SAME, 18 ALTITUDE_NOT_THE_SAME, 19 ORDER_NOT_THE_SAME, 20 ROUND_NOT_THE_SAME, 21 ROUND_RECEIVED_NOT_THE_SAME, 22 WITNESS_CONFLICT, 23 } 24 25 alias ErrorCallback = bool delegate(const Event e1, const Event e2, const ErrorCode code) nothrow @safe; 26 const HashGraph h1, h2; 27 const ErrorCallback error_callback; 28 int order_offset; 29 long round_offset; 30 uint count; 31 this(const HashGraph h1, const HashGraph h2, const ErrorCallback error_callback) { 32 this.h1 = h1; 33 this.h2 = h2; 34 this.error_callback = error_callback; 35 } 36 37 bool compare() @trusted { 38 count = 0; 39 auto h1_nodes = h1.nodes 40 .byValue 41 .map!((n) => n[]) 42 .array; 43 typeof(h1_nodes) h2_nodes; 44 try { 45 h2_nodes = h1.nodes 46 .byValue 47 .map!((n) => h2.nodes[n.channel][]) 48 .array; 49 } 50 catch (Exception e) { 51 if (error_callback) { 52 error_callback(null, null, ErrorCode.NODES_DOES_NOT_MATCH); 53 } 54 return false; 55 } 56 bool ok = true; 57 58 foreach (ref h1_events, ref h2_events; lockstep(h1_nodes, h2_nodes)) { 59 while (!h1_events.empty && higher(h1_events.front.altitude, h2_events 60 .front.altitude)) { 61 h1_events.popFront; 62 } 63 while (!h2_events.empty && higher(h2_events.front.altitude, h1_events 64 .front.altitude)) { 65 h2_events.popFront; 66 } 67 bool check(bool ok, const ErrorCode code) { 68 if (!ok && error_callback) { 69 return error_callback(h1_events.front, h2_events.front, code); 70 } 71 return ok; 72 } 73 74 if (!h1_events.empty && !h2_events.empty) { 75 order_offset = h1_events.front.order - h2_events.front.order; 76 if (!h1_events.front.hasRound || !h2_events.front.hasRound) { 77 return error_callback(null, null, ErrorCode.NODES_DOES_NOT_MATCH); 78 } 79 round_offset = h1_events.front.round.number - h2_events.front.round.number; 80 } 81 //error_callback(h1_events.front, h2_events.front, ErrorCode.NONE); 82 while (!h1_events.empty && !h2_events.empty) { 83 const e1 = h1_events.front; 84 const e2 = h2_events.front; 85 86 with (ErrorCode) { 87 ok &= check(e1.fingerprint == e2.fingerprint, FINGERPRINT_NOT_THE_SAME); 88 ok &= check(e1.event_body.mother == e2.event_body.mother, MOTHER_NOT_THE_SAME); 89 ok &= check(e1.event_body.father == e2.event_body.father, FATHER_NOT_THE_SAME); 90 ok &= check(e1.altitude == e2.altitude, ALTITUDE_NOT_THE_SAME); 91 ok &= check(e1.order - e2.order == order_offset, ORDER_NOT_THE_SAME); 92 ok &= check(e1.round.number - e2.round.number == round_offset, ROUND_NOT_THE_SAME); 93 if ((e1.round_received) && (e2.round_received)) { 94 ok &= check(e1.round_received.number - e2.round_received.number == round_offset, 95 ROUND_RECEIVED_NOT_THE_SAME); 96 } 97 ok &= check((e1.witness is null) == (e2.witness is null), WITNESS_CONFLICT); 98 } 99 // if (!ok) { 100 // return ok; 101 // } 102 count++; 103 h1_events.popFront; 104 h2_events.popFront; 105 } 106 } 107 return ok; 108 } 109 }