1 module tagion.hashgraphview.EventChain;
2 
3 version (none) {
4 
5     import std.algorithm : map;
6     import std.array : array;
7     import std.range : iota;
8     import tagion.basic.Types : Buffer;
9     import tagion.crypto.SecureInterfaceNet : SecureNet;
10     import tagion.crypto.Types : Pubkey, Signature;
11     import tagion.hashgraph.Event : Event;
12     import tagion.hashgraph.HashGraphBasic : EventBody, EventPackage;
13     import tagion.hibon.Document : Document;
14     import tagion.hibon.HiBON : HiBON;
15     import tagion.hibon.HiBONRecord;
16     import tagion.utils.StdTime : sdt_t;
17 
18     enum NIL = -1; // Defines an unconected Event
19 
20     @safe
21     struct EventBodyCompact {
22         @label("p") @optional @filter(q{!a.empty}) Document payload; // Transaction
23         @label("m") @filter(q{a != -1}) @fixed(q{-1}) int mother; // Hash of the self-parent
24         @label("f") @filter(q{a != -1}) @fixed(q{-1}) int father; // Hash of the other-parent
25         @label("a") int altitude;
26         @label("t") sdt_t time;
27         @label("M") @optional @(filter.Initialized) Buffer mother_fingerprint; /// This event is connect to the previous mother
28         @label("F") @optional @(filter.Initialized) Buffer father_fingerprint; /// This event is connect to the previous father
29         @label("C") @optional @(filter.Initialized) Pubkey channel; /// Event Channel (Pubkey of the node);
30         mixin HiBONRecord;
31     }
32 
33     @safe
34     struct EventCompact {
35         @label("s") Signature signature; // Signature
36         @label("b") EventBodyCompact ebody; // Event Body
37         mixin HiBONRecord;
38     }
39 
40     @safe
41     struct EventEpochChunk {
42         @label("epacks") EventCompact[] epacks;
43         @label("chain") Buffer chain;
44         mixin HiBONRecord!(
45                 q{
46             this(EventCompact[] epacks, Buffer chain) pure nothrow {
47                 this.epacks=epacks;
48                 this.chain=chain;
49             }
50         });
51     }
52 
53     @safe
54     struct HashGraphRecorver {
55         const SecureNet net;
56         this(const SecureNet net) {
57             this.net = net;
58         }
59 
60         immutable(EventEpochChunk) opCall(const(Event[]) events, Buffer chain) const pure {
61             int[Buffer] event_ids;
62             foreach (i, e; events) {
63                 event_ids[e.fingerprint] = cast(int) i;
64             }
65             EventCompact event_body_compact(const(Event) e) pure {
66                 EventBodyCompact ebody;
67                 ebody.altitude = e.event_body.altitude;
68                 ebody.time = sdt_t(e.event_body.time);
69                 ebody.payload = e.event_body.payload;
70                 if (e.mother) {
71                     ebody.mother = event_ids.get(e.event_body.mother, NIL);
72                     if (!(e.event_body.mother in event_ids)) {
73                         ebody.mother_fingerprint = e.event_body.mother;
74                         ebody.channel = Pubkey(e.channel);
75                     }
76                 }
77                 if (e.father) {
78                     ebody.father = event_ids.get(e.event_body.father, NIL);
79                     if (!(e.event_body.father in event_ids)) {
80                         ebody.father_fingerprint = e.event_body.father;
81                     }
82                 }
83                 EventCompact epack;
84                 epack.ebody = ebody;
85                 epack.signature = Signature(e.event_package.signature);
86                 return epack;
87             }
88 
89             auto epacks =
90                 events
91                     .map!((e) => event_body_compact(e))
92                     .array;
93             return (() @trusted { return cast(immutable) EventEpochChunk(epacks, chain); })();
94         }
95 
96         const(immutable(EventPackage)*[]) opCall(const(EventEpochChunk) epoch_chunk) const {
97             auto result_epacks = new immutable(EventPackage)*[epoch_chunk.epacks.length];
98             immutable(EventPackage)* reconstruct_epack(const int event_id) {
99                 immutable(EventPackage)* result;
100                 if (event_id !is NIL) {
101                     if (result_epacks[event_id]) {
102                         return result_epacks[event_id];
103                     }
104                     const ebody_compact = epoch_chunk.epacks[event_id];
105                     Buffer mother_fingerprint;
106                     Pubkey channel;
107                     if (ebody_compact.ebody.mother_fingerprint) {
108                         mother_fingerprint = ebody_compact.ebody.mother_fingerprint;
109                         channel = Pubkey(ebody_compact.ebody.channel);
110                     }
111                     else {
112                         const mother = reconstruct_epack(ebody_compact.ebody.mother);
113                         mother_fingerprint = mother.fingerprint;
114                         channel = Pubkey(mother.pubkey);
115                     }
116                     Buffer father_fingerprint;
117                     if (ebody_compact.ebody.father_fingerprint) {
118                         father_fingerprint = ebody_compact.ebody.father_fingerprint;
119                     }
120                     else {
121                         const father = reconstruct_epack(ebody_compact.ebody.father);
122                         if (father) {
123                             father_fingerprint = father.fingerprint;
124                         }
125                     }
126                     immutable ebody = EventBody(
127                             ebody_compact.ebody.payload,
128                             mother_fingerprint,
129                             father_fingerprint,
130                             ebody_compact.ebody.altitude,
131                             ebody_compact.ebody.time);
132 
133                     result = cast(immutable) new EventPackage(net, channel, ebody_compact.signature, ebody);
134                 }
135                 return result;
136             }
137             // auto result=iota(cast(int)epoch_chunk.epacks.length)
138             //     .map!((event_id) => reconstruct_epack(event_id))
139             //     .array;
140             return (() @trusted {
141                 return iota(cast(int) epoch_chunk.epacks.length)
142                     .map!((event_id) => reconstruct_epack(event_id))
143                     .array;
144             })();
145         }
146 
147     }
148 
149 }