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

Use Sourcify database as default StorageService #1390

Merged
merged 16 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
marcocastignoli marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ openapi: "3.0.0"
paths:
/files/contracts/{chain}:
get:
summary: Get all contract addresses verified on a chain (full or partial match)
description: Returns all verified contracts from the repository for the desired chain. Searches for full and partial matches.
summary: Get the first 100 contract addresses verified on a chain (full or partial match)
description: Returns the first 100 verified contracts from the repository for the desired chain. Searches for full and partial matches.
tags:
- Repository
parameters:
Expand All @@ -14,6 +14,11 @@ paths:
schema:
type: string
format: sourcify-chainId
- name: offset
in: query
required: false
schema:
type: number
responses:
"200":
description: Chain is available as a full match or partial match in the repository
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ type RetrieveMethod = (
address: string,
match: MatchLevel
) => Promise<FilesInfo<any>>;
type ConractRetrieveMethod = (chain: string) => Promise<ContractData>;
type ConractRetrieveMethod = (
chain: string,
offset: number,
paginationSize: number
) => Promise<ContractData>;
marcocastignoli marked this conversation as resolved.
Show resolved Hide resolved

export function createEndpoint(
retrieveMethod: RetrieveMethod,
Expand Down Expand Up @@ -43,7 +47,11 @@ export function createContractEndpoint(
return async (req: Request, res: Response, next: NextFunction) => {
let retrieved: ContractData;
try {
retrieved = await contractRetrieveMethod(req.params.chain);
retrieved = await contractRetrieveMethod(
req.params.chain,
req.query.offset ? parseInt(req.query.offset as string) : 0,
100
);
if (retrieved.full.length === 0 && retrieved.partial.length === 0)
return next(new NotFoundError("Contracts have not been found!"));
} catch (err: any) {
Expand Down Expand Up @@ -96,6 +104,29 @@ export async function checkAllByChainAndAddressEndpoint(
res.send(resultArray);
}

export async function getMetadataEndpoint(req: any, res: Response) {
const { match, chain, address } = req.params;
const file = await services.storage.getMetadata(chain, address, match);
if (file === false) {
res.status(404).send();
}
res.json(JSON.parse(file as string));
}

export async function getFileEndpoint(req: any, res: Response) {
const { match, chain, address } = req.params;
const file = await services.storage.getFile(
chain,
address,
match,
req.params[0]
);
if (!file) {
res.status(404).send();
}
res.send(file);
}

export async function checkByChainAndAddressesEnpoint(req: any, res: Response) {
const map: Map<string, any> = new Map();
const addresses = req.query.addresses.split(",");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
createContractEndpoint,
checkAllByChainAndAddressEndpoint,
checkByChainAndAddressesEnpoint,
getFileEndpoint,
getMetadataEndpoint,
} from "./repository.handlers";
import { safeHandler } from "../controllers.common";

Expand All @@ -16,34 +18,23 @@ const router: Router = Router();
[
{
prefix: "/tree/any",
method: createEndpoint(
services.storage.repositoryV1.getTree,
"any_match",
true
),
method: createEndpoint(services.storage.getTree, "any_match", true),
},
{
prefix: "/any",
method: createEndpoint(
services.storage.repositoryV1.getContent,
"any_match",
true
),
method: createEndpoint(services.storage.getContent, "any_match", true),
},
{
prefix: "/tree",
method: createEndpoint(services.storage.repositoryV1.getTree, "full_match"),
method: createEndpoint(services.storage.getTree, "full_match"),
},
{
prefix: "/contracts",
method: createContractEndpoint(services.storage.repositoryV1.getContracts),
method: createContractEndpoint(services.storage.getContracts),
},
{
prefix: "",
method: createEndpoint(
services.storage.repositoryV1.getContent,
"full_match"
),
method: createEndpoint(services.storage.getContent, "full_match"),
},
].forEach((pair) => {
router
Expand All @@ -60,6 +51,14 @@ router
.route("/check-all-by-addresses")
.get(safeHandler(checkAllByChainAndAddressEndpoint));

router
.route("/repository/contracts/:match/:chain/:address/metadata.json")
.get(safeHandler(getMetadataEndpoint));

router
.route("/repository/contracts/:match/:chain/:address/sources/*")
.get(safeHandler(getFileEndpoint));

router
.route("/check-by-addresses")
.get(safeHandler(checkByChainAndAddressesEnpoint));
Expand Down
6 changes: 0 additions & 6 deletions services/server/src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,12 +266,6 @@ export class Server {
// Enable session only for session endpoints
this.app.use("/*session*", getSessionMiddleware());

this.app.use(
"/repository",
express.static(this.repository),
serveIndex(this.repository, { icons: true })
);

this.app.use("/", routes);
this.app.use(genericErrorHandler);
}
Expand Down
139 changes: 135 additions & 4 deletions services/server/src/server/services/StorageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import {
} from "./storageServices/AllianceDatabaseService";
import logger from "../../common/logger";
import { getMatchStatus } from "../common";
import { ContractData, FileObject, FilesInfo, MatchLevel } from "../types";
import { getFileRelativePath } from "./utils/util";
import config from "config";

export interface IStorageService {
init(): Promise<boolean>;
Expand Down Expand Up @@ -95,6 +98,130 @@ export class StorageService {
}
}

getMetadata = async (
chainId: string,
address: string,
match: MatchLevel
): Promise<string | false> => {
return this.repositoryV2!.getMetadata(chainId, address, match);
};

pushMetadataInFilesInfo = async <T>(
responseWithoutMetadata: FilesInfo<T[]>,
chainId: string,
address: string,
match: MatchLevel
) => {
// files doesn't contain metadata because it's not available in database
// we have to push the metadata (from RepositoryV2) into files
const metadata = await this.getMetadata(
chainId,
address,
responseWithoutMetadata.status === "full" ? "full_match" : "any_match"
);

if (!metadata) {
logger.error("Contract exists in the database but not in RepositoryV2", {
chainId,
address,
match,
});
throw new Error(
"Contract exists in the database but not in RepositoryV2"
);
}

const relativePath = getFileRelativePath(
chainId,
address,
match === "full_match" ? "full" : "partial",
"metadata.json"
);

if (typeof responseWithoutMetadata.files[0] === "string") {
// push the repository url
responseWithoutMetadata.files.push(
(config.get("repositoryV1.serverUrl") + relativePath) as T
);
} else {
// push the object
responseWithoutMetadata.files.push({
name: "metadata.json",
path: relativePath,
content: metadata,
} as T);
}
};

getFile = async (
chainId: string,
address: string,
match: MatchLevel,
path: string
): Promise<string | false> => {
return this.sourcifyDatabase!.getFile(chainId, address, match, path);
};

getTree = async (
chainId: string,
address: string,
match: MatchLevel
): Promise<FilesInfo<string[]>> => {
const responseWithoutMetadata = await this.sourcifyDatabase!.getTree(
chainId,
address,
match
);

// if files is empty it means that the contract doesn't exist
if (responseWithoutMetadata.files.length === 0) {
return responseWithoutMetadata;
}

await this.pushMetadataInFilesInfo<string>(
responseWithoutMetadata,
chainId,
address,
match
);

return responseWithoutMetadata;
};

getContent = async (
chainId: string,
address: string,
match: MatchLevel
): Promise<FilesInfo<FileObject[]>> => {
const responseWithoutMetadata = await this.sourcifyDatabase!.getContent(
chainId,
address,
match
);

// if files is empty it means that the contract doesn't exist
if (responseWithoutMetadata.files.length === 0) {
return responseWithoutMetadata;
}

await this.pushMetadataInFilesInfo<FileObject>(
responseWithoutMetadata,
chainId,
address,
match
);

return responseWithoutMetadata;
};

getContracts = async (
chainId: string,
offset: number,
paginationSize: number
): Promise<ContractData> => {
return this.sourcifyDatabase!.getContracts(chainId, offset, paginationSize);
};

/* async init() {
try {
await this.repositoryV1?.init();
Expand Down Expand Up @@ -124,8 +251,11 @@ export class StorageService {
chainId: string
): Promise<Match[]> {
return (
(await this.repositoryV1?.checkByChainAndAddress?.(address, chainId)) ||
[]
(await this.sourcifyDatabase?.checkByChainAndAddress?.(
address,
chainId,
true
)) || []
);
}

Expand All @@ -134,9 +264,10 @@ export class StorageService {
chainId: string
): Promise<Match[]> {
return (
(await this.repositoryV1?.checkAllByChainAndAddress?.(
(await this.sourcifyDatabase?.checkByChainAndAddress?.(
address,
chainId
chainId,
false
)) || []
);
}
Expand Down
Loading