Skip to content

Commit

Permalink
Merge branch 'main' into change-runners-to-matterlabs-ci-runner
Browse files Browse the repository at this point in the history
  • Loading branch information
alexandrst88 authored Oct 16, 2023
2 parents 972c2b2 + 8f42c78 commit 8ad0229
Show file tree
Hide file tree
Showing 74 changed files with 885 additions and 146 deletions.
1 change: 0 additions & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,3 @@
- [ ] PR title corresponds to the body of PR (we generate changelog entries from PRs).
- [ ] Tests for the changes have been added / updated.
- [ ] Documentation comments have been added / updated.
- [ ] Code has been formatted via `zk fmt` and `zk lint`.
14 changes: 14 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,20 @@ jobs:
file: packages/worker/Dockerfile
no-cache: true

- name: Build and push Docker image for App
uses: docker/build-push-action@v4
with:
push: true
tags: |
"matterlabs/block-explorer-app:latest"
"matterlabs/block-explorer-app:v${{ needs.createReleaseVersion.outputs.releaseVersion }}"
"matterlabs/block-explorer-app:${{ steps.setVersionForFlux.outputs.imageTag }}"
"us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/block-explorer-app:latest"
"us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/block-explorer-app:v${{ needs.createReleaseVersion.outputs.releaseVersion }}"
"us-docker.pkg.dev/matterlabs-infra/matterlabs-docker/block-explorer-app:${{ steps.setVersionForFlux.outputs.imageTag }}"
file: packages/app/Dockerfile
no-cache: true

deployFrontendToStaging:
name: Deploy Block Explorer frontend to staging
runs-on: ubuntu-latest
Expand Down
74 changes: 74 additions & 0 deletions docker-compose-cli.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
version: '3.2'

services:
app:
build:
context: .
dockerfile: ./packages/app/Dockerfile
environment:
- VITE_APP_ENVIRONMENT=local
ports:
- '3010:3010'
depends_on:
- api
restart: unless-stopped

worker:
build:
context: .
dockerfile: ./packages/worker/Dockerfile
environment:
- PORT=3001
- LOG_LEVEL=verbose
- NODE_ENV=development
- DATABASE_HOST=postgres
- DATABASE_USER=postgres
- DATABASE_PASSWORD=postgres
- DATABASE_NAME=block-explorer
- BLOCKCHAIN_RPC_URL=http://host.docker.internal:3050
- BATCHES_PROCESSING_POLLING_INTERVAL=1000
ports:
- '3001:3001'
- '9229:9229'
- '9230:9230'
restart: unless-stopped

api:
build:
context: .
dockerfile: ./packages/api/Dockerfile
environment:
- PORT=3020
- METRICS_PORT=3005
- LOG_LEVEL=verbose
- NODE_ENV=development
- DATABASE_URL=postgres://postgres:postgres@postgres:5432/block-explorer
ports:
- '3020:3020'
- '3005:3005'
- '9231:9229'
- '9232:9230'
depends_on:
- worker
restart: unless-stopped

postgres:
image: "postgres:14"
logging:
driver: none
volumes:
- postgres:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 5s
timeout: 5s
retries: 5
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=block-explorer

volumes:
postgres:
7 changes: 5 additions & 2 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ services:
build:
context: .
dockerfile: ./packages/app/Dockerfile
target: development-stage
command: npm run --prefix packages/app dev -- --host
ports:
- '3010:3010'
volumes:
- ./packages/app:/usr/src/app/packages/app
- /usr/src/app/packages/app/node_modules
depends_on:
- api
restart: unless-stopped
Expand All @@ -26,14 +30,14 @@ services:
- DATABASE_PASSWORD=postgres
- DATABASE_NAME=block-explorer
- BLOCKCHAIN_RPC_URL=http://zksync:3050
- BATCHES_PROCESSING_POLLING_INTERVAL=1000
ports:
- '3001:3001'
- '9229:9229'
- '9230:9230'
volumes:
- ./packages/worker:/usr/src/app/packages/worker
- /usr/src/app/packages/worker/node_modules
- ./node_modules:/usr/src/worker/node_modules:ro
depends_on:
zksync:
condition: service_healthy
Expand All @@ -59,7 +63,6 @@ services:
volumes:
- ./packages/api:/usr/src/app/packages/api
- /usr/src/app/packages/api/node_modules
- ./node_modules:/usr/src/api/node_modules:ro
depends_on:
- worker
restart: unless-stopped
Expand Down
3 changes: 2 additions & 1 deletion packages/api/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,6 @@ ENV METRICS_PORT $METRICS_PORT
EXPOSE $PORT $METRICS_PORT 9229 9230

USER node
WORKDIR /usr/src/app/packages/api

CMD [ "node", "packages/api/dist/main.js" ]
CMD [ "node", "dist/main.js" ]
2 changes: 1 addition & 1 deletion packages/api/src/address/address.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { TransferDto } from "../transfer/transfer.dto";

const entityName = "address";

@ApiTags(entityName)
@ApiTags("Address BFF")
@Controller(entityName)
export class AddressController {
constructor(
Expand Down
39 changes: 39 additions & 0 deletions packages/api/src/api/account/account.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { mock } from "jest-mock-extended";
import { BadRequestException, Logger } from "@nestjs/common";
import { L2_ETH_TOKEN_ADDRESS } from "../../common/constants";
import { BlockService } from "../../block/block.service";
import { BlockDetail } from "../../block/blockDetail.entity";
import { TransactionService } from "../../transaction/transaction.service";
import { BalanceService } from "../../balance/balance.service";
import { TransactionStatus } from "../../transaction/entities/transaction.entity";
Expand Down Expand Up @@ -104,6 +105,7 @@ describe("AccountController", () => {
beforeEach(async () => {
blockServiceMock = mock<BlockService>({
getLastBlockNumber: jest.fn().mockResolvedValue(100),
findMany: jest.fn().mockResolvedValue([]),
});
transactionServiceMock = mock<TransactionService>({
findByAddress: jest.fn().mockResolvedValue([]),
Expand Down Expand Up @@ -603,4 +605,41 @@ describe("AccountController", () => {
expect(parseAddressListPipeExceptionFactory()).toEqual(new BadRequestException("Error! Missing address"));
});
});

describe("getAccountMinedBlocks", () => {
it("returns not ok response when no blocks by miner found", async () => {
const response = await controller.getAccountMinedBlocks(address, {
page: 1,
offset: 10,
maxLimit: 100,
});
expect(response).toEqual({
status: ResponseStatus.NOTOK,
message: ResponseMessage.NO_TRANSACTIONS_FOUND,
result: [],
});
});

it("returns blocks list response when block by miner are found", async () => {
jest
.spyOn(blockServiceMock, "findMany")
.mockResolvedValue([{ number: 1, timestamp: new Date("2023-03-03") } as BlockDetail]);
const response = await controller.getAccountMinedBlocks(address, {
page: 1,
offset: 10,
maxLimit: 100,
});
expect(response).toEqual({
status: ResponseStatus.OK,
message: ResponseMessage.OK,
result: [
{
blockNumber: "1",
timeStamp: "1677801600",
blockReward: "0",
},
],
});
});
});
});
30 changes: 30 additions & 0 deletions packages/api/src/api/account/account.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Controller, Get, Query, Logger, UseFilters, ParseArrayPipe, BadRequestE
import { ApiTags, ApiExcludeController } from "@nestjs/swagger";
import { L2_ETH_TOKEN_ADDRESS } from "../../common/constants";
import { TokenType } from "../../token/token.entity";
import { dateToTimestamp } from "../../common/utils";
import { BlockService } from "../../block/block.service";
import { TransactionService } from "../../transaction/transaction.service";
import { TransferService } from "../../transfer/transfer.service";
Expand All @@ -25,6 +26,7 @@ import {
AccountEtherBalanceResponseDto,
AccountsEtherBalancesResponseDto,
} from "../dtos/account/accountEtherBalanceResponse.dto";
import { AccountMinedBlocksResponseDto } from "../dtos/account/accountMinedBlocksResponse.dto";
import { ApiExceptionFilter } from "../exceptionFilter";

const entityName = "account";
Expand Down Expand Up @@ -225,4 +227,32 @@ export class AccountController {
result: balance,
};
}

@Get("/getminedblocks")
public async getAccountMinedBlocks(
@Query("address", new ParseAddressPipe()) address: string,
@Query() pagingOptions: PagingOptionsWithMaxItemsLimitDto
): Promise<AccountMinedBlocksResponseDto> {
const blocks = await this.blockService.findMany({
miner: address,
...pagingOptions,
selectFields: ["number", "timestamp"],
});
if (!blocks.length) {
return {
status: ResponseStatus.NOTOK,
message: ResponseMessage.NO_TRANSACTIONS_FOUND,
result: [],
};
}
return {
status: ResponseStatus.OK,
message: ResponseMessage.OK,
result: blocks.map((block) => ({
blockNumber: block.number.toString(),
timeStamp: dateToTimestamp(block.timestamp).toString(),
blockReward: "0",
})),
};
}
}
7 changes: 7 additions & 0 deletions packages/api/src/api/api.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ describe("ApiController", () => {
});
});

describe("getAccountMinedBlocks", () => {
it("returns null as it is defined only to appear in docs and cannot be called", async () => {
const result = await controller.getAccountMinedBlocks({ page: 1, offset: 10, maxLimit: 1000 });
expect(result).toBe(null);
});
});

describe("getBlockNumberByTimestamp", () => {
it("returns null as it is defined only to appear in docs and cannot be called", async () => {
const result = await controller.getBlockNumberByTimestamp();
Expand Down
23 changes: 23 additions & 0 deletions packages/api/src/api/api.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
AccountsEtherBalancesResponseDto,
} from "./dtos/account/accountEtherBalanceResponse.dto";
import { AccountTokenBalanceResponseDto } from "./dtos/account/accountTokenBalanceResponse.dto";
import { AccountMinedBlock } from "./dtos/account/accountMinedBlock.dto";
import { AccountMinedBlocksResponseDto } from "./dtos/account/accountMinedBlocksResponse.dto";
import { BlockNumberResponseDto } from "./dtos/block/blockNumberResponse.dto";
import { BlockCountdownResponseDto } from "./dtos/block/blockCountdownResponse.dto";
import { BlockRewardResponseDto } from "./dtos/block/blockRewardResponse.dto";
Expand Down Expand Up @@ -364,6 +366,27 @@ export class ApiController {
return null;
}

@ApiTags("Account API")
@Get("api?module=account&action=getminedblocks")
@ApiOperation({ summary: "Get list of Blocks Validated by Address" })
@ApiQuery({
name: "address",
description: "The address to get validated blocks by",
example: "0x0000000000000000000000000000000000000000",
required: true,
})
@ApiExtraModels(AccountMinedBlock)
@ApiOkResponse({
description: "Blocks validated by address",
type: AccountMinedBlocksResponseDto,
})
public async getAccountMinedBlocks(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@Query() pagingOptions: PagingOptionsWithMaxItemsLimitDto
): Promise<AccountMinedBlocksResponseDto> {
return null;
}

@ApiTags("Block API")
@Get("api?module=block&action=getblocknobytime")
@ApiOperation({ summary: "Retrieve block number closest to a specific timestamp" })
Expand Down
24 changes: 24 additions & 0 deletions packages/api/src/api/dtos/account/accountMinedBlock.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ApiProperty } from "@nestjs/swagger";

export class AccountMinedBlock {
@ApiProperty({
type: String,
description: "The number (height) of the block",
example: "3233097",
})
public readonly blockNumber: string;

@ApiProperty({
type: String,
description: "The timestamp of the block",
example: "1679988122",
})
public readonly timeStamp: string;

@ApiProperty({
type: String,
description: "Reward for the block",
example: "1000",
})
public readonly blockReward: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ApiProperty } from "@nestjs/swagger";
import { ResponseBaseDto } from "../common/responseBase.dto";
import { AccountMinedBlock } from "./accountMinedBlock.dto";

export class AccountMinedBlocksResponseDto extends ResponseBaseDto {
@ApiProperty({
description: "List of blocks validated by address",
type: AccountMinedBlock,
isArray: true,
})
public readonly result: AccountMinedBlock[];
}
8 changes: 4 additions & 4 deletions packages/api/src/api/log/log.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe("LogController", () => {
const address = "address";
beforeEach(async () => {
logServiceMock = mock<LogService>({
findLogs: jest.fn().mockResolvedValue([
findMany: jest.fn().mockResolvedValue([
{
logIndex: 1,
},
Expand Down Expand Up @@ -52,8 +52,8 @@ describe("LogController", () => {
0,
10
);
expect(logServiceMock.findLogs).toBeCalledTimes(1);
expect(logServiceMock.findLogs).toBeCalledWith({
expect(logServiceMock.findMany).toBeCalledTimes(1);
expect(logServiceMock.findMany).toBeCalledWith({
address,
fromBlock: 0,
toBlock: 10,
Expand Down Expand Up @@ -89,7 +89,7 @@ describe("LogController", () => {
});

it("returns not ok response and empty logs list when logs are not found", async () => {
(logServiceMock.findLogs as jest.Mock).mockResolvedValueOnce([]);
(logServiceMock.findMany as jest.Mock).mockResolvedValueOnce([]);
const response = await controller.getLogs(
address,
{
Expand Down
2 changes: 1 addition & 1 deletion packages/api/src/api/log/log.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class LogController {
@Query("fromBlock", new ParseLimitedIntPipe({ min: 0, isOptional: true })) fromBlock?: number,
@Query("toBlock", new ParseLimitedIntPipe({ min: 0, isOptional: true })) toBlock?: number
): Promise<LogsResponseDto> {
const logs = await this.logService.findLogs({
const logs = await this.logService.findMany({
address,
fromBlock,
toBlock,
Expand Down
1 change: 1 addition & 0 deletions packages/api/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export enum ApiAccountAction {
TokenBalance = "tokenbalance",
TokenTransfers = "tokentx",
NFTTransfers = "tokennfttx",
GetMinedBlocks = "getminedblocks",
}

export enum ApiContractAction {
Expand Down
Loading

0 comments on commit 8ad0229

Please sign in to comment.