@kyve/core-beta
Version:
🚀 The base KYVE node implementation.
118 lines (102 loc) • 3.72 kB
text/typescript
import BigNumber from "bignumber.js";
import { Node } from "../..";
import { callWithBackoffStrategy, standardizeJSON, VOTE } from "../../utils";
/**
* saveBundleDownload downloads a bundle from the storage provider.
* The download should be aborted if the pool is not
* active anymore or a new bundle proposal has been found
* or the node is the current uploader and the upload interval
* has passed.
*
* If there is an error retrieving the bundle from the storage provider
* the node instantly votes with abstain and continues to try to retrieve
* the bundle.
*
* @method saveBundleDownload
* @param {Node} this
* @param {number} updatedAt
* @return {Promise<Buffer | null>}
*/
export async function saveBundleDownload(
this: Node,
updatedAt: number
): Promise<Buffer | null> {
return await callWithBackoffStrategy(
async () => {
await this.syncPoolState();
const unixNow = new BigNumber(Date.now());
const unixIntervalEnd = new BigNumber(
this.pool.bundle_proposal!.updated_at
)
.plus(this.pool.data!.upload_interval)
.multipliedBy(1000);
// check if new proposal is available in the meantime
if (parseInt(this.pool.bundle_proposal!.updated_at) > updatedAt) {
return null;
}
// check if pool got inactive in the meantime
if (this.validateIsPoolActive()) {
return null;
}
// check if validator needs to upload
if (
this.pool.bundle_proposal!.next_uploader === this.staker &&
unixNow.gte(unixIntervalEnd)
) {
return null;
}
// get storage provider the proposed bundle was saved to
this.logger.debug(
`storageProviderFactory(${
this.pool.bundle_proposal?.storage_provider_id ?? 0
}, $STORAGE_PRIV)`
);
const storageProvider = await this.storageProviderFactory(
this.pool.bundle_proposal?.storage_provider_id ?? 0
);
// calculate download timeout for storage provider
// the timeout should always be 20 seconds less than the upload interval
// so that the node still has enough time to vote abstain when the
// download timeout is reached
const downloadTimeoutSec = Math.max(
0,
parseInt(this.pool.data!.upload_interval) - 20
);
this.logger.debug(
`this.storageProvider.retrieveBundle(${
this.pool.bundle_proposal!.storage_id
},${downloadTimeoutSec * 1000})`
);
const { storageData } = await storageProvider.retrieveBundle(
this.pool.bundle_proposal!.storage_id,
downloadTimeoutSec * 1000
);
this.m.storage_provider_retrieve_successful.inc();
this.logger.info(
`Successfully downloaded bundle with id ${
this.pool.bundle_proposal!.storage_id
} from StorageProvider:${storageProvider.name}`
);
return storageData;
},
{ limitTimeoutMs: 5 * 60 * 1000, increaseByMs: 10 * 1000 },
async (err: any, ctx) => {
this.logger.info(
`Retrieving bundle from StorageProvider was unsuccessful. Retrying in ${(
ctx.nextTimeoutInMs / 1000
).toFixed(2)}s ...`
);
this.logger.debug(standardizeJSON(err));
this.m.storage_provider_retrieve_failed.inc();
// vote abstain if bundle could not be retrieved from storage
// provider. With voting abstain the network knows that the node
// is still online but just could not vote
if (!this.pool.bundle_proposal?.voters_abstain.includes(this.staker)) {
await this.voteBundleProposal(
this.pool.bundle_proposal!.storage_id,
VOTE.ABSTAIN
);
}
}
);
}