├── .dockerignore ├── hsdexplorer ├── explorer │ ├── __init__.py │ ├── history │ │ ├── __init__.py │ │ └── write.py │ ├── migrations │ │ ├── __init__.py │ │ └── 0001_initial.py │ ├── templatetags │ │ ├── __init__.py │ │ └── hsd_math.py │ ├── tests.py │ ├── apps.py │ ├── static │ │ ├── img │ │ │ ├── right_red_arrow.png │ │ │ ├── right_black_arrow.png │ │ │ └── right_green_arrow.png │ │ ├── scss │ │ │ ├── modules │ │ │ │ └── _colors.scss │ │ │ ├── main.scss │ │ │ └── partials │ │ │ │ ├── _card.scss │ │ │ │ ├── _tables.scss │ │ │ │ ├── _header.scss │ │ │ │ ├── _layout.scss │ │ │ │ └── _box.scss │ │ └── js │ │ │ └── popper.min.js │ ├── admin.py │ ├── templates │ │ └── explorer │ │ │ ├── _tx-input-list.html │ │ │ ├── events.html │ │ │ ├── blocks.html │ │ │ ├── _block-table.html │ │ │ ├── _pagination.html │ │ │ ├── _events-table.html │ │ │ ├── index.html │ │ │ ├── about.html │ │ │ ├── _events-single-table.html │ │ │ ├── names.html │ │ │ ├── _transaction.html │ │ │ ├── _tx-output-list.html │ │ │ ├── address.html │ │ │ ├── name.html │ │ │ ├── block.html │ │ │ ├── transaction.html │ │ │ └── base.html │ ├── math.py │ ├── urls.py │ ├── utils.py │ ├── models.py │ ├── tasks.py │ ├── views.py │ └── hsd.py ├── .dockerignore ├── hsdexplorer │ ├── middleware │ │ ├── __init__.py │ │ └── health.py │ ├── __init__.py │ ├── wsgi.py │ ├── celery.py │ ├── urls.py │ └── settings.py ├── hsdbin │ ├── decode.js │ ├── package.json │ ├── key.js │ ├── package-lock.json │ ├── compress.js │ └── records.js └── manage.py ├── .gitignore ├── docs ├── constants.md └── transactions.md ├── skaffold.yaml ├── Pipfile ├── Dockerfile ├── kube ├── redis.yaml ├── handshake-node.yaml ├── postgres.yaml └── handshake-explorer.yaml ├── README.md ├── .circleci └── config.yml ├── Pipfile.lock └── LICENSE /.dockerignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hsdexplorer/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/history/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/templatetags/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hsdexplorer/hsdexplorer/middleware/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ExplorerConfig(AppConfig): 5 | name = 'explorer' 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.swp 3 | GeoIP.dat 4 | node_modules/ 5 | celerybeat-schedule 6 | **/static/**/scss/**/*.css 7 | **/static/**/scss/**/*.css.map 8 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/img/right_red_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdickman/handshake-explorer/HEAD/hsdexplorer/explorer/static/img/right_red_arrow.png -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/img/right_black_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdickman/handshake-explorer/HEAD/hsdexplorer/explorer/static/img/right_black_arrow.png -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/img/right_green_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tdickman/handshake-explorer/HEAD/hsdexplorer/explorer/static/img/right_green_arrow.png -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/scss/modules/_colors.scss: -------------------------------------------------------------------------------- 1 | $background: #EBE9E9; 2 | $boxBackground: #FFF; 3 | $boxHeaderBackground: #F7F2F2; 4 | $lightGrey: grey; 5 | $black: #3E3F3A; 6 | -------------------------------------------------------------------------------- /hsdexplorer/hsdbin/decode.js: -------------------------------------------------------------------------------- 1 | const Resource = require('./resource'); 2 | 3 | data = process.argv[2]; 4 | b = new Buffer.from(data, 'hex'); 5 | console.log(JSON.stringify(Resource.decode(b))); 6 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/scss/main.scss: -------------------------------------------------------------------------------- 1 | @import 'vendor/bootstrap'; 2 | @import 'partials/box'; 3 | @import 'partials/card'; 4 | @import 'partials/layout'; 5 | @import 'partials/header'; 6 | @import 'partials/tables'; 7 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from . import models 3 | 4 | # Register your models here. 5 | admin.site.register(models.Name) 6 | admin.site.register(models.Block) 7 | admin.site.register(models.Event) 8 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/templatetags/hsd_math.py: -------------------------------------------------------------------------------- 1 | from django import template 2 | 3 | register = template.Library() 4 | 5 | 6 | @register.filter(name='to_hns') 7 | def to_hns(value): 8 | if value is None or value == '': 9 | return '' 10 | return value / 1000000 11 | -------------------------------------------------------------------------------- /hsdexplorer/hsdexplorer/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import, unicode_literals 2 | 3 | # This will make sure the app is always imported when 4 | # Django starts so that shared_task will use this app. 5 | from .celery import app as celery_app 6 | 7 | __all__ = ('celery_app',) 8 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/scss/partials/_card.scss: -------------------------------------------------------------------------------- 1 | @import '../modules/colors'; 2 | 3 | .border-secondary { 4 | border-color: #fff !important; 5 | } 6 | 7 | .card-header { 8 | background-color: $boxHeaderBackground; 9 | } 10 | 11 | .row .tx-card { 12 | margin-top: 1rem; 13 | } 14 | 15 | .tx-arrow { 16 | width: 16px; 17 | } 18 | -------------------------------------------------------------------------------- /docs/constants.md: -------------------------------------------------------------------------------- 1 | # Network Constants 2 | 3 | Values for Testnet: 4 | 5 | * Open period - 72 blocks (~6 hours) == treeInterval 6 | 7 | Values: 8 | 9 | * Mainnet - https://github.com/handshake-org/hsd/blob/master/lib/protocol/networks.js#L230 10 | * Testnet - https://github.com/handshake-org/hsd/blob/master/lib/protocol/networks.js#L683 11 | -------------------------------------------------------------------------------- /skaffold.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: skaffold/v1alpha5 2 | kind: Config 3 | build: 4 | artifacts: 5 | - image: gcr.io/hello-world-392/handshake-explorer 6 | context: . 7 | deploy: 8 | kubectl: 9 | manifests: 10 | - ./kube/*.yaml 11 | profiles: 12 | - name: gcb 13 | build: 14 | googleCloudBuild: 15 | projectId: hello-world-392 16 | -------------------------------------------------------------------------------- /hsdexplorer/hsdbin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hsd", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "decode.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bns": "^0.3.0", 13 | "bstring": "^0.2.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/scss/partials/_tables.scss: -------------------------------------------------------------------------------- 1 | @import '../modules/colors'; 2 | 3 | .table { 4 | margin-bottom: 0; 5 | } 6 | 7 | .table th, .table td { 8 | border-top: 0; 9 | padding: 0.5rem; 10 | } 11 | 12 | .table thead th { 13 | border-bottom: 0; 14 | color: $lightGrey; 15 | font-weight: 200; 16 | } 17 | 18 | td.label { 19 | color: $lightGrey; 20 | } 21 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/scss/partials/_header.scss: -------------------------------------------------------------------------------- 1 | .bg-primary { 2 | background-color: #3581B8 !important; 3 | } 4 | 5 | .search-icon { 6 | margin-left: -33px; 7 | font-weight: 500; 8 | font-size: 18px; 9 | -webkit-transform: rotate(45deg); 10 | -moz-transform: rotate(45deg); 11 | -o-transform: rotate(45deg); 12 | transform: rotate(45deg); 13 | cursor: pointer; 14 | } 15 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/templates/explorer/_tx-input-list.html: -------------------------------------------------------------------------------- 1 | {% load hsd_math %} 2 | 11 | -------------------------------------------------------------------------------- /hsdexplorer/hsdexplorer/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for hsdexplorer project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hsdexplorer.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/templates/explorer/events.html: -------------------------------------------------------------------------------- 1 | {% extends "explorer/base.html" %} 2 | {% block title %}Handshake Explorer: Events{% endblock %} 3 | {% block content %} 4 |
5 |
6 |
Latest Events
7 |
8 |
9 | {% include "explorer/_events-table.html" %} 10 | {% include "explorer/_pagination.html" with url_prefix="/events" %} 11 |
12 |
13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/math.py: -------------------------------------------------------------------------------- 1 | def total_received(txs, address): 2 | received = 0 3 | for tx in txs: 4 | for it in tx['outputs']: 5 | if it.get('address') == address: 6 | received += it.get('value', 0) 7 | return received 8 | 9 | 10 | def total_sent(txs, address): 11 | sent = 0 12 | for tx in txs: 13 | for ot in tx['inputs']: 14 | if ot.get('address') == address: 15 | sent += ot.get('value', 0) 16 | return sent 17 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [dev-packages] 7 | 8 | [packages] 9 | gunicorn = "*" 10 | django = ">=2.1.2" 11 | whitenoise = "*" 12 | requests = "*" 13 | "pysha3" = "*" 14 | django-tz-detect = "*" 15 | redis = "*" 16 | "psycopg2-binary" = "*" 17 | django-debug-toolbar = "*" 18 | libsass = "*" 19 | django-compressor = "*" 20 | django-sass-processor = "*" 21 | django-redis = "*" 22 | celery = "*" 23 | django-extensions = "*" 24 | django-memoize = "*" 25 | 26 | [requires] 27 | python_version = "3.6" 28 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/scss/partials/_layout.scss: -------------------------------------------------------------------------------- 1 | @import '../modules/colors'; 2 | 3 | body { 4 | padding-top: 100px; 5 | } 6 | 7 | h1 { 8 | padding: 2rem 0; 9 | } 10 | 11 | h2 { 12 | padding: 2rem 0 1.3rem; 13 | } 14 | 15 | .right { 16 | float: right; 17 | text-align: right; 18 | } 19 | 20 | .full { 21 | width: 100%; 22 | } 23 | 24 | .row { 25 | margin-right: 0px; 26 | margin-left: 0px; 27 | } 28 | 29 | /* Layout */ 30 | body { 31 | background-color: $background; 32 | } 33 | 34 | /* Links */ 35 | a, a:hover { 36 | color: $black; 37 | } 38 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/templates/explorer/blocks.html: -------------------------------------------------------------------------------- 1 | {% extends "explorer/base.html" %} 2 | {% block title %}Handshake Explorer: Blocks{% endblock %} 3 | {% block content %} 4 | 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /hsdexplorer/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'hsdexplorer.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/static/scss/partials/_box.scss: -------------------------------------------------------------------------------- 1 | @import '../modules/colors'; 2 | 3 | .box { 4 | margin-bottom: 21px; 5 | width: 100%; 6 | background-color: $boxBackground; 7 | border-radius: 5px; 8 | box-shadow: 0 2px 2px rgba(0, 0, 0, 0.1); 9 | overflow: hidden; 10 | } 11 | 12 | .box-header { 13 | background-color: $boxHeaderBackground; 14 | line-height: 21px; 15 | padding: 10px 20px; 16 | } 17 | 18 | .box-header-right { 19 | float: right; 20 | } 21 | 22 | .box-header-title { 23 | color: $black; 24 | font-size: 16px; 25 | } 26 | 27 | .box-body { 28 | padding: 8px 15px 8px 15px; 29 | overflow-x: auto; 30 | } 31 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/templates/explorer/_block-table.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {% for block in blocks %} 12 | 13 | 14 | 15 | 16 | 17 | 18 | {% endfor %} 19 | 20 |
HeightAgeTransactionsMiner
{{ block.height }}{{ block.time }}{{ block.txs | length }}{{ block.txs.0.outputs.0.address }}
21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | 3 | RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - 4 | RUN apt update && apt install -y nodejs libunbound-dev && rm -rf /var/lib/apt/lists/* 5 | 6 | WORKDIR /app 7 | RUN pip install pipenv 8 | ADD Pipfile* /tmp/ 9 | RUN cd /tmp && pipenv install --system --deploy 10 | 11 | ADD hsdexplorer/hsdbin/package.json /app/hsdbin/ 12 | RUN cd hsdbin && npm install 13 | 14 | ADD ./hsdexplorer/ /app/ 15 | RUN COLLECTSTATIC=1 echo 'yes' | python manage.py collectstatic; python manage.py compilescss; unset COLLECTSTATIC 16 | 17 | ENTRYPOINT ["gunicorn", "--bind", "0.0.0.0:8000", "--log-level", "debug", "hsdexplorer.wsgi"] 18 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/templates/explorer/_pagination.html: -------------------------------------------------------------------------------- 1 | {# Required variables: current_page, pages, max_page, url_prefix #} 2 | 19 | -------------------------------------------------------------------------------- /kube/redis.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: redis 5 | spec: 6 | ports: 7 | - port: 6379 8 | name: redis 9 | clusterIP: None 10 | selector: 11 | app: redis 12 | --- 13 | apiVersion: apps/v1 14 | kind: StatefulSet 15 | metadata: 16 | name: redis 17 | spec: 18 | selector: 19 | matchLabels: 20 | app: redis # has to match .spec.template.metadata.labels 21 | serviceName: redis 22 | replicas: 1 23 | template: 24 | metadata: 25 | labels: 26 | app: redis # has to match .spec.selector.matchLabels 27 | spec: 28 | containers: 29 | - name: redis 30 | image: redis:3.2-alpine 31 | ports: 32 | - containerPort: 6379 33 | name: redis 34 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/templates/explorer/_events-table.html: -------------------------------------------------------------------------------- 1 | {# Required variables: events #} 2 | {% load hsd_math %} 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {% for event in events %} 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | {% endfor %} 23 | 24 |
BlockActionNameValueTX
{{ event.block_id }}{{ event.action | lower }}{{ event.name.name }}{{ event.value | to_hns }}{% if event.value is not None %} HNS{% endif %}TX
25 | -------------------------------------------------------------------------------- /hsdexplorer/explorer/templates/explorer/index.html: -------------------------------------------------------------------------------- 1 | {% extends "explorer/base.html" %} 2 | {% block title %}Handshake Explorer: Home{% endblock %} 3 | {% block content %} 4 |