Serialization converts an object from one representation to another, commonly from in-memory data to a file or transferable format. Deserialization, also called hydration, reconstructs in-memory objects from that representation. section 7.4.3 section 9.2.3
A robust serializer lets each object control its external representation. A global symbol such as Symbol.for('toJson') provides a discoverable hook without colliding with ordinary method names; a generic helper uses the hook when available and otherwise falls back to JSON.stringify. section 7.4.3
Serializing a ledger
A Block can emit a tailored JSON summary containing its index, hashes, timestamp, data count, data, and version. A ledger is converted to an array, serialized block by block, joined with a delimiter, and converted into a UTF-8 Buffer suitable for writing to a file or sending over a network.
Serialization also works incrementally with streams. An async generator reads delimited JSON blocks from a file, parses each block as it becomes available, and yields it without loading the entire file. Consumers can hydrate each object and validate it immediately. section 9.2.3
Listing 9.8 Async generator that sends blocks read from a file
async function* generateBlocksFromFile(file) { #1
try {
await fsp.access(file, fs.constants.F_OK | fs.constants.R_OK);
const dataStream = fs.createReadStream(file,
{ encoding: 'utf8', highWaterMark: 64 });
let previousDecodedData = '';
for await (const chunk of dataStream) {
previousDecodedData += chunk;
let separatorIndex;
while ((separatorIndex = previousDecodedData.indexOf(';')) >= 0) {
const decodedData = previousDecodedData.slice(0,
separatorIndex + 1);
const blocks = tokenize(';', decodedData)
.filter(str => str.length > 0)
.map(str => str.replace(';', ''));
for (const block of blocks) {
yield JSON.parse(block); #2
}
previousDecodedData = previousDecodedData.slice(
separatorIndex + 1);
}
}
if (previousDecodedData.length > 0) {
yield JSON.parse(previousDecodedData); #2
}
}
catch (e) {
console.error(`Error processing file: ${e.message}`);
throw e;
}
}
Shows an async generator that reads file chunks, separates serialized blocks, parses JSON, and yields each decoded object. section 9.2.3
Listing 9.10 Validating a stream of blocks generated from a file
let validBlocks = 0;
const chain = new Blockchain(); #1
let skippedGenesis = false
for await (const blockData of generateBlocksFromFile('blocks.txt')) {
if (!skippedGenesis) {
skippedGenesis = true;
continue; #2
}
const block =
new Block(blockData.index, chain.top.hash, blockData.data,
blockData.difficulty);
chain.push(block); #3
if (block.validate().isFailure) { #4
continue;
}
validBlocks++
}
console.log(validBlocks) // 2
Shows the consumer side: skip the genesis block, hydrate each decoded object into a Block, add it to a chain, and validate it. section 9.2.3























