Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ export interface ISolution {
workerAddress: string;
solution: string;
error?: boolean | SolutionError;
verificationResult?: VerificationResult;
rejectionReason?: SolutionError;
}

export interface ISolutionsFile {
exchangeAddress: string;
solutions: ISolution[];
}

export enum VerificationResult {
Accepted = 'accepted',
Rejected = 'rejected',
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ import { ErrorJob } from '../../common/constants/errors';
import { JobRequestType, SolutionError } from '../../common/enums/job';
import { EventType } from '../../common/enums/webhook';
import { ConflictError, ValidationError } from '../../common/errors';
import { IManifest, ISolution } from '../../common/interfaces/job';
import {
IManifest,
ISolution,
VerificationResult,
} from '../../common/interfaces/job';
import { checkCurseWords } from '../../common/utils/curseWords';
import { sendWebhook } from '../../common/utils/webhook';
import { StorageService } from '../storage/storage.service';
Expand Down Expand Up @@ -48,8 +52,8 @@ export class JobService {
const errorSolutions: ISolution[] = [];
const uniqueSolutions: ISolution[] = [];

const filteredExchangeSolution = exchangeSolutions.filter(
(exchangeSolution) => !exchangeSolution.error,
const filteredExchangeSolution = exchangeSolutions.filter((solution) =>
this.isAcceptedSolution(solution),
);

filteredExchangeSolution.forEach((exchangeSolution) => {
Expand Down Expand Up @@ -88,6 +92,30 @@ export class JobService {
return { errorSolutions, uniqueSolutions };
}

private isAcceptedSolution(solution: ISolution): boolean {
return (
!solution.error &&
solution.verificationResult !== VerificationResult.Rejected
);
}

private toFinalResult(solution: ISolution): ISolution {
const rejectionReason =
solution.error ||
solution.verificationResult === VerificationResult.Rejected
? solution.rejectionReason || (solution.error as SolutionError)
: undefined;

return {
workerAddress: solution.workerAddress,
solution: solution.solution,
verificationResult: rejectionReason
? VerificationResult.Rejected
: VerificationResult.Accepted,
...(rejectionReason ? { rejectionReason } : {}),
};
}

async processJobSolution(webhook: WebhookDto): Promise<string> {
const logger = this.logger.child({
action: 'processJobSolution',
Expand Down Expand Up @@ -149,7 +177,11 @@ export class JobService {
);
}

if (existingJobSolutions.length >= submissionsRequired) {
if (
existingJobSolutions.filter((solution) =>
this.isAcceptedSolution(solution),
).length >= submissionsRequired
) {
logger.warn(ErrorJob.AllSolutionsHaveAlreadyBeenSent, {
submissionsRequired,
nExistingJobSolutions: existingJobSolutions.length,
Expand All @@ -175,7 +207,7 @@ export class JobService {
const jobSolutionUploaded = await this.storageService.uploadJobSolutions(
webhook.escrowAddress,
webhook.chainId,
recordingOracleSolutions,
recordingOracleSolutions.map((solution) => this.toFinalResult(solution)),
);

const lastExchangeSolution =
Expand Down Expand Up @@ -206,8 +238,9 @@ export class JobService {
);

if (
recordingOracleSolutions.filter((solution) => !solution.error).length >=
submissionsRequired
recordingOracleSolutions.filter((solution) =>
this.isAcceptedSolution(solution),
).length >= submissionsRequired
) {
const reputationOracleWebhook = await KVStoreUtils.get(
webhook.chainId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,14 @@ export default function JobDetail() {
},
{ id: 'solution', label: 'Fortune' },
{
id: 'error',
id: 'verificationResult',
label: 'Status',
render: ({ error }) => (error ? 'Refused' : 'Accepted'),
render: ({ verificationResult }) =>
verificationResult === 'rejected'
? 'Rejected'
: 'Accepted',
},
{ id: 'error', label: 'Refused reason' },
{ id: 'rejectionReason', label: 'Rejection reason' },
]}
data={data}
page={page}
Expand Down
3 changes: 2 additions & 1 deletion packages/apps/job-launcher/client/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,10 @@ export type JobDetailsResults = JobDetailsResponse & {
};

export type FortuneFinalResult = {
exchangeAddress: string;
workerAddress: string;
solution: string;
verificationResult: 'accepted' | 'rejected';
rejectionReason?: string;
};

export type Qualification = {
Expand Down
12 changes: 10 additions & 2 deletions packages/apps/job-launcher/server/src/modules/job/job.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,18 @@ export class FortuneFinalResultDto {
@IsString()
public solution: string;

@ApiProperty()
@ApiProperty({
name: 'verification_result',
enum: ['accepted', 'rejected'],
})
@IsNotEmpty()
@IsIn(['accepted', 'rejected'])
public verificationResult: string;

@ApiPropertyOptional({ name: 'rejection_reason' })
@IsOptional()
@IsString()
public error?: string;
public rejectionReason?: string;
}

export class JobListDto {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -950,11 +950,13 @@ describe('JobService', () => {
{
workerAddress: faker.finance.ethereumAddress(),
solution: 'good',
verificationResult: 'accepted',
},
{
workerAddress: faker.finance.ethereumAddress(),
solution: 'bad',
error: 'wrong answer',
verificationResult: 'rejected',
rejectionReason: 'wrong answer',
},
];

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
export type FortuneFinalResult = {
workerAddress: string;
solution: string;
error?: 'duplicated' | 'curse_word';
};

export enum VerificationResult {
Accepted = 'accepted',
Rejected = 'rejected',
}

export type MarketingFinalResult = {
workerAddress: string;
postUrl: string;
verificationResult: VerificationResult;
export class BaseFinalResult {
workerAddress!: string;
verificationResult!: VerificationResult;
rejectionReason?: string;
};
}

export class FortuneFinalResult extends BaseFinalResult {
solution!: string;
}

export class MarketingFinalResult extends BaseFinalResult {
postUrl!: string;
}

type CvatAnnotationMetaJob = {
job_id: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import {
MarketingJobType,
} from '@/common/enums';

export type FortuneManifest = {
export interface BaseManifest<
TJobType extends FortuneJobType | MarketingJobType,
> {
submissionsRequired: number;
requestType: FortuneJobType;
};
jobType: TJobType;
}

export type MarketingManifest = {
job_type: MarketingJobType;
submissions_required: number;
end_date?: string;
};
export type FortuneManifest = BaseManifest<FortuneJobType>;

export interface MarketingManifest extends BaseManifest<MarketingJobType> {
endDate?: string;
}

export type CvatManifest = {
annotation: {
Expand Down
Loading
Loading