Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Further generalized two getStartingBlock...() methods #687

Merged
merged 3 commits into from
May 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 40 additions & 37 deletions lib/bitcoin/BitcoinProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,21 @@ export default class BitcoinProcessor {
await this.normalizedFeeCalculator.initialize();
await this.mongoDbLockTransactionStore.initialize();

// We always need to start the processing from the first block of a fee sampling group
// so that in-memory state for fee sampling will be repoppulated yielding correct fee calculation,
// so we trim the databases to make sure this condition is met.
// NOTE: We also initialize the `lastProcessedBlock`, this is an opional step currently,
// but will be required if Issue #692 is implemented.
this.lastProcessedBlock = await this.trimDatabasesToLastFeeSamplingGroupBoundary();
thehenrytsai marked this conversation as resolved.
Show resolved Hide resolved

console.debug('Synchronizing blocks for sidetree transactions...');
const startingBlock = await this.getStartingBlockForInitialization();
const startingBlock = await this.getStartingBlockForPeriodicPoll();

// Throw if bitcoin client is not synced up to the bitcoin service's known height.
// NOTE: Implementation for issue #692 can simplify this method and remove this check.
if (startingBlock === undefined) {
throw new SidetreeError(ErrorCode.BitcoinProcessorBitcoinClientCurrentHeightNotUpToDate);
}

console.info(`Starting block: ${startingBlock.height} (${startingBlock.hash})`);
await this.processTransactions(startingBlock);
Expand All @@ -172,6 +185,27 @@ export default class BitcoinProcessor {
void this.periodicPoll();
}

/**
* NOTE: Should be used ONLY during service initialization.
* @returns The last processed block after trimming. `undefined` if all data are deleted after trimming.
*/
private async trimDatabasesToLastFeeSamplingGroupBoundary (): Promise<IBlockInfo | undefined> {
// Look in the transaction store to figure out the last block that we need to start from.
const lastSavedTransaction = await this.transactionStore.getLastTransaction();

// If there is no transaction saved in the DBs, we still need to perform trimming
// because there could be stale fee calculater data lingering, so we trim using the genesis block.
let lastValidBlock;
if (lastSavedTransaction === undefined) {
lastValidBlock = await this.trimDatabasesToFeeSamplingGroupBoundary(this.genesisBlockNumber);
} else {
// Else we trim DBs using the block number of the last saved transaction.
lastValidBlock = await this.trimDatabasesToFeeSamplingGroupBoundary(lastSavedTransaction.transactionTime);
}

return lastValidBlock;
}

/**
* Gets the blockchain time of the given time hash.
* Gets the latest logical blockchain time if time hash is not given.
Expand Down Expand Up @@ -435,45 +469,14 @@ export default class BitcoinProcessor {
return this.lastProcessedBlock!;
}

private async getStartingBlockForInitialization (): Promise<IBlockInfo> {

// Look in the transaction store to figure out the last block that we need to
// start from.
const lastSavedTransaction = (await this.transactionStore.getLastTransaction());

// If there's nothing saved in the DB then let's start from the genesis block
if (!lastSavedTransaction) {
// Put the system DBs in the correct state. We are going to ignore the return value
// from the following call as we already know the starting block is the
// genesis block.
await this.trimDatabasesToFeeSamplingGroupBoundary(this.genesisBlockNumber);
private async getStartingBlockForPeriodicPoll (): Promise<IBlockInfo | undefined> {
// If last processed block is undefined, start processing from genesis block.
if (this.lastProcessedBlock === undefined) {
await this.trimDatabasesToLastFeeSamplingGroupBoundary();
return this.bitcoinClient.getBlockInfoFromHeight(this.genesisBlockNumber);
}

// If we are here then it means that there is a potential starting point in the DB.
// Since we are initializing, it is quite possible that the last block that we processed
// (and saved in the db) has been forked. Check for the fork.
const lastSavedBlockIsValid = await this.verifyBlock(lastSavedTransaction.transactionTime, lastSavedTransaction.transactionTimeHash);

let lastValidBlock: IBlockInfo | undefined;
if (lastSavedBlockIsValid) {
// There was no fork ... let's put the system DBs in the correct state.
lastValidBlock = await this.trimDatabasesToFeeSamplingGroupBoundary(lastSavedTransaction.transactionTime);
} else {
// There was a fork so we need to revert. The revert function peforms all the correct
// operations and puts the system in the correct state and returns the last valid block.
lastValidBlock = await this.revertDatabases();
}

// If there is a valid processed block, we will start processing the block following it, else start processing from the genesis block.
const startingBlockHeight = lastValidBlock ? lastValidBlock.height + 1 : this.genesisBlockNumber;

return this.bitcoinClient.getBlockInfoFromHeight(startingBlockHeight);
}

private async getStartingBlockForPeriodicPoll (): Promise<IBlockInfo | undefined> {

const lastProcessedBlockIsValid = await this.verifyBlock(this.lastProcessedBlock!.height, this.lastProcessedBlock!.hash);
const lastProcessedBlockIsValid = await this.verifyBlock(this.lastProcessedBlock.height, this.lastProcessedBlock.hash);

// If the last processed block is not valid then that means that we need to
// revert the DB back to a known valid block.
Expand Down
1 change: 1 addition & 0 deletions lib/bitcoin/ErrorCode.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export default {
BitcoinWalletIncorrectImportString: 'bitcoin_wallet_incorrect_import_string',
BitcoinProcessorBitcoinClientCurrentHeightNotUpToDate: 'bitcion_processor_bitcoin_client_current_height_not_up_to_date',
BitcoinProcessorCannotProcessBlocksBeforeGenesis: 'bitcoin_processor_cannot_process_blocks_before_genesis',
BitcoinProcessInvalidPreviousBlockHash: 'bitcoin_processor_invalid_previous_block_hash',
LockIdentifierIncorrectFormat: 'lock_identifier_incorrect_format',
Expand Down
Loading