162 lines
4.9 KiB
TypeScript
162 lines
4.9 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { verifyDrawResult, executeDeterministicDrawV1 } from '../src/core/randomizer/deterministic';
|
|
import { computeParticipantsSnapshotHash, computeConditionsHash } from '../src/core/randomizer/canonical';
|
|
import { DEFAULT_FILTER_RULES } from '../src/core/types/giveaway';
|
|
import { FilteredParticipant } from '../src/core/types/participant';
|
|
import { ParticipantSnapshotData } from '../src/core/types/audit';
|
|
|
|
describe('Verification API Replay Engine', () => {
|
|
const participants: FilteredParticipant[] = [
|
|
{
|
|
platformUserId: '10',
|
|
firstName: 'Победитель',
|
|
lastName: 'Один',
|
|
source: 'LIKES',
|
|
liked: true,
|
|
commented: false,
|
|
commentsCount: 0,
|
|
reposted: false,
|
|
subscribed: true,
|
|
eligible: true,
|
|
exclusionReason: null,
|
|
},
|
|
{
|
|
platformUserId: '20',
|
|
firstName: 'Победитель',
|
|
lastName: 'Два',
|
|
source: 'LIKES',
|
|
liked: true,
|
|
commented: false,
|
|
commentsCount: 0,
|
|
reposted: false,
|
|
subscribed: true,
|
|
eligible: true,
|
|
exclusionReason: null,
|
|
},
|
|
{
|
|
platformUserId: '30',
|
|
firstName: 'Победитель',
|
|
lastName: 'Три',
|
|
source: 'LIKES',
|
|
liked: true,
|
|
commented: false,
|
|
commentsCount: 0,
|
|
reposted: false,
|
|
subscribed: true,
|
|
eligible: true,
|
|
exclusionReason: null,
|
|
},
|
|
];
|
|
|
|
const snapshot: ParticipantSnapshotData = {
|
|
id: 'snap-verif-1',
|
|
giveawayId: 'gw-verif-1',
|
|
version: 1,
|
|
createdAt: '2026-08-17T12:00:00.000Z',
|
|
eligibleParticipants: participants,
|
|
filterRulesSnapshot: { ...DEFAULT_FILTER_RULES },
|
|
participantCount: 3,
|
|
participantsSnapshotHash: computeParticipantsSnapshotHash(participants),
|
|
conditionsHash: computeConditionsHash(DEFAULT_FILTER_RULES),
|
|
};
|
|
|
|
const seed = 'verification-engine-seed';
|
|
|
|
it('should return verified: true when claimed winners and proof hash match replay', () => {
|
|
const draw = executeDeterministicDrawV1({
|
|
giveawayId: 'gw-verif-1',
|
|
snapshot,
|
|
totalLoadedCount: 3,
|
|
winnersCount: 1,
|
|
reserveWinnersCount: 1,
|
|
seed,
|
|
});
|
|
|
|
const result = verifyDrawResult({
|
|
giveawayId: 'gw-verif-1',
|
|
drawId: draw.drawId,
|
|
drawnAt: draw.drawnAt,
|
|
snapshot,
|
|
seed,
|
|
claimedWinnersCount: 1,
|
|
claimedReserveCount: 1,
|
|
claimedWinnerIds: draw.winnerIds,
|
|
claimedReserveWinnerIds: draw.reserveWinnerIds,
|
|
claimedDeterministicProofHash: draw.deterministicProofHash,
|
|
claimedAuditEventHash: draw.auditEventHash,
|
|
algorithmVersion: draw.algorithmVersion,
|
|
});
|
|
|
|
expect(result.verified).toBe(true);
|
|
expect(result.winnersMatch).toBe(true);
|
|
expect(result.reserveWinnersMatch).toBe(true);
|
|
expect(result.deterministicProofHashMatch).toBe(true);
|
|
expect(result.auditEventHashMatch).toBe(true);
|
|
expect(result.participantsSnapshotIntegrity).toBe(true);
|
|
expect(result.conditionsIntegrity).toBe(true);
|
|
expect(result.expectedWinnerIds).toEqual(draw.winnerIds);
|
|
});
|
|
|
|
it('should return verified: false and winnersMatch: false if claimed winners differ', () => {
|
|
const draw = executeDeterministicDrawV1({
|
|
giveawayId: 'gw-verif-1',
|
|
snapshot,
|
|
totalLoadedCount: 3,
|
|
winnersCount: 1,
|
|
reserveWinnersCount: 1,
|
|
seed,
|
|
});
|
|
|
|
const fakeWinnerIds = ['9999']; // Tampered winners
|
|
|
|
const result = verifyDrawResult({
|
|
giveawayId: 'gw-verif-1',
|
|
drawId: draw.drawId,
|
|
drawnAt: draw.drawnAt,
|
|
snapshot,
|
|
seed,
|
|
claimedWinnersCount: 1,
|
|
claimedReserveCount: 1,
|
|
claimedWinnerIds: fakeWinnerIds,
|
|
claimedReserveWinnerIds: draw.reserveWinnerIds,
|
|
claimedDeterministicProofHash: draw.deterministicProofHash,
|
|
claimedAuditEventHash: draw.auditEventHash,
|
|
algorithmVersion: draw.algorithmVersion,
|
|
});
|
|
|
|
expect(result.verified).toBe(false);
|
|
expect(result.winnersMatch).toBe(false);
|
|
});
|
|
|
|
it('should return verified: false if deterministicProofHash was tampered with', () => {
|
|
const draw = executeDeterministicDrawV1({
|
|
giveawayId: 'gw-verif-1',
|
|
snapshot,
|
|
totalLoadedCount: 3,
|
|
winnersCount: 1,
|
|
reserveWinnersCount: 1,
|
|
seed,
|
|
});
|
|
|
|
const fakeProofHash = '0000000000000000000000000000000000000000000000000000000000000000';
|
|
|
|
const result = verifyDrawResult({
|
|
giveawayId: 'gw-verif-1',
|
|
drawId: draw.drawId,
|
|
drawnAt: draw.drawnAt,
|
|
snapshot,
|
|
seed,
|
|
claimedWinnersCount: 1,
|
|
claimedReserveCount: 1,
|
|
claimedWinnerIds: draw.winnerIds,
|
|
claimedReserveWinnerIds: draw.reserveWinnerIds,
|
|
claimedDeterministicProofHash: fakeProofHash,
|
|
claimedAuditEventHash: draw.auditEventHash,
|
|
algorithmVersion: draw.algorithmVersion,
|
|
});
|
|
|
|
expect(result.verified).toBe(false);
|
|
expect(result.deterministicProofHashMatch).toBe(false);
|
|
expect(result.winnersMatch).toBe(true);
|
|
});
|
|
});
|