Skip to content

Service to resolve unstoppable domains, including TYRON.

License

Notifications You must be signed in to change notification settings

tyrondao/resolution-service

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Resolution service

Tests Security Rating Known Vulnerabilities Coverage Unstoppable Domains Documentation Get help on Discord

Resolution service provides an API for getting domain data and metadata regardless of that domain's location (whether it is stored in Ethereum, Zilliqa, or any other blockchain). The service is used to cache blockchain events in a database for easy retrieval without acessing blockchain APIs.

The resolution service is provided as a docker image so it can be launched on a variety of platforms and in the cloud.

Resolution service endpoints

Installation

Pre-requirements

  • git - to clone the repository.
  • docker - to run the service. Install docker by following instructions for an appropriate system.
  • postgres - to store the data. Postgres can be configured on the same server as the resolution service or on a dedicated database hosting (e.g. AWS RDS, Google Cloud SQL). To install postgres locally, follow these instructions. Make sure to configure password authentication for the DB user that will be used by the service.
    • This guide has been tested with Postgres 11.17, although other versions may work as well.

Quick start

  1. Clone the resolution-service repository
    git clone https://github.com/unstoppabledomains/resolution-service.git
  2. Build the docker container
    docker build -t resolution-service .
  3. Setup environment variables
    Create a file service.env that will contain required environment variables:
NODE_ENV=production
RESOLUTION_POSTGRES_HOST=example.com          	# DB host
RESOLUTION_POSTGRES_PORT=5432                   # DB port
RESOLUTION_POSTGRES_USERNAME=example           	# DB user configured in postgres
RESOLUTION_POSTGRES_PASSWORD=password          	# DB password configured in postgres
RESOLUTION_POSTGRES_DATABASE=resolution_service # Name of the resolution service database
ETHEREUM_JSON_RPC_API_URL=https://alchemy.com  	# Address of a JSON RPC provider. This can be a public API (e.g. Alchemy), or a local ethereum node with JSON RPC enabled
POLYGON_JSON_RPC_API_URL=https://alchemy.com   	# Address of a JSON RPC provider. This can be a public API (e.g. Alchemy), or a local ethereum node with JSON RPC enabled
VIEWBLOCK_API_KEY=apikey                       	# key for Viewblock API, required for getting data from Zilliqa blockchain
METADATA_API=apikey				                      # key for Unstoppable Domain's Metadata API
MORALIS_API_URL=apikey				                  # URL for the Moralis API
MORALIS_APP_ID=apikey				                    # App ID for the Moralis API
OPENSEA_API_KEY=apikey				                  # key for Opensea's API service

This is the minimum required set of configurations for the service. Additional configuration options are listed in Environment configuration options.

  1. Create the resolution_service postgres database createdb resolution_service
  2. Launch the service docker run -d --env-file service.env -p 3000:3000 --network="host" resolution-service

Running the service

Once the service is started, it will perform initial synchronization with the blockchain networks. It may take more than 24 hours for a full synchronization. During the initial synchronization the API may not work reliably. The status of synchronization can be checked using the /status endpoint. After the synchronization is complete, the service API endpoints can be accessed normally. Note that the service is stateless, so the container doesn't need any persistent storage. All data is stored in the database.

Environment configuration options

Option Default value required Description
RESOLUTION_API_PORT 3000 The port for the HTTP API.
RESOLUTION_RUNNING_MODE API,ETH_WORKER,MATIC_WORKER,ZIL_WORKER,MIGRATIONS Comma-separated list of running modes of the resolution service (see Running modes).
RESOLUTION_POSTGRES_HOST localhost ✔️ Host for the postgres DB. Note that to connect to a postgres instance running on the same server as the container, host.docker.internal should be used instead of localhost on Windows and MacOS (see https://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds).
RESOLUTION_POSTGRES_USERNAME postgres ✔️ Username that is used to connect to postgres.
RESOLUTION_POSTGRES_PASSWORD secret ✔️ Password that is used to connect to postgres.
RESOLUTION_POSTGRES_DATABASE resolution_service ✔️ Database name in postgres.
RESOLUTION_POSTGRES_PORT 5432 Port number for Postgres database.
ETHEREUM_CONFIRMATION_BLOCKS 20 Number of blocks that the service will wait before accepting an event from the CNS contract. This helps to avoid block reorgs, forks, etc.
ETHEREUM_BLOCK_FETCH_LIMIT 500 Batch limit for fetching event data from the Ethereum JSON RPC. Note that some API providers may limit the amount of data that can be returned in a single request. So this number should be kept relatively low. However, raising this limit should speed up synchronization if a dedicated node is used with the service.
ETHEREUM_RECORDS_PER_PAGE 100 Batch limit for fetching domain records from CNS registry smart contract.
ETHEREUM_FETCH_INTERVAL 5000 Specifies the interval to fetch data from the CNS registry in milliseconds.
CNS_REGISTRY_EVENTS_STARTING_BLOCK 9080000 Starting block that is used to look for events in the CNS registry. This helps to avoid parsing old blockchain data, before the contract was even deployed.
CNS_RESOLVER_ADVANCED_EVENTS_STARTING_BLOCK 9080000 Starting block that is used to look for events in the CNS registry.
ETHEREUM_ACCEPTABLE_DELAY_IN_BLOCKS 100 How much blocks Ethereum mirror can lag behind until it's considered as unacceptable and need to be fixed. /status endpoint will return health: true/false field depends on number of blocks behind compared with this number.
ETHEREUM_JSON_RPC_API_URL - ✔️ Address of a JSON RPC provider. This can be a public API (e.g. Alchemy), or a local ethereum node with JSON RPC enabled.
ETHEREUM_NETWORK_ID 1 ID of the Ethereum network that is used by the service.
POLYGON_CONFIRMATION_BLOCKS 20 Number of blocks that the service will wait before accepting an event from the smart contracts on Polygon. This helps to avoid block reorgs, forks, etc.
POLYGON_BLOCK_FETCH_LIMIT 500 Batch limit for fetching event data from the Polygon JSON RPC. Note that some API providers may limit the amount of data that can be returned in a single request. So this number should be kept relatively low. However, raising this limit should speed up synchronization if a dedicated node is used with the service.
POLYGON_RECORDS_PER_PAGE 100 Batch limit for fetching domain records from Polygon smart contracts.
POLYGON_FETCH_INTERVAL 5000 Specifies the interval to fetch data from the Polygon blockchain in milliseconds.
POLYGON_UNS_REGISTRY_EVENTS_STARTING_BLOCK 19345077 Starting block that is used to look for events in the UNS registry on the Polygon blockchain. This helps to avoid parsing old blockchain data, before the contract was even deployed.
POLYGON_ACCEPTABLE_DELAY_IN_BLOCKS 100 How much blocks Polygon mirror can lag behind until it's considered as unacceptable and need to be fixed. /status endpoint will return health: true/false field depends on number of blocks behind compared with this number.
POLYGON_JSON_RPC_API_URL - ✔️ Address of a Polygon JSON RPC provider. This can be a public API (e.g. Alchemy), or a local ethereum node with JSON RPC enabled.
POLYGON_NETWORK_ID 137 ID of the Polygon network that is used by the service.
ZNS_NETWORK mainnet Name of the Zilliqa network will be used by ZNS worker (mainnet or testnet).
VIEWBLOCK_API_KEY - ✔️ API key for viewblock, required by ZNS worker.
ZNS_FETCH_INTERVAL 5000 Specifies the interval to fetch data from the ZNS registry in milliseconds.
NEW_RELIC_LICENSE_KEY - License key that will be used to access newrelic. If the key is not specified, new relic will not be enabled.
NEW_RELIC_APP_NAME - App name will be used to access newrelic. If the app name is not specified, new relic will not be enabled.
BUGSNAG_API_KEY - API key that will be used to access bugsnag. If the key is not specified, bugsnag will not be enabled.
TYPEORM_LOGGING_COLORIZE true Colorize typeorm logs.
ZILLIQA_ACCEPTABLE_DELAY_IN_BLOCKS 100 How much blocks Zilliqa mirror can lag behind until it's considered as unacceptable and need to be fixed. /status endpoint will return health: true/false field depends on number of blocks behind compared with this number.
MORALIS_API_URL - URL for the Moralis API. Required by the metadata API endpoints (METADATA_API running mode).
MORALIS_APP_ID - App ID for the Moralis API. Required by the metadata API endpoints (METADATA_API running mode).

Running modes

The service provides several running modes. By default it will run all of them. However, the modes that will be used can be selected during startup using the RESOLUTION_RUNNING_MODE environment variable. Available running modes:

  • API - Runs all APIs
  • SERVICE_API - Runs the service API (see "Service endpoints" in API reference)
  • METADATA_API - Runs the metadata API (see "Metadata endpoints" in API reference)
  • ETH_WORKER - Runs the ETH worker to sync data from the Ethereum CNS and UNS registry
  • MATIC_WORKER - Runs the MATIC worker to sync data from the Polygon UNS registry
  • ZIL_WORKER - Runs the ZIL worker to sync data from the Zilliqa ZNS registry
  • MIGRATIONS - Runs the migration scripts if necessary.

For example, to run only the API with the ETH_WORKER, the following environment configuration can be used:

RESOLUTION_RUNNING_MODE=API,ETH_WORKER

API keys

The /domains API requires an API key which is simply a version 4 UUID. Currently there are no key management functions in the resolution service. All API keys must be added manually using the database. To generate a random API key run the following query in postgres:

 INSERT INTO api_keys (name, api_key) VALUES ('my API key', md5(clock_timestamp()::text)::uuid);

Note: The above example should not be used for production API keys as the key which is based on a predictable value. Production keys should be generated externally.

API reference

The full api reference OpenAPI specification By default all API endpoints are enabled. Use the RUNNING_MODE env variable to enable specific sets of endpoints.

Endpoint Description
Service endpoints:
GET /domains Gets the list of domains.
GET /domains/:domainName Gets the resolution of the specified domain.
GET /records Gets resolution records for multiple domains requested.
- domains: required query parameter, accepts an array of UD domains.
- key: optional query parameter, reflects what resolution record to retrieve across the requested domains.
Example: /records?domains[]=ryan.crypto&domains[]=mvwi.crypto&key=social.picture.value
GET /status Gets the synchronization status.
GET /api-docs Returns a swagger documentation page.
Metadata endpoints:
GET /metadata/:domainOrToken Retrieve erc721 metadata information of the specified domain
GET /image/:domainOrToken Retrieve image_data as a svg string
GET /image-src/:domainOrToken Retrieve image_data as 'image/svg+xml'

Note: The /domains and /records endpoints require an API key. The key must be provided as Bearer authentication header for requests. New keys must be added manually to the database (see API keys for more info).

Development notes

Development pre-requirements

The dev. environment has generally the same pre-requirements as running the service normally. So, postgres and docker are also necessary. For convenience postgres configuration can be the same as defaults (username - postgres, password - secret).

Additional pre-requirements that are necessary for development:

  • Node.JS 14.16.1 Can be installed using NVM
  • yarn

Running in dev. mode

  1. Install project dependencies
nvm install 14.16.1
nvm use 14.16.1
yarn install
  1. Configure environment variables.
    The required variables are the same as running the service in docker. Copy ./local.dev.env.sample to ./local.dev.env and set variables as necessary.
RESOLUTION_POSTGRES_HOST=localhost
RESOLUTION_POSTGRES_USERNAME=postgres
RESOLUTION_POSTGRES_PASSWORD=password
RESOLUTION_POSTGRES_DATABASE=resolution_service
ETHEREUM_JSON_RPC_API_URL=localhost:8545
POLYGON_JSON_RPC_API_URL=localhost:8546
VIEWBLOCK_API_KEY=apikey
METADATA_API=apikey
MORALIS_API_URL=apikey
MORALIS_APP_ID=apikey
OPENSEA_API_KEY=apikey
  1. Run the service
yarn start:dev

Running unit tests

Unit tests can be run using yarn test. This command will run the tests with ENV variables set in ./local.test.env file. You should copy ./local.test.env.sample to ./local.test.env and redefine any env variable in yours local environment if needed, for example: export RESOLUTION_POSTGRES_PASSWORD=password. Testing command will take this variable first instead of using variable from ./local.test.env file.

For checking coverage use yarn test:coverage.

Unit/integration tests use a postgres database that is cleaned before each test. By default, the database name is resolution_service_test.

Debugging

To debug the service the following command could be used:

yarn start:dev:debug

To debug the tests use:

yarn test:debug

If you are using Visual Studio Code to debug the code add this to .vscode/launch.json launch configuration:

  "configurations": [
    ...,
    {
      "type": "node",
      "request": "attach",
      "name": "Attach to resolution service",
      "protocol": "inspector",
      "port": 9229,
      "restart": true,
      "localRoot": "${workspaceFolder}",
      "remoteRoot": "${workspaceFolder}"
    },

Service architecture

Architecture chart

The service currently consists of three main components: API, and three workers. The API component is a basic HTTP API that allows reading domain data from the database. The OpenAPI specification: OpenAPI specification.

Currently there are three workers in the resolution service:

  • ETH worker
    Contains a scheduled job that connects to the Ethereum blockchain using JSON RPC and pulls CNS (.crypto) and UNS domains and resolution events. The events are parsed and saved to the database.
  • MATIC worker
    Contains a scheduled job that connects to the Polygon blockchain using JSON RPC and pulls domains and resolution events. The events are parsed and saved to the database.
    Since Polygon and Ethereum are compatible, we use two instances of the same worker implementation to pull data from these networks.
  • ZIL worker
    Contains a scheduled job that connects to the Zilliqa blockchain using and pulls ZNS (.zil) domains and resolution events. The events are parsed and saved to the database.

More workers may be added in the future.

Logs and monitoring

The resolution service outputs logs to stdout so they are available by docker logs and can be monitored by cloud tools (e.g. AWS CloudWatch or Google Cloud Logging). The general log format should be: <timestamp> <log level>: <Component label> - <Log message>

The resolution service has a configurable logging level. Log messages are at consistent levels across the whole service. We use the following guidelines to determine logging level:

Event Component description log level
Startup info all Log any startup information (e.g. worker is starting, API is listening) info
Sync progress Workers Log current sync progress of a worker (which blocks are being processed, how many blocks are left to process) info
Handled errors all Log any errors that can be handled gracefully (e.g. a malformed request that will return a 400 error) warn
Unhandled errors all Log any errors that were captured by top-level error handlers (e.g. an unexpected third-party API error, invalid db state) error
API Request API controllers Log any request to the API with their parameters debug
DB query all Log any db queries with their parameters debug
Parsed event Workers Log any event or transaction parsed by the worker debug
External API calls all Log external API calls debug

Additionally, if the appropriate keys are provided in the environment configuration, the service will report errors to monitoring tools. The resolution service has integrations with bugsnag and newrelic.

Adding new env vars

  1. Add it to Github repository Secrets (https://github.com/unstoppabledomains/resolution-service/settings/secrets/actions)
  2. Add it to such files: env.ts, deploy-production.yml, deploy-staging.yml, tests.yml, create-yaml.sh

Testing image uploads locally

Metadata service will cache NFT PFP images, uploading them to Google Cloud Storage (GCS) CDN. To test file uploads localy, unofficial GCS emulator is used.

To use the emulator make sure docker is installed.

Pull the image from Docker Hub

docker pull fsouza/fake-gcs-server

Create the following directory structure for the GSC bucket storage, where resolution-client-assets is the name of the bucket.

  storage
  |--> resolution-client-assets

Run docker container with mounted bucket directory:

docker run -d --name fake-gcs-server -p 4443:4443 -v ${PWD}/storage:/data fsouza/fake-gcs-server -scheme http -public-host localhost:4443

Add the following variable to local dev config:

CLOUD_STORAGE_ENDPONT_URL=http://localhost:4443

About

Service to resolve unstoppable domains, including TYRON.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 98.7%
  • Other 1.3%