1 /// \file RecorderChainBlock.d
2 module tagion.recorderchain.RecorderChainBlock;
3 
4 import std.array;
5 import tagion.basic.Types : Buffer, FileExtension;
6 import tagion.crypto.SecureInterfaceNet : HashNet;
7 import tagion.crypto.Types : Fingerprint;
8 import tagion.dart.Recorder;
9 import tagion.hashchain.HashChainBlock : HashChainBlock;
10 import tagion.hibon.Document;
11 import tagion.hibon.HiBONJSON : JSONString;
12 import tagion.hibon.HiBONRecord : GetLabel, HiBONRecord, exclude, label, recordType;
13 
14 @recordType("RCB")
15 @safe struct RecorderBlock {
16     /** Fingerprint of this block */
17     @exclude Fingerprint fingerprint;
18     /** Bullseye of DART database */
19     @label("eye") Fingerprint bullseye;
20     /** Epoch number */
21     @label("epoch_number") long epoch_number;
22     /** Fingerprint of the previous block */
23     @label("previous") Fingerprint previous;
24     /** Recorder with database changes of this block */
25     @label("recorder") Document recorder_doc;
26 
27 
28     /** Ctor creates block from recorder, previous hash and bullseye.
29      *      @param recorder_doc - Document with recorder for block
30      *      @param previous - fingerprint of the previous block
31      *      @param bullseye - bullseye of database
32      *      @param net - hash net
33      */
34     mixin HiBONRecord!(
35         q{
36         this(
37             Document recorder_doc,
38             Fingerprint previous,
39             Fingerprint bullseye,
40             long epoch_number,
41             const(HashNet) net)
42         {
43             this.recorder_doc = recorder_doc;
44             this.previous = previous;
45             this.bullseye = bullseye;
46             this.epoch_number = epoch_number;
47 
48             this.fingerprint = net.calcHash(toDoc);
49         }
50 
51         this(
52             const(Document) doc,
53             const(HashNet) net)
54         {
55             this(doc);
56             this.fingerprint = net.calcHash(toDoc);
57         }
58     });
59 }
60 /** @brief File contains class RecorderChainBlock and RecorderChainBlockFactory
61  */
62 
63 /**
64  * \class RecorderChainBlock
65  * Class represents block from recorder chain
66  */
67 @recordType("RCB")
68 @safe class RecorderChainBlock : HashChainBlock {
69     /** Fingerprint of this block */
70     @exclude Fingerprint fingerprint;
71     /** Bullseye of DART database */
72     @label("eye") Fingerprint bullseye;
73     /** Epoch number */
74     @label("epoch_number") long epoch_number;
75     /** Fingerprint of the previous block */
76     @label("previous") Fingerprint previous;
77     /** Recorder with database changes of this block */
78     @label("recorder") Document recorder_doc;
79 
80     mixin JSONString;
81 
82     /** Ctor creates block from recorder, previous hash and bullseye.
83      *      @param recorder_doc - Document with recorder for block
84      *      @param previous - fingerprint of the previous block
85      *      @param bullseye - bullseye of database
86      *      @param net - hash net
87      */
88     mixin HiBONRecord!(
89             q{
90             private this(
91                 Document recorder_doc,
92                 Fingerprint previous,
93                 Fingerprint bullseye,
94                 long epoch_number,
95                 const(HashNet) net)
96             {
97                 this.recorder_doc = recorder_doc;
98                 this.previous = previous;
99                 this.bullseye = bullseye;
100                 this.epoch_number = epoch_number;
101 
102                 this.fingerprint = net.calcHash(toDoc);
103             }
104 
105             private this(
106                 const(Document) doc,
107                 const(HashNet) net)
108             {
109                 this(doc);
110                 this.fingerprint = net.calcHash(toDoc);
111             }
112         });
113 
114     Fingerprint getHash() const {
115         return fingerprint;
116     }
117 
118     Fingerprint getPrevious() const {
119         return previous;
120     }
121 }
122 
123 unittest {
124     import tagion.basic.tagionexceptions : TagionException;
125     import tagion.crypto.SecureNet : StdHashNet;
126     import tagion.hibon.HiBON : HiBON;
127 
128     HiBON test_hibon = new HiBON;
129     test_hibon["dummy1"] = 1;
130     test_hibon["dummy2"] = 2;
131 
132     const net = new StdHashNet;
133     auto factory = RecordFactory(net);
134     auto dummy_recorder = factory.recorder;
135     dummy_recorder.add(Document(test_hibon));
136 
137     auto doc_recorder = dummy_recorder.toDoc;
138 
139     Fingerprint bullseye = [1, 2, 3, 4, 5, 6, 7, 8];
140     Fingerprint previous = [1, 2, 4, 8, 16, 32, 64, 128];
141     int epoch_number = 0;
142 
143     /// RecorderChainBlock_create_block
144     {
145         auto block = new RecorderChainBlock(doc_recorder, previous, bullseye, epoch_number, net);
146 
147         assert(block.previous == previous);
148         assert(block.bullseye == bullseye);
149         assert(block.recorder_doc == doc_recorder);
150 
151         assert(block.fingerprint == net.calcHash(block.toDoc));
152     }
153 
154     /// RecorderChainBlock_toHiBON
155     {
156         enum previousLabel = GetLabel!(RecorderChainBlock.previous).name;
157         enum recorderLabel = GetLabel!(RecorderChainBlock.recorder_doc).name;
158         enum bullseyeLabel = GetLabel!(RecorderChainBlock.bullseye).name;
159 
160         auto block = new RecorderChainBlock(doc_recorder, previous, bullseye, epoch_number, net);
161 
162         assert(block.toHiBON[previousLabel].get!Buffer == previous);
163         assert(block.toHiBON[bullseyeLabel].get!Buffer == bullseye);
164         assert(block.toHiBON[recorderLabel].get!Document.serialize == doc_recorder.serialize);
165 
166         assert(net.calcHash(Document(block.toHiBON)) == block.fingerprint);
167     }
168 
169     /// RecorderChainBlock_restore_from_doc
170     {
171         auto block = new RecorderChainBlock(doc_recorder, previous, bullseye, epoch_number, net);
172         auto restored_block = new RecorderChainBlock(block.toDoc);
173 
174         assert(block.toDoc.serialize == restored_block.toDoc.serialize);
175     }
176 
177     /// RecorderChainBlock_from_doc_no_member
178     {
179         auto block = new RecorderChainBlock(doc_recorder, previous, bullseye, epoch_number, net);
180         auto block_hibon = block.toHiBON;
181         block_hibon.remove(GetLabel!(RecorderChainBlock.bullseye).name);
182 
183         try {
184             new RecorderChainBlock(Document(block_hibon));
185             assert(false);
186         }
187         catch (TagionException e) {
188         }
189     }
190 }