From 43ef1bb409d38d5d8960c032a3b034d5c1261a47 Mon Sep 17 00:00:00 2001 From: wa0x6e <495709+wa0x6e@users.noreply.github.com> Date: Thu, 7 Aug 2025 00:10:06 +0400 Subject: [PATCH 1/4] feat: increase leaderboard vp_value on vote creation --- src/writer/vote.ts | 6 +++--- test/schema.sql | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/writer/vote.ts b/src/writer/vote.ts index 7a37194a..7ac0cf32 100644 --- a/src/writer/vote.ts +++ b/src/writer/vote.ts @@ -194,12 +194,12 @@ export async function action(body, ipfs, receipt, id, context): Promise { await db.queryAsync( ` INSERT INTO votes SET ?; - INSERT INTO leaderboard (space, user, vote_count, last_vote) - VALUES(?, ?, 1, ?) + INSERT INTO leaderboard (space, user, vote_count, last_vote, vp_value) + VALUES(?, ?, 1, ?, ?) ON DUPLICATE KEY UPDATE vote_count = vote_count + 1, last_vote = ?; UPDATE spaces SET vote_count = vote_count + 1 WHERE id = ?; `, - [params, msg.space, voter, created, created, msg.space] + [params, msg.space, voter, created, vp_value, created, msg.space] ); } diff --git a/test/schema.sql b/test/schema.sql index 7477fb10..d94d5664 100644 --- a/test/schema.sql +++ b/test/schema.sql @@ -190,11 +190,13 @@ CREATE TABLE leaderboard ( vote_count SMALLINT UNSIGNED NOT NULL DEFAULT '0', proposal_count SMALLINT UNSIGNED NOT NULL DEFAULT '0', last_vote BIGINT, + vp_value DECIMAL(13,3) NOT NULL DEFAULT 0.000, PRIMARY KEY user_space (user,space), INDEX space (space), INDEX vote_count (vote_count), INDEX proposal_count (proposal_count), - INDEX last_vote (last_vote) + INDEX last_vote (last_vote), + INDEX vp_value (vp_value) ); CREATE TABLE skins ( From 2172f479ffe145fa939a36a12283cf1b393b5b7d Mon Sep 17 00:00:00 2001 From: wa0x6e <495709+wa0x6e@users.noreply.github.com> Date: Thu, 7 Aug 2025 00:31:38 +0400 Subject: [PATCH 2/4] feat: decrease leaderboard vp_value on proposal deletion --- src/writer/delete-proposal.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/writer/delete-proposal.ts b/src/writer/delete-proposal.ts index 3d777acd..73ccd10b 100644 --- a/src/writer/delete-proposal.ts +++ b/src/writer/delete-proposal.ts @@ -22,7 +22,7 @@ export async function action(body): Promise { const msg = jsonParse(body.msg); const proposal = await getProposal(msg.space, msg.payload.proposal); - const voters = await db.queryAsync(`SELECT voter FROM votes WHERE proposal = ?`, [ + const voters = await db.queryAsync(`SELECT voter, vp_value FROM votes WHERE proposal = ?`, [ msg.payload.proposal ]); const id = msg.payload.proposal; @@ -53,4 +53,22 @@ export async function action(body): Promise { } await db.queryAsync(queries, parameters); + + const votersWithVpValue = voters.filter(v => v.vp_value > 0); + if (votersWithVpValue.length > 0) { + const batchSize = 1000; + for (let i = 0; i < votersWithVpValue.length; i += batchSize) { + const batch = votersWithVpValue.slice(i, i + batchSize); + const vpQueries = batch + .map( + () => + `UPDATE leaderboard SET vp_value = GREATEST(vp_value - ?, 0) WHERE user = ? AND space = ?;` + ) + .join('\n '); + + const vpParams = batch.flatMap(voter => [voter.vp_value, voter.voter, msg.space]); + + await db.queryAsync(vpQueries, vpParams); + } + } } From d6381a80d36d12d35ab1293a828a5a9e3d20cf78 Mon Sep 17 00:00:00 2001 From: wa0x6e <495709+wa0x6e@users.noreply.github.com> Date: Thu, 7 Aug 2025 15:09:09 +0400 Subject: [PATCH 3/4] fix: update leaderboard vp_value on new vote --- src/writer/vote.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/writer/vote.ts b/src/writer/vote.ts index 7ac0cf32..2a8f0b1a 100644 --- a/src/writer/vote.ts +++ b/src/writer/vote.ts @@ -185,6 +185,7 @@ export async function action(body, ipfs, receipt, id, context): Promise { proposalId, msg.space, created, + vp_value, voter, msg.space ] @@ -194,12 +195,20 @@ export async function action(body, ipfs, receipt, id, context): Promise { await db.queryAsync( ` INSERT INTO votes SET ?; - INSERT INTO leaderboard (space, user, vote_count, last_vote, vp_value) - VALUES(?, ?, 1, ?, ?) - ON DUPLICATE KEY UPDATE vote_count = vote_count + 1, last_vote = ?; - UPDATE spaces SET vote_count = vote_count + 1 WHERE id = ?; + INSERT INTO leaderboard ( + space, user, vote_count, last_vote, vp_value + ) VALUES ( + ?, ?, 1, ?, ? + ) + ON DUPLICATE KEY UPDATE + vote_count = vote_count + 1, + last_vote = VALUES(last_vote), + vp_value = vp_value + VALUES(vp_value); + UPDATE spaces + SET vote_count = vote_count + 1 + WHERE id = ?; `, - [params, msg.space, voter, created, vp_value, created, msg.space] + [params, msg.space, voter, created, vp_value, msg.space] ); } From 01a782bbab6215982a045195b90ba89a742f66d4 Mon Sep 17 00:00:00 2001 From: wa0x6e <495709+wa0x6e@users.noreply.github.com> Date: Thu, 7 Aug 2025 16:21:46 +0400 Subject: [PATCH 4/4] refactor: code improvement --- src/helpers/entityValue.ts | 7 ++++--- src/writer/delete-proposal.ts | 7 ++++--- src/writer/vote.ts | 30 ++++++++++++------------------ 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/helpers/entityValue.ts b/src/helpers/entityValue.ts index 222fdc0b..25e891b5 100644 --- a/src/helpers/entityValue.ts +++ b/src/helpers/entityValue.ts @@ -15,7 +15,8 @@ export function getVoteValue(proposal: Proposal, vote: Vote): number { throw new Error('invalid data to compute vote value'); } - return proposal.vp_value_by_strategy - .map((value, index) => value * vote.vp_by_strategy[index]) - .reduce((a, b) => a + b, 0); + return proposal.vp_value_by_strategy.reduce( + (sum, value, index) => sum + value * vote.vp_by_strategy[index], + 0 + ); } diff --git a/src/writer/delete-proposal.ts b/src/writer/delete-proposal.ts index 73ccd10b..4e550b90 100644 --- a/src/writer/delete-proposal.ts +++ b/src/writer/delete-proposal.ts @@ -19,6 +19,8 @@ export async function verify(body): Promise { } export async function action(body): Promise { + const BATCH_SIZE = 1000; + const msg = jsonParse(body.msg); const proposal = await getProposal(msg.space, msg.payload.proposal); @@ -56,9 +58,8 @@ export async function action(body): Promise { const votersWithVpValue = voters.filter(v => v.vp_value > 0); if (votersWithVpValue.length > 0) { - const batchSize = 1000; - for (let i = 0; i < votersWithVpValue.length; i += batchSize) { - const batch = votersWithVpValue.slice(i, i + batchSize); + for (let i = 0; i < votersWithVpValue.length; i += BATCH_SIZE) { + const batch = votersWithVpValue.slice(i, i + BATCH_SIZE); const vpQueries = batch .map( () => diff --git a/src/writer/vote.ts b/src/writer/vote.ts index 2a8f0b1a..3bd442c8 100644 --- a/src/writer/vote.ts +++ b/src/writer/vote.ts @@ -119,14 +119,16 @@ export async function action(body, ipfs, receipt, id, context): Promise { const withOverride = hasStrategyOverride(context.proposal.strategies); if (vpState === 'final' && withOverride) vpState = 'pending'; - let vp_value = 0; + // Get proposal voting power value + // Value is set on creation, and not updated on vote update + let vpValue = 0; let cb = 0; try { - vp_value = getVoteValue(context.proposal, context.vp); + vpValue = getVoteValue(context.proposal, context.vp); cb = LAST_CB; } catch (e: any) { - capture(e, { msg, proposalId }); + capture(e, { msg, proposalId, context }); } const params = { @@ -143,7 +145,7 @@ export async function action(body, ipfs, receipt, id, context): Promise { vp: context.vp.vp, vp_by_strategy: JSON.stringify(context.vp.vp_by_strategy), vp_state: vpState, - vp_value, + vp_value: vpValue, cb }; @@ -185,7 +187,7 @@ export async function action(body, ipfs, receipt, id, context): Promise { proposalId, msg.space, created, - vp_value, + vpValue, voter, msg.space ] @@ -195,20 +197,12 @@ export async function action(body, ipfs, receipt, id, context): Promise { await db.queryAsync( ` INSERT INTO votes SET ?; - INSERT INTO leaderboard ( - space, user, vote_count, last_vote, vp_value - ) VALUES ( - ?, ?, 1, ?, ? - ) - ON DUPLICATE KEY UPDATE - vote_count = vote_count + 1, - last_vote = VALUES(last_vote), - vp_value = vp_value + VALUES(vp_value); - UPDATE spaces - SET vote_count = vote_count + 1 - WHERE id = ?; + INSERT INTO leaderboard (space, user, vote_count, last_vote, vp_value) + VALUES(?, ?, 1, ?, ?) + ON DUPLICATE KEY UPDATE vote_count = vote_count + 1, last_vote = VALUES(last_vote), vp_value = vp_value + VALUES(vp_value); + UPDATE spaces SET vote_count = vote_count + 1 WHERE id = ?; `, - [params, msg.space, voter, created, vp_value, msg.space] + [params, msg.space, voter, created, vpValue, msg.space] ); }