Skip to content

Commit

Permalink
Fix/resubmit bundle votes (#45)
Browse files Browse the repository at this point in the history
* implemented resubmitting of failed bundle votes

* started fixing unit tests

* fixed unit tests
  • Loading branch information
troykessler authored May 19, 2023
1 parent becdebe commit 7eae47e
Show file tree
Hide file tree
Showing 7 changed files with 618 additions and 279 deletions.
7 changes: 6 additions & 1 deletion common/protocol/src/methods/main/runNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,12 @@ export async function runNode(this: Validator): Promise<void> {
// by calling a special query from chain
if (await this.canVote(updatedAt)) {
// if the node can vote the node validates the current bundle proposal
await this.validateBundleProposal(updatedAt);
const success = await this.validateBundleProposal(updatedAt);

if (!success) {
this.logger.info(`Retrying to validate bundle proposal`);
continue;
}
}

// wait until the upload interval has passed to continue with the proposal
Expand Down
23 changes: 16 additions & 7 deletions common/protocol/src/methods/txs/voteBundleProposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,19 @@ export async function voteBundleProposal(
},pool_id: ${this.poolId.toString()},storage_id: ${storageId},vote: ${vote}})`
);

const tx = await this.client[c].kyve.bundles.v1beta1.voteBundleProposal({
staker: this.staker,
pool_id: this.poolId.toString(),
storage_id: storageId,
vote,
});
// use a higher gas multiplier of 1.5 because while voting the gas can drastically increase,
// making late submitted votes fail due to not enough gas
const tx = await this.client[c].kyve.bundles.v1beta1.voteBundleProposal(
{
staker: this.staker,
pool_id: this.poolId.toString(),
storage_id: storageId,
vote,
},
{
fee: 1.6,
}
);

this.logger.debug(`VoteProposal = ${tx.txHash}`);

Expand All @@ -59,7 +66,9 @@ export async function voteBundleProposal(
this.logger.info(`Voted ${voteMessage} on bundle "${storageId}"`);

this.m.tx_vote_bundle_proposal_successful.inc();
this.m.fees_vote_bundle_proposal.inc(parseInt(tx.fee.amount[0].amount));
this.m.fees_vote_bundle_proposal.inc(
parseInt(tx?.fee?.amount[0]?.amount ?? 0)
);

if (vote === 1) {
this.m.bundles_voted_valid.inc();
Expand Down
50 changes: 28 additions & 22 deletions common/protocol/src/methods/validate/validateBundleProposal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import { sha256, standardizeJSON, VOTE } from "../../utils";
* @method validateBundleProposal
* @param {Validator} this
* @param {number} updatedAt
* @return {Promise<void>}
* @return {Promise<boolean>} whether the validation was successful or has to be repeated
*/
export async function validateBundleProposal(
this: Validator,
updatedAt: number
): Promise<void> {
): Promise<boolean> {
try {
this.logger.info(
`Validating bundle proposal = ${this.pool.bundle_proposal!.storage_id}`
Expand All @@ -31,7 +31,7 @@ export async function validateBundleProposal(
// if no bundle got returned it means that the pool is not active anymore
// or a new bundle proposal round has started
if (storageProviderResult === null) {
return;
return true;
}

// vote invalid if data size does not match with proposed data size
Expand All @@ -47,11 +47,11 @@ export async function validateBundleProposal(
`Found different byte size on bundle downloaded from storage provider`
);

await this.voteBundleProposal(
const success = await this.voteBundleProposal(
this.pool.bundle_proposal!.storage_id,
VOTE.INVALID
);
return;
return success;
}

this.logger.info(
Expand All @@ -72,11 +72,11 @@ export async function validateBundleProposal(
`Found different hash on bundle downloaded from storage provider`
);

await this.voteBundleProposal(
const success = await this.voteBundleProposal(
this.pool.bundle_proposal!.storage_id,
VOTE.ABSTAIN
);
return;
return success;
}

this.logger.info(
Expand All @@ -88,7 +88,7 @@ export async function validateBundleProposal(
// if no bundle got returned it means that the pool is not active anymore
// or a new bundle proposal round has started
if (validationBundle === null) {
return;
return true;
}

// vote invalid if bundle key does not match with proposed from key
Expand All @@ -102,11 +102,11 @@ export async function validateBundleProposal(
// archive local invalid bundle for debug purposes
this.archiveDebugBundle(validationBundle);

await this.voteBundleProposal(
const success = await this.voteBundleProposal(
this.pool.bundle_proposal!.storage_id,
VOTE.INVALID
);
return;
return success;
}

this.logger.info(
Expand All @@ -124,11 +124,11 @@ export async function validateBundleProposal(
// archive local invalid bundle for debug purposes
this.archiveDebugBundle(validationBundle);

await this.voteBundleProposal(
const success = await this.voteBundleProposal(
this.pool.bundle_proposal!.storage_id,
VOTE.INVALID
);
return;
return success;
}

this.logger.info(
Expand Down Expand Up @@ -202,11 +202,11 @@ export async function validateBundleProposal(

// vote abstain if bundleSummary is null
if (bundleSummary === null) {
await this.voteBundleProposal(
const success = await this.voteBundleProposal(
this.pool.bundle_proposal!.storage_id,
VOTE.ABSTAIN
);
return;
return success;
}

this.logger.debug(
Expand All @@ -232,29 +232,32 @@ export async function validateBundleProposal(
? VoteType.VOTE_TYPE_VALID
: VoteType.VOTE_TYPE_INVALID;

await this.voteBundleProposal(
const success = await this.voteBundleProposal(
this.pool.bundle_proposal!.storage_id,
vote
);

// update metrics
this.m.bundles_amount.inc();
this.m.bundles_data_items.set(proposedBundle.length);
this.m.bundles_byte_size.set(storageProviderResult.byteLength);

return success;
} catch (err) {
this.logger.error(
`Unexpected error validating data items with runtime. Voting abstain ...`
);
this.logger.error(standardizeJSON(err));

await this.voteBundleProposal(
const success = await this.voteBundleProposal(
this.pool.bundle_proposal!.storage_id,
VoteType.VOTE_TYPE_ABSTAIN
);
return success;
}

// update metrics
this.m.bundles_amount.inc();
this.m.bundles_data_items.set(proposedBundle.length);
this.m.bundles_byte_size.set(storageProviderResult.byteLength);
} else {
// if proposed bundle is empty we always vote abstain
await this.voteBundleProposal(
const success = await this.voteBundleProposal(
this.pool.bundle_proposal!.storage_id,
VoteType.VOTE_TYPE_ABSTAIN
);
Expand All @@ -265,11 +268,14 @@ export async function validateBundleProposal(
parseInt(this.pool.bundle_proposal!.bundle_size)
);
this.m.bundles_byte_size.set(storageProviderResult.byteLength);

return success;
}
} catch (err) {
this.logger.error(
`Unexpected error validating bundle proposal. Skipping validation ...`
);
this.logger.error(standardizeJSON(err));
return false;
}
}
17 changes: 11 additions & 6 deletions common/protocol/test/genesis.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -445,12 +445,17 @@ describe("genesis tests", () => {
});

expect(txs.voteBundleProposal).toHaveBeenCalledTimes(1);
expect(txs.voteBundleProposal).toHaveBeenLastCalledWith({
staker: "test_staker",
pool_id: "0",
storage_id: "another_test_storage_id",
vote: VoteType.VOTE_TYPE_VALID,
});
expect(txs.voteBundleProposal).toHaveBeenLastCalledWith(
{
staker: "test_staker",
pool_id: "0",
storage_id: "another_test_storage_id",
vote: VoteType.VOTE_TYPE_VALID,
},
{
fee: 1.6,
}
);

expect(txs.submitBundleProposal).toHaveBeenCalledTimes(0);

Expand Down
Loading

0 comments on commit 7eae47e

Please sign in to comment.