Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API v2: GET verification jobs endpoint #1901

Merged
merged 2 commits into from
Mar 3, 2025
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
34 changes: 34 additions & 0 deletions services/database/migrations/20231109160023-sourcify.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,38 @@ exports.up = function (db, callback) {
ALTER TABLE "session" ADD CONSTRAINT "session_pkey" PRIMARY KEY ("sid") NOT DEFERRABLE INITIALLY IMMEDIATE;
CREATE INDEX "IDX_session_expire" ON "session" ("expire");`,
),
// Add verification job tables
db.runSql.bind(
db,
`CREATE TABLE verification_jobs (
id uuid NOT NULL DEFAULT gen_random_uuid(),
started_at timestamptz NOT NULL DEFAULT NOW(),
completed_at timestamptz,
chain_id bigint NOT NULL,
contract_address bytea NOT NULL,
verified_contract_id BIGINT,
error_code varchar,
error_id uuid,
verification_endpoint varchar NOT NULL,
hardware varchar,
compilation_time BIGINT,
CONSTRAINT verification_jobs_pkey PRIMARY KEY (id),
CONSTRAINT verification_jobs_verified_contract_id_fk FOREIGN KEY (verified_contract_id) REFERENCES verified_contracts(id) ON DELETE RESTRICT ON UPDATE RESTRICT
);`,
),
db.runSql.bind(
db,
`CREATE TABLE verification_jobs_ephemeral (
id uuid NOT NULL DEFAULT gen_random_uuid(),
recompiled_creation_code bytea,
recompiled_runtime_code bytea,
onchain_creation_code bytea,
onchain_runtime_code bytea,
creator_transaction_hash bytea,
CONSTRAINT verification_jobs_ephemeral_pkey PRIMARY KEY (id),
CONSTRAINT verification_jobs_ephemeral_id_fk FOREIGN KEY (id) REFERENCES verification_jobs(id) ON DELETE CASCADE ON UPDATE CASCADE
);`,
),
],
callback,
);
Expand All @@ -83,6 +115,8 @@ exports.up = function (db, callback) {
exports.down = function (db, callback) {
async.series(
[
db.dropTable.bind(db, "verification_jobs_ephemeral"),
db.dropTable.bind(db, "verification_jobs"),
db.dropTable.bind(db, "session"),
db.dropTable.bind(db, "sourcify_sync"),
db.dropTable.bind(db, "sourcify_matches"),
Expand Down
114 changes: 76 additions & 38 deletions services/server/src/apiv2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ info:
servers:
- url: 'http://localhost:3000'
description: localhost
- url: 'https://staging.sourcify.dev/server/'
- url: 'https://staging.sourcify.dev/server'
description: Staging
- url: 'https://sourcify.dev/server/'
- url: 'https://sourcify.dev/server'
description: Production
paths:
'/v2/verify/{chainId}/{address}':
Expand Down Expand Up @@ -96,9 +96,9 @@ paths:
servers:
- url: 'http://localhost:3000'
description: localhost
- url: 'https://staging.sourcify.dev/server/'
- url: 'https://staging.sourcify.dev/server'
description: Staging
- url: 'https://sourcify.dev/server/'
- url: 'https://sourcify.dev/server'
description: Production
'/v2/verify/{verificationId}':
get:
Expand All @@ -120,9 +120,9 @@ paths:
servers:
- url: 'http://localhost:3000'
description: localhost
- url: 'https://staging.sourcify.dev/server/'
- url: 'https://staging.sourcify.dev/server'
description: Staging
- url: 'https://sourcify.dev/server/'
- url: 'https://sourcify.dev/server'
description: Production
'/v2/contract/{chainId}/{address}':
get:
Expand Down Expand Up @@ -168,9 +168,9 @@ paths:
servers:
- url: 'http://localhost:3000'
description: localhost
- url: 'https://staging.sourcify.dev/server/'
- url: 'https://staging.sourcify.dev/server'
description: Staging
- url: 'https://sourcify.dev/server/'
- url: 'https://sourcify.dev/server'
description: Production
'/v2/contracts/{chainId}':
get:
Expand Down Expand Up @@ -219,9 +219,9 @@ paths:
servers:
- url: 'http://localhost:3000'
description: localhost
- url: 'https://staging.sourcify.dev/server/'
- url: 'https://staging.sourcify.dev/server'
description: Staging
- url: 'https://sourcify.dev/server/'
- url: 'https://sourcify.dev/server'
description: Production
tags:
- name: Contract Lookup
Expand Down Expand Up @@ -366,13 +366,18 @@ components:
type: string
format: uuid
error:
$ref: '#/components/schemas/GenericErrorResponse'
$ref: '#/components/schemas/MatchingErrorResponse'
description: 'Optional, when the verification fails for some reason.'
jobStartTime:
type: string
format: date-time
jobFinishTime:
type: string
compilationTime:
type: string
description: Time it took to compile the contract on the server in milliseconds.
examples:
- '1333'
required:
- isJobCompleted
- verificationId
Expand All @@ -387,6 +392,7 @@ components:
verificationId: 72d12273-0723-448e-a9f6-f7957128efa5
jobStartTime: '2024-07-24T11:00:00Z'
jobFinishTime: '2024-07-24T12:00:00Z'
compilationTime: '1333'
contract:
match: match
creationMatch: match
Expand All @@ -412,10 +418,16 @@ components:
verificationId: 72d12273-0723-448e-a9f6-f7957128efa5
jobStartTime: '2024-07-24T11:00:00Z'
jobFinishTime: '2024-07-24T12:00:00Z'
compilationTime: '1333'
error:
custom_code: non_existing_contract
message: Contract 0x2738d13E81e30bC615766A0410e7cF199FD59A83 does not exist on chain 11155111
id: 1ac6b91a-0605-4459-93dc-18f210a70192
customCode: non_matching_bytecodes
message: The onchain and recompiled bytecodes don't match.
errorId: 1ac6b91a-0605-4459-93dc-18f210a70192
recompiledCreationCode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033'
recompiledRuntimeCode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033'
onchainCreationCode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070034'
onchainRuntimeCode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070034'
creatorTransactionHash: '0xb6ee9d528b336942dd70d3b41e2811be10a473776352009fd73f85604f5ed206'
contract:
match: null
creationMatch: null
Expand Down Expand Up @@ -863,9 +875,9 @@ components:
examples:
Example 1:
value:
custom_code: unsupported_chain
customCode: unsupported_chain
message: The chain with chainId 9429413 is not supported
id: 1ac6b91a-0605-4459-93dc-18f210a70192
errorId: 1ac6b91a-0605-4459-93dc-18f210a70192
TooManyRequestsResponse:
description: You are sending too many requests to the server
content:
Expand All @@ -875,9 +887,9 @@ components:
examples:
Example 1:
value:
custom_code: too_many_requests
customCode: too_many_requests
message: You are sending too many requests
id: 1ac6b91a-0605-4459-93dc-18f210a70192
errorId: 1ac6b91a-0605-4459-93dc-18f210a70192
ListVerifiedContracts:
description: ''
content:
Expand Down Expand Up @@ -914,9 +926,9 @@ components:
examples:
Example 1:
value:
custom_code: internal_error
customCode: internal_error
message: Something went wrong
id: 1ac6b91a-0605-4459-93dc-18f210a70192
errorId: 1ac6b91a-0605-4459-93dc-18f210a70192
EtherscanLimitResponse:
description: You've reached the API key limit for the Etherscan key.
content:
Expand All @@ -926,9 +938,9 @@ components:
examples:
Example 1:
value:
custom_code: etherscan_limit
customCode: etherscan_limit
message: Etherscan API key limit reached
id: 1ac6b91a-0605-4459-93dc-18f210a70192
errorId: 1ac6b91a-0605-4459-93dc-18f210a70192
ContractNotVerifiedResponse:
description: The contract is not verified on Sourcify
content:
Expand All @@ -952,9 +964,9 @@ components:
examples:
Example 1:
value:
custom_code: job_not_found
customCode: job_not_found
message: The verification job with id 461157eb-e4ea-4c5f-9aec-04c56924fd96 was not found
id: 1ac6b91a-0605-4459-93dc-18f210a70192
errorId: 1ac6b91a-0605-4459-93dc-18f210a70192
schemas:
Language:
type: string
Expand All @@ -969,6 +981,30 @@ components:
pattern: 'v\d+\.\d+\.\d+(-nightly\.\d{4}\.\d+\.\d+)?\+commit\.[a-f0-9]{8}'
examples:
- 0.8.7+commit.e28d00a7
MatchingErrorResponse:
examples:
- customCode: non_matching_bytecodes
message: The onchain and recompiled bytecodes don't match.
errorId: 1ac6b91a-0605-4459-93dc-18f210a70192
recompiledCreationCode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033'
recompiledRuntimeCode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033'
onchainCreationCode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070034'
onchainRuntimeCode: '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070034'
creatorTransactionHash: '0xb6ee9d528b336942dd70d3b41e2811be10a473776352009fd73f85604f5ed206'
allOf:
- $ref: '#/components/schemas/GenericErrorResponse'
- type: object
properties:
recompiledCreationCode:
$ref: '#/components/schemas/BytecodeString'
recompiledRuntimeCode:
$ref: '#/components/schemas/BytecodeString'
onchainCreationCode:
$ref: '#/components/schemas/BytecodeString'
onchainRuntimeCode:
$ref: '#/components/schemas/BytecodeString'
creatorTransactionHash:
$ref: '#/components/schemas/Keccak256'
GenericErrorResponse:
type: object
title: GenericErrorResponse
Expand All @@ -987,11 +1023,25 @@ components:
type: string
format: uuid
required:
- customCode
- message
- errorId
examples:
- custom_code: unsupported_chain
- customCode: unsupported_chain
message: The chain with chainId 9429413 is not supported
id: 1ac6b91a-0605-4459-93dc-18f210a70192
errorId: 1ac6b91a-0605-4459-93dc-18f210a70192
BytecodeString:
type: string
title: BytecodeString
pattern: '^0x([0-9|a-f][0-9|a-f])*$'
examples:
- '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033'
Keccak256:
type: string
title: Keccak256
pattern: '(\b0x[a-f0-9]{64}\b)'
examples:
- '0xb6ee9d528b336942dd70d3b41e2811be10a473776352009fd73f85604f5ed206'
VerifiedContractMinimal:
type: object
title: VerifiedContractMinimal
Expand Down Expand Up @@ -1062,12 +1112,6 @@ components:
$ref: '#/components/schemas/CreationTransformations'
transformationValues:
$ref: '#/components/schemas/CreationTransformationValues'
BytecodeString:
type: string
title: BytecodeString
pattern: '^0x([0-9|a-f][0-9|a-f])*$'
examples:
- '0x608060405234801561001057600080fd5b5060043610610036570565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea264697066735821220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033'
LinkReferences:
type: object
title: LinkReferences
Expand Down Expand Up @@ -1311,12 +1355,6 @@ components:
cborAuxdata:
'1': '0xa26469706673582212201c37bb166aa1bc4777a7471cda1bbba7ef75600cd859180fa30d503673b99f0264736f6c63430008190033'
callProtection: '0x9deba23b95205127e906108f191a26f5d520896a'
Keccak256:
type: string
title: Keccak256
pattern: '(\b0x[a-f0-9]{64}\b)'
examples:
- '0xb6ee9d528b336942dd70d3b41e2811be10a473776352009fd73f85604f5ed206'
HexStringWithout0x:
type: string
title: HexStringWithout0x
Expand Down
46 changes: 45 additions & 1 deletion services/server/src/server/apiv2/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,28 @@
import logger from "../../common/logger";

export type ErrorCode =
| VerificationError
| "unknown_error"
| "route_not_found"
| "unsupported_chain"
| "invalid_parameter"
| "proxy_resolution_error";
| "proxy_resolution_error"
| "job_not_found";

export interface GenericErrorResponse {
customCode: ErrorCode;
message: string;
errorId: string;
}

export interface MatchingErrorResponse extends GenericErrorResponse {
recompiledCreationCode?: string;
recompiledRuntimeCode?: string;
onchainCreationCode?: string;
onchainRuntimeCode?: string;
creatorTransactionHash?: string;
}

export class UnknownError extends InternalServerError {
payload: GenericErrorResponse;

Expand Down Expand Up @@ -73,6 +83,19 @@
}
}

export class JobNotFoundError extends NotFoundError {
payload: GenericErrorResponse;

constructor(message: string) {
super(message);
this.payload = {
customCode: "job_not_found",
message,
errorId: uuidv4(),
};
}
}

// Maps OpenApiValidator errors to our custom error format
export function errorHandler(
err: any,
Expand All @@ -98,3 +121,24 @@
logger.error("Unknown server error: ", err);
next(new UnknownError("The server encountered an unexpected error."));
}

// TODO: Add sensible error codes here,
// possibly from lib-sourcify after the verification flow refactoring
export type VerificationError =
| "non_existing_contract"
| "non_matching_bytecodes";

export function getVerificationErrorMessage(
code: VerificationError,
chainId: string,
address: string,
) {
switch (code) {
case "non_existing_contract":
return `Contract ${address} does not exist on chain ${chainId}`;

Check warning on line 138 in services/server/src/server/apiv2/errors.ts

View check run for this annotation

Codecov / codecov/patch

services/server/src/server/apiv2/errors.ts#L138

Added line #L138 was not covered by tests
case "non_matching_bytecodes":
return `The onchain and recompiled bytecodes don't match`;
default:
return `Unknown verification error`;

Check warning on line 142 in services/server/src/server/apiv2/errors.ts

View check run for this annotation

Codecov / codecov/patch

services/server/src/server/apiv2/errors.ts#L142

Added line #L142 was not covered by tests
}
}
Loading