1 /// \file recorderchain.d 2 module tagion.tools.recorderchain; 3 4 /** 5 * @brief tool replay whole recorder chain in DART database 6 */ 7 8 import std.array; 9 import std.file : copy, exists; 10 import std.format; 11 import std.getopt; 12 import std.path; 13 import std.stdio; 14 import tagion.basic.Types : FileExtension; 15 import tagion.basic.tagionexceptions; 16 import tagion.crypto.SecureInterfaceNet : SecureNet; 17 import tagion.crypto.SecureNet; 18 import tagion.dart.BlockFile; 19 import tagion.dart.DART; 20 import tagion.dart.DARTFile; 21 import tagion.dart.Recorder; 22 // import tagion.prior_services.RecorderService; 23 import tagion.recorderchain.RecorderChain; 24 import tagion.recorderchain.RecorderChainBlock : RecorderChainBlock; 25 import tagion.tools.Basic; 26 27 auto logo = import("logo.txt"); 28 29 mixin Main!(_main, "tagionrecorderchain"); 30 31 int _main(string[] args) { 32 immutable program = args[0]; 33 34 if (args.length == 1) { 35 writeln("Error: No arguments provided for ", baseName(args[0]), "!"); 36 return 1; 37 } 38 39 /** Net for DART database creation */ 40 SecureNet secure_net = new StdSecureNet; 41 /** Net for recorder factory creation */ 42 const hash_net = new StdHashNet; 43 /** Used for create recorder */ 44 auto factory = RecordFactory(hash_net); 45 /** Passphrase for generate key pair for secure net */ 46 string passphrase = "verysecret"; 47 secure_net.generateKeyPair(passphrase); 48 /** Directory for recorder block chain */ 49 string chain_directory; 50 /** Directory for DART database */ 51 string dart_file; 52 /** Directory for genesis DART */ 53 string gen_dart_file; 54 55 bool interactive_mode; 56 57 58 GetoptResult main_args; 59 60 try { 61 main_args = getopt(args, 62 std.getopt.config.caseSensitive, 63 std.getopt.config.bundling, 64 "chaindirectory|c", "Path to recorder chain directory", &chain_directory, 65 "dartfile|d", "Path to dart file", &dart_file, 66 "genesisdart|g", "Path to genesis dart file", &gen_dart_file, 67 "interactive|i", "Go through the recorder in interactive mode", &interactive_mode, 68 ); 69 70 if (main_args.helpWanted) { 71 writeln(logo); 72 defaultGetoptPrinter( 73 [ 74 // format("%s version %s", program, REVNO), 75 "Documentation: https://tagion.org/", 76 "", 77 "Usage:", 78 format("%s [<option>...]", program), 79 "", 80 "Examples:", 81 "# To run recorer chain specify 3 required parameters", 82 format("%s -с chain_directory -d new_dart.drt -g genesis_dart.drt", program), 83 "", 84 "<option>:", 85 86 ].join("\n"), 87 main_args.options); 88 return 0; 89 } 90 } 91 catch (Exception e) { 92 stderr.writefln(e.msg); 93 return 1; 94 } 95 96 // Check genesis DART file 97 if (!gen_dart_file.exists || gen_dart_file.extension != FileExtension.dart) { 98 writefln("Incorrect genesis DART file '%s'", gen_dart_file); 99 return 1; 100 } 101 102 // Copy genesis DART as base for DART that is being recovered 103 gen_dart_file.copy(dart_file); 104 105 // Open new DART file 106 DART dart; 107 try { 108 dart = new DART(secure_net, dart_file); 109 } 110 catch (Exception e) { 111 writefln("Invalid format of genesis DART file '%s'", gen_dart_file); 112 return 1; 113 } 114 115 // Check existence of recorder chain directory 116 if (!chain_directory.exists) { 117 writefln("Recorder chain directory '%s' does not exist", chain_directory); 118 return 1; 119 } 120 121 RecorderChainStorage storage = new RecorderChainFileStorage(chain_directory, hash_net); 122 auto recorder_chain = new RecorderChain(storage); 123 124 // Check validity of recorder chain 125 if (!recorder_chain.isValidChain) { 126 writeln("Recorder block chain is not valid!\nAbort"); 127 return 1; 128 } 129 130 // Collect info from chain directory 131 auto blocks_count = recorder_chain.storage.getHashes.length; 132 if (blocks_count == 0) { 133 writeln("No recorder chain files"); 134 return 1; 135 } 136 import core.stdc.stdio; 137 138 139 import tagion.hibon.HiBONJSON; 140 try { 141 recorder_chain.replay((RecorderChainBlock block) { 142 writefln("current bullseye<%(%02x%)>", dart.bullseye); 143 if (interactive_mode) { 144 writefln("recorder that will be added:\n%s", block.recorder_doc.toPretty); 145 const input = getchar; 146 } 147 148 auto recorder = factory.recorder(block.recorder_doc); 149 dart.modify(recorder); 150 if (block.bullseye != dart.bullseye) { 151 stderr.writeln(format("ERROR: expected bullseye: %(%02x%) \ngot %(%02x%)", 152 block.bullseye, 153 dart.bullseye)); 154 } 155 }); 156 } 157 catch(TagionException e) { 158 writefln("%s. Abort", e.msg); 159 return 1; 160 } 161 162 return 0; 163 }