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 }