Skip to content

Commit

Permalink
Merge pull request #487 from BoostryJP/feature/#464
Browse files Browse the repository at this point in the history
feat: add tui explorer
  • Loading branch information
YoshihitoAso authored Mar 6, 2023
2 parents 9e2ba0a + b29c7cd commit b2f1667
Show file tree
Hide file tree
Showing 44 changed files with 2,653 additions and 42 deletions.
20 changes: 11 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,12 @@ RUN . ~/.bash_profile \
&& poetry config virtualenvs.create false

# install python packages
USER apl
COPY pyproject.toml /app/pyproject.toml
COPY poetry.lock /app/poetry.lock
RUN . ~/.bash_profile \
&& poetry install --directory /app --only main --no-root \
&& rm -f /app/pyproject.toml \
&& rm -f /app/poetry.lock

# app deploy
USER root
COPY --chown=apl:apl LICENSE /app/ibet-Prime/
RUN mkdir -p /app/ibet-Prime/bin/
COPY --chown=apl:apl bin/ /app/ibet-Prime/bin/
RUN mkdir -p /app/ibet-Prime/cmd/
COPY --chown=apl:apl cmd/ /app/ibet-Prime/cmd/
RUN mkdir -p /app/ibet-Prime/contracts/
COPY --chown=apl:apl contracts/ /app/ibet-Prime/contracts/
RUN mkdir -p /app/ibet-Prime/conf/
Expand All @@ -88,6 +81,15 @@ COPY --chown=apl:apl app/ /app/ibet-Prime/app/
RUN find /app/ibet-Prime/ -type d -name __pycache__ | xargs rm -fr \
&& chmod -R 755 /app/ibet-Prime/

USER apl
COPY pyproject.toml /app/ibet-Prime/pyproject.toml
COPY poetry.lock /app/ibet-Prime/poetry.lock
RUN . ~/.bash_profile \
&& cd /app/ibet-Prime \
&& poetry install --only main --no-root -E ibet-explorer \
&& rm -f /app/ibet-Prime/pyproject.toml \
&& rm -f /app/ibet-Prime/poetry.lock

# command deploy
USER apl
COPY run.sh healthcheck.sh /app/
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ English | [日本語](./README_JA.md)

Install python packages with:
```bash
$ pip install -r requirements.txt
$ poetry install --no-root --only main -E explorer
```

### Setting environment variables
Expand All @@ -68,13 +68,13 @@ The main environment variables are as follows.
<td>DATABASE_URL</td>
<td>False</td>
<td nowrap>Database URL</td>
<td>postgresql://issuerapi:issuerapipass@localhost:5432/issuerapidb</td>
<td>postgresql+psycopg://issuerapi:issuerapipass@localhost:5432/issuerapidb</td>
</tr>
<tr>
<td>TEST_DATABASE_URL</td>
<td>False</td>
<td nowrap>Test database URL</td>
<td>postgresql://issuerapi:issuerapipass@localhost:5432/issuerapidb</td>
<td>postgresql+psycopg://issuerapi:issuerapipass@localhost:5432/issuerapidb</td>
</tr>
<tr>
<td>DATABASE_SCHEMA</td>
Expand Down
6 changes: 3 additions & 3 deletions README_JA.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@

以下のコマンドで Python パッケージをインストールします。
```bash
$ pip install -r requirements.txt
$ poetry install --no-root --only main -E explorer
```

### 環境変数の設定
Expand All @@ -69,13 +69,13 @@ $ pip install -r requirements.txt
<td>DATABASE_URL</td>
<td>False</td>
<td nowrap>データベース URL</td>
<td>postgresql://issuerapi:issuerapipass@localhost:5432/issuerapidb</td>
<td>postgresql+psycopg://issuerapi:issuerapipass@localhost:5432/issuerapidb</td>
</tr>
<tr>
<td>TEST_DATABASE_URL</td>
<td>False</td>
<td nowrap>テスト用データベース URL</td>
<td>postgresql://issuerapi:issuerapipass@localhost:5432/issuerapidb</td>
<td>postgresql+psycopg://issuerapi:issuerapipass@localhost:5432/issuerapidb</td>
</tr>
<tr>
<td>DATABASE_SCHEMA</td>
Expand Down
4 changes: 3 additions & 1 deletion app/model/schema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@
# Response
BlockDataResponse,
BlockDataListResponse,
BlockDataDetail,
TxDataResponse,
TxDataListResponse
TxDataListResponse,
TxDataDetail
)
from .bulk_transfer import (
# Response
Expand Down
15 changes: 14 additions & 1 deletion app/model/schema/bc_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@
from pydantic.dataclasses import dataclass
from web3 import Web3

from .types import ResultSet
from .types import (
ResultSet,
SortOrder
)


############################
Expand All @@ -44,6 +47,7 @@ class BlockData(BaseModel):
gas_used: int
size: NonNegativeInt


class BlockDataDetail(BaseModel):
number: NonNegativeInt = Field(description="Block number")
parent_hash: str
Expand All @@ -64,6 +68,7 @@ class BlockDataDetail(BaseModel):
size: NonNegativeInt
transactions: list[str] = Field(description="Transaction list")


class TxData(BaseModel):
hash: str = Field(description="Transaction hash")
block_hash: str
Expand All @@ -72,6 +77,7 @@ class TxData(BaseModel):
from_address: str
to_address: Optional[str]


class TxDataDetail(BaseModel):
hash: str = Field(description="Transaction hash")
block_hash: str
Expand All @@ -87,6 +93,7 @@ class TxDataDetail(BaseModel):
value: NonNegativeInt
nonce: NonNegativeInt


############################
# REQUEST
############################
Expand All @@ -97,6 +104,8 @@ class ListBlockDataQuery:
limit: Optional[NonNegativeInt] = Query(default=None, description="number of set")
from_block_number: Optional[NonNegativeInt] = Query(default=None)
to_block_number: Optional[NonNegativeInt] = Query(default=None)
sort_order: Optional[SortOrder] = Query(default=SortOrder.ASC, description="sort order(0: ASC, 1: DESC)")


@dataclass
class ListTxDataQuery:
Expand All @@ -120,20 +129,24 @@ def to_address_is_valid_address(cls, v):
raise ValueError("to_address is not a valid address")
return v


############################
# RESPONSE
############################

class BlockDataResponse(BaseModel):
__root__: BlockDataDetail


class BlockDataListResponse(BaseModel):
result_set: ResultSet
block_data: list[BlockData]


class TxDataResponse(BaseModel):
__root__: TxDataDetail


class TxDataListResponse(BaseModel):
result_set: ResultSet
tx_data: list[TxData]
35 changes: 30 additions & 5 deletions app/routers/bc_explorer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@
SPDX-License-Identifier: Apache-2.0
"""
from pathlib import Path
from typing import Tuple, Dict, Any, Type

from eth_utils import to_checksum_address
from fastapi import (
APIRouter,
Depends, HTTPException
Depends,
HTTPException,
Path
)
from pydantic import NonNegativeInt
from sqlalchemy import desc
from sqlalchemy.orm import Session
from web3.contract import ContractFunction
import config

from app import log
from app.database import db_session
Expand All @@ -36,7 +38,9 @@
)
from app.model.db import (
IDXBlockData,
IDXTxData, Token
IDXTxData,
Token,
IDXBlockDataBlockNumber
)
from app.model.schema import (
ListBlockDataQuery,
Expand Down Expand Up @@ -90,9 +94,27 @@ def list_block_data(
limit = request_query.limit
from_block_number = request_query.from_block_number
to_block_number = request_query.to_block_number
sort_order = request_query.sort_order # default: asc

# NOTE: The more data, the slower the SELECT COUNT(1) query becomes.
# To get total number of block data, latest block number where block data synced is used here.
idx_block_data_block_number = (
session.query(IDXBlockDataBlockNumber).filter(IDXBlockDataBlockNumber.chain_id == str(config.CHAIN_ID)).first()
)
if idx_block_data_block_number is None:
return json_response({
"result_set": {
"count": 0,
"offset": offset,
"limit": limit,
"total": 0
},
"block_data": []
})

total = idx_block_data_block_number.latest_block_number + 1

query = session.query(IDXBlockData)
total = query.count()

# Search Filter
if from_block_number is not None and to_block_number is not None:
Expand All @@ -105,7 +127,10 @@ def list_block_data(
count = query.count()

# Sort
query = query.order_by(IDXBlockData.number)
if sort_order == 0:
query = query.order_by(IDXBlockData.number)
else:
query = query.order_by(desc(IDXBlockData.number))

# Pagination
if limit is not None:
Expand Down
21 changes: 21 additions & 0 deletions cmd/explorer/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.PHONY: isort black test run

format: isort black

isort:
isort src/.

black:
poetry run black src

test:
pytest .

console:
textual console

dev:
TEXTUAL=devtools poetry run python src/main.py

run:
poetry run python src/main.py
44 changes: 44 additions & 0 deletions cmd/explorer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# ibet-Prime BC-Explorer

## Run

### with container

```bash
> docker exec -it -e "TERM=xterm-256color" ibet-prime-app bash --login
> apl@2e5a80e06fcb:/$ ibet-explorer --help

Usage: ibet-explorer [OPTIONS]

╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ --url TEXT ibet-Prime server URL to connect [default: http://localhost:5000] │
│ --lot-size INTEGER Lot size to fetch Block Data list [default: 100] │
│ --install-completion [bash|zsh|fish|powershell|pwsh] Install completion for the specified shell. [default: None] │
│ --show-completion [bash|zsh|fish|powershell|pwsh] Show completion for the specified shell, to copy it or customize the installation. [default: None] │
│ --help Show this message and exit. │
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
```

- **URL**: ibet-Prime URL.
- You can run this on pythonic way in local.

### Poetry
```bash
> poetry install
> poetry run python src/main.py --url http://localhost:5000
```

### Pip
```bash
> pip install -e ./
> python src/main.py --url http://localhost:5000
```

## Screenshots 👀

![query-setting](https://user-images.githubusercontent.com/15183665/222354993-0c11eedc-fb22-472a-8c9f-f9bc8be4d173.png)

![block](https://user-images.githubusercontent.com/15183665/222355008-0c893524-2a80-4975-9c44-537649b11fc7.png)

![transaction](https://user-images.githubusercontent.com/15183665/222355025-24b72685-8d27-48e5-9ea1-b265c4365629.png)

7 changes: 7 additions & 0 deletions cmd/explorer/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions cmd/explorer/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[tool.poetry]
name = "ibet-prime-explorer"
version = "0.1.0"
description = "ibet-Prime Terminal UI for Block Chain Explorer"
authors = ["BOOSTRY Co., Ltd. <dev@boostry.co.jp>"]
readme = "README.md"
packages = [
{ include = "src" },
]

[tool.poetry.dependencies]
python = "3.10.4"

[tool.poetry.scripts]
ibet-explorer = "src.main:app"

[tool.mypy]
python_version = "3.10"
no_strict_optional = true
ignore_missing_imports = true
check_untyped_defs = true

[tool.black]
includes = "src"
target-version = ['py310']
line-length = 120

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
18 changes: 18 additions & 0 deletions cmd/explorer/src/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""
Copyright BOOSTRY Co., Ltd.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache-2.0
"""
Loading

0 comments on commit b2f1667

Please sign in to comment.