loadXchain method Null safety
- XchainModel xchain,
- {List<
String> skip = const []}
Deserializes and persists all the blocks from the xchain into database.
Implementation
Future<Map<BlockModel, List<TransactionModel>>> loadXchain(XchainModel xchain,
{List<String> skip = const []}) async {
Map<String, Uint8List> serializedblocks =
await _l0storage.getAll(base64Url.encode(xchain.address));
Map<BlockModel, List<TransactionModel>> blocks = {};
for (String blockId in serializedblocks.keys) {
if (blockId == 'public.key' ||
skip.contains(blockId.replaceAll('.block', ''))) continue;
Uint8List serializedBackup = serializedblocks[blockId]!;
List<Uint8List> backupList = CompactSize.decode(serializedBackup);
Uint8List signature = backupList[0];
Uint8List serializedBlock = backupList[1];
if (!Rsa.verify(xchain.publicKey, serializedBlock, signature)) {
throw StateError('Backup signature could not be verified for $blockId');
}
BlockModel block = BlockModel.deserialize(serializedBlock);
if (!Bytes.memEquals(Digest('SHA3-256').process(block.serialize()),
base64Url.decode(blockId.replaceAll('.block', '')))) {
throw Exception('Corrupted Block ${block.toString()}');
}
List<TransactionModel> transactions =
TransactionService.deserializeTransactions(serializedBlock);
MerkelTree merkelTree = MerkelTree.build(
transactions.map((TransactionModel txn) => txn.id!).toList());
if (!Bytes.memEquals(block.transactionRoot, merkelTree.root!)) {
throw Exception('Invalid transaction root for ${block.toString()}');
}
for (TransactionModel transaction in transactions) {
transaction.block = block;
transaction.merkelProof = merkelTree.proofs[transaction.id!];
if (!TransactionService.validateAuthor(transaction, xchain.publicKey)) {
throw Exception(
'Transaction authorshhip could not be verified: ${transaction.toString()}');
}
}
block.transactionRoot = merkelTree.root!;
blocks[block] = transactions;
}
return blocks;
}