# Como Executar um Nó Catalyst

Já sentiu curiosidade sobre como funcionam os nós Catalyst do Decentraland? Já quis executar seu próprio nó e se sentiu sobrecarregado sem saber por onde começar? Está criando conteúdo para o Decentraland e acha difícil realizar todo o ciclo de desenvolvimento e testes em servidores de produção?

Se você está (ou já esteve) nessa situação, não tema mais. Este tutorial ajudará no processo de planejamento, explicará o que você precisa decidir e então o guiará passo a passo na inicialização do servidor. Além disso, caso algo não saia conforme o planejado, há uma seção de solução de problemas no final com alguns dos problemas mais comuns e como corrigi-los.

Pronto? Mãos à obra.

### Requisitos de hardware

Os servidores da Decentraland Foundation são implantados na Amazon AWS em `t2.xlarge` instâncias. Portanto, enquanto esses servidores são destinados ao uso público, o seu próprio pode funcionar com especificações bem menores, dependendo do uso pretendido.

Uma AWS EC2 `t2.xlarge` possui o seguinte hardware:

* 4 vCPUs.
* 16 Gb de RAM

E para armazenamento de arquivos + armazenamento de DB, um SSD / HDD com 2 Tb de capacidade deve ser mais que suficiente. No momento desta escrita, os servidores da fundação estão usando um pouco mais de 1 Tb para todo o armazenamento.

### Pré-requisitos de software

O seguinte é necessário para executar o catalyst-owner:

* Sistema operacional Linux / MacOS
* Docker / docker-compose
* Git
* LiveKit Cluster

### Algumas opções a considerar antes de começarmos

* Você quer que seu nó seja exposto publicamente na Internet? Se sim, você precisará de uma instância exposta à internet e de uma URL pública para se conectar a ela.
* O nó será usado para o desenvolvimento de cenas, wearables, etc.? Nesse caso, as especificações de hardware podem ser bem menores, pois provavelmente será acessado por uma ou duas pessoas, não por centenas de usuários.
* Você quer sincronizar todos os tipos de entidade? Se estiver usando isso para desenvolver cenas, provavelmente você vai querer pular a sincronização de profiles, pois eles consomem muito tempo, largura de banda e, mais importante, espaço em disco, e não te trarão benefício para esse objetivo.

### LiveKit

Um cluster LiveKit externo é necessário pelo serviço Comms do Catalyst para orquestrar as comunicações entre jogadores. Para isso, há duas opções: usar uma conta LiveKit Cloud ou executar seu próprio cluster LiveKit.

A recomendação é configurar [Livekit Cloud account](https://cloud.livekit.io/) que vem com um nível gratuito que pode gerenciar 100 usuários, ou pagar pelo serviço conforme o tráfego. Essa abordagem é mais fácil, pois não exige provisionar infraestrutura extra e o serviço pode gerenciar o escalonamento. Caso contrário, será necessário provisionar um cluster LiveKit. LiveKit faz um ótimo trabalho com a documentação deles:

* [Implantação](https://docs.livekit.io/oss/deployment/)
* [Configuração Distribuída](https://docs.livekit.io/oss/deployment/distributed/)

*Caso queira se aprofundar nos detalhes técnicos necessários para suportar comunicações baseadas em transporte LiveKit, confira o* [*ADR-70 New Communications Architecture*](https://adr.decentraland.org/adr/ADR-70)*.*

### Guia passo a passo

A primeira coisa a fazer é clonar o [catalyst-owner](https://github.com/decentraland/catalyst-owner) repositório do GitHub

```bash
> git clone https://github.com/decentraland/catalyst-owner.git
Cloning into 'catalyst-owner'...
remote: Enumerating objects: 2392, done.
remote: Counting objects: 100% (602/602), done.
remote: Compressing objects: 100% (168/168), done.
remote: Total 2392 (delta 506), reused 481 (delta 430), pack-reused 1790
Receiving objects: 100% (2392/2392), 926.05 KiB | 1.09 MiB/s, done.
Resolving deltas: 100% (1257/1257), done.
> cd catalyst-owner
```

Uma vez feito isso, é hora de configurar as variáveis de ambiente para o nó e fazer quaisquer alterações conforme apropriado.

```bash
# Na pasta /catalyst-owner
> cp .env.example .env
> cp .env-advanced.example .env-advanced
```

Agora, usando seu editor de texto favorito, faça as alterações necessárias nesses arquivos. Por exemplo, configurar o `EMAIL` variável de ambiente com um email válido é obrigatório para que você possa receber atualizações sobre expiração de certificados do Certbot.

Também pode ser necessário configurar seu valor particular para `CATALYST_URL` especialmente se o seu servidor for exposto publicamente na Internet. Para uso em sua máquina local, o padrão de `http://localhost` servirá.

**Serviço Comms**

Uma vez que o cluster LiveKit esteja disponível, você precisará definir as variáveis específicas do LiveKit para o serviço Comms funcionar, por exemplo:

```
LIVEKIT_HOST=wss://livekit-1.mydomain.org
LIVEKIT_API_KEY=API-JjHuvM
LIVEKIT_API_SECRET=J7YSHmNzkNCEfT2
ROOM_PREFIX=my-prefix
```

O `ROOM_PREFIX` variável é opcional e pode ser configurada para identificar salas LiveKit criadas pelo Catalyst. Isso é útil se mais de um Catalyst estiver usando o mesmo LiveKit Cluster.

**Content Server**

Há uma variável chamada `CONTENT_SERVER_STORAGE` que define a pasta local que o content server usará para armazenamento. O padrão é `CONTENT_SERVER_STORAGE=./storage`. Você pode alterar esse valor para armazenar arquivos em outro lugar, ou pelo menos certificar-se de que a pasta referenciada exista. Pode ser necessário criá-la assim:

```bash
# Na pasta /catalyst-owner ou onde quer que CONTENT_SERVER_STORAGE esteja apontando
> mkdir storage
```

Há outra variável interessante `SYNC_IGNORED_ENTITY_TYPES` que permite ignorar certos tipos de entidade durante o processo de sincronização. Se você for usar o servidor Catalyst para desenvolvimento, talvez não precise que todos os tipos de conteúdo sejam sincronizados. Você pode definir a var env `SYNC_IGNORED_ENTITY_TYPES="profile,store"` para que apenas scenes e wearables sejam trazidos dos servidores DAO. Isso economizará muito tempo, largura de banda e espaço em disco no seu servidor.

> 💡 Para uma lista mais exaustiva de variáveis de ambiente suportadas, consulte o [Environment variables](#environment-variables) seção abaixo.

#### Iniciar o nó Catalyst

Depois que todas as variáveis de ambiente forem configuradas, é hora de iniciar o nó. Isso deve ser tão simples quanto executar o `init.sh` script na pasta raiz.

```bash
# Na pasta /catalyst-owner

> ./init.sh
## Loading env variables... [ OK ]
[ OK ]
## Checking if email is configured... [ OK ]
## Checking if storage is configured... [ OK ]
## Checking if catalyst url is configured... [ OK ]
 AVISO: Você não está executando a imagem mais recente dos Nodes Content e Lambdas do Catalyst.
 AVISO: Você não está executando a imagem mais recente do Archipelago Node do Catalyst.
 AVISO: Você não está executando a imagem mais recente do Explorer BFF Node do Catalyst.
 - DOCKER_TAG:               45a5154f11b53d55aadfdf7f958e2fce6a964824
 - LIGHTHOUSE_DOCKER_TAG:    latest
 - CATALYST_URL:             http://localhost
 - CONTENT_SERVER_STORAGE:   ./storage
 - EMAIL:                    a@a.com
 - ETH_NETWORK:              mainnet
 - REGENERATE:               0

Iniciando em 5 segundos...
45a5154f11b53d55aadfdf7f958e2fce6a964824: Pulling from decentraland/catalyst-content
Digest: sha256:d6c2981c57cb9367fdb3228d15b07e4d26e62c902944115937de24ecd3ab6aac
Status: Image is up to date for decentraland/catalyst-content:45a5154f11b53d55aadfdf7f958e2fce6a964824
docker.io/decentraland/catalyst-content:45a5154f11b53d55aadfdf7f958e2fce6a964824
45a5154f11b53d55aadfdf7f958e2fce6a964824: Pulling from decentraland/catalyst-lambdas
Digest: sha256:5605812dd29316afc32e561d2a2ce1311f164f07ef3cd99a1cd60727518636e5
Status: Image is up to date for decentraland/catalyst-lambdas:45a5154f11b53d55aadfdf7f958e2fce6a964824
docker.io/decentraland/catalyst-lambdas:45a5154f11b53d55aadfdf7f958e2fce6a964824
latest: Pulling from decentraland/catalyst-lighthouse
Digest: sha256:fedc10b714823909f0a1c17955eed2f22a02e4f784090848d3253ef734e410d4
Status: Image is up to date for decentraland/catalyst-lighthouse:latest
docker.io/decentraland/catalyst-lighthouse:latest
latest: Pulling from decentraland/archipelago-service
Digest: sha256:e2c1d6fa96a5cfbbf6fb37e3840c0724fb5abeef8c366025a28fab3ad33d6480
Status: Image is up to date for quay.io/decentraland/archipelago-service:latest
quay.io/decentraland/archipelago-service:latest
latest: Pulling from decentraland/explorer-bff
Digest: sha256:fa9e305c44972a8613b01f4cd573d6fb84b0fb03ce953a506fbb06053202913c
Status: Image is up to date for quay.io/decentraland/explorer-bff:latest
quay.io/decentraland/explorer-bff:latest
Stopping nginx ... done
## Using HTTP because CATALYST_URL is set to http://localhost
## Replacing value $katalyst_host on nginx server file... [ OK ]
## Restarting containers...
Creating network "catalyst-owner_default" with the default driver
Creating catalyst-owner_comms-server_1 ... done
Creating node-exporter                   ... done
Creating catalyst-owner_lambdas_1      ... done
Creating postgres                      ... done
Creating catalyst-owner_certbot_1        ... done
Creating nats                            ... done
Creating postgres-exporter               ... done
Creating catalyst-owner_content-server_1 ... done
Creating catalyst-owner_archipelago_1    ... done
Creating catalyst-owner_explorer-bff_1   ... done
Creating nats-exporter                   ... done
Creating cadvisor                        ... done
Creating nginx                           ... done
## O servidor Catalyst está ativo e funcionando em http://localhost
```

Se tudo correu bem, agora temos um nó Decentraland completo em execução. Você pode abrir o navegador e digitar a URL. Se estiver usando o padrão, deve ser [`http://localhost`](http://localhost/).

Podemos verificar os logs do content server com este comando docker:

```bash
> docker logs catalyst-owner_content-server_1
```

Mesmo que o servidor agora esteja em execução, ele não está 100% pronto para entrar em operação. Ele precisa sincronizar o conteúdo a partir dos outros [servers of the DAO](https://decentraland.github.io/catalyst-monitor) para que possa oferecer a mesma experiência aos usuários conectados a ele. A sincronização pode levar muito tempo. Em uma boa conexão com a internet, 6 horas devem ser bastante comuns. Então... é hora de tomar um café, tirar uma soneca, dormir bem e voltar amanhã.

Uma forma de saber se a sincronização está completa consiste em verificar os resultados do endpoint de status do content: <http://localhost/content/status> (use sua URL aqui).

```json
{
  "synchronizationStatus": {
    "lastSyncWithDAO": 1658153514917,
    "synchronizationState": "Bootstrapping"
  },
  "snapshot": {
    "entities": {
      "profile": 1271331,
      "scene": 23477,
      "wearable": 17351,
      "store": 890
    },
    "lastUpdatedTime": 1658153414530
  },
  "version": "v3",
  "commitHash": "9a2e0d5d05d02646df2e1e5d00436d3166a07aa1",
  "catalystVersion": "4.8.6",
  "ethNetwork": "mainnet"
}
```

Enquanto `synchronizationState` estiver `Bootstrapping`, o nó suspenderá temporariamente a aceitação de novos deployments. Essa medida garante que nenhuma nova entidade seja implantada até que o nó esteja atualizado dentro da rede DAO. Uma vez que o status mude para `Syncing`, isso indica que o nó conseguiu se atualizar e agora está recebendo continuamente as últimas atualizações. Esse é o estado saudável em que o nó está totalmente funcionando e aceitando novos deployments.

```json
{
  "synchronizationStatus": {
    "lastSyncWithDAO": 1658153872301,
    "synchronizationState": "Syncing"
  },
  "snapshot": {
    "entities": {
      "profile": 1271317,
      "scene": 23477,
      "store": 890,
      "wearable": 17350
    },
    "lastUpdatedTime": 1658152050030
  },
  "version": "v3",
  "commitHash": "9a2e0d5d05d02646df2e1e5d00436d3166a07aa1",
  "catalystVersion": "4.8.6",
  "ethNetwork": "mainnet"
}
```

Se você for mais do tipo linha de comando, pode procurar nos logs da imagem docker do content server por esta mensagem: `Starting to sync entities from servers pointer changes`. Quando você vir esse texto, o content server estará totalmente sincronizado e pronto para uso completo.

### Environment variables

A seguir está uma lista abrangente de todas as variáveis de ambiente do content server com seus valores padrão, conforme registrado nos logs do content server durante a inicialização:

```jsx
STORAGE_ROOT_FOLDER: "/app/storage/content_server/"
DENYLIST_FILE_NAME: "denylist.txt"
DENYLIST_URLS: "https://config.decentraland.org/denylist"
SYNC_IGNORED_ENTITY_TYPES: ""
FOLDER_MIGRATION_MAX_CONCURRENCY: 1000
SERVER_PORT: 6969
LOG_REQUESTS: false
UPDATE_FROM_DAO_INTERVAL: 1800000
SYNC_WITH_SERVERS_INTERVAL: 45000
CHECK_SYNC_RANGE: 1200000
DECENTRALAND_ADDRESS: "0x1337e0507eb4ab47e08a179573ed4533d9e22a7b"
DEPLOYMENTS_DEFAULT_RATE_LIMIT_TTL: 60
DEPLOYMENTS_DEFAULT_RATE_LIMIT_MAX: 300
ETH_NETWORK: "mainnet"
LOG_LEVEL: "debug"
FETCH_REQUEST_TIMEOUT: "2m"
USE_COMPRESSION_MIDDLEWARE: false
BOOTSTRAP_FROM_SCRATCH: false
REQUEST_TTL_BACKWARDS: 1200000
LAND_MANAGER_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/land-manager"
COLLECTIONS_L1_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/collections-ethereum-mainnet"
COLLECTIONS_L2_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/collections-matic-mainnet"
THIRD_PARTY_REGISTRY_L2_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/tpr-matic-mainnet"
BLOCKS_L1_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/blocks-ethereum-mainnet"
BLOCKS_L2_SUBGRAPH_URL: "https://api.thegraph.com/subgraphs/name/decentraland/blocks-matic-mainnet"
PSQL_DATABASE: "content"
PSQL_HOST: "postgres"
PSQL_SCHEMA: "public"
PSQL_PORT: "5432"
GARBAGE_COLLECTION: true
GARBAGE_COLLECTION_INTERVAL: 21600000
PG_IDLE_TIMEOUT: 30000
PG_QUERY_TIMEOUT: 60000
PG_STREAM_QUERY_TIMEOUT: 600000
SNAPSHOT_FREQUENCY_IN_MILLISECONDS: 21600000
CUSTOM_DAO: undefined
DISABLE_SYNCHRONIZATION: false
SYNC_STREAM_TIMEOUT: "10m"
CONTENT_SERVER_ADDRESS: "http://localhost/content/"
REPOSITORY_QUEUE_MAX_CONCURRENCY: 50
REPOSITORY_QUEUE_MAX_QUEUED: 300
REPOSITORY_QUEUE_TIMEOUT: "1m"
ENTITIES_CACHE_SIZE: 150000
DEPLOYMENT_RATE_LIMIT_MAX: {}
DEPLOYMENT_RATE_LIMIT_TTL: {}
VALIDATE_API: false
RETRY_FAILED_DEPLOYMENTS_DELAY_TIME: 900000
```

### Usando seu nó para produção

Se você quiser executar seu próprio servidor e ajudar a escalar a rede, antes de tudo isso é incrível, a comunidade e a fundação realmente apreciam você fazê-lo.

Nesse caso, você terá que passar pelo processo de solicitar aprovação ao DAO para ingressar na rede visitando [this link](https://governance.decentraland.org/submit/catalyst/). Você também pode solicitar uma doação de MANA para cobrir as despesas de infraestrutura e gerenciamento.

É importante que as especificações do seu hardware estejam mais alinhadas com o que foi sugerido acima nos requisitos de hardware, pois o servidor será usado por qualquer membro da comunidade para entrar no Decentraland.

### Especificações da API

Para mais detalhes sobre as APIs para content, lambdas e comms servers você pode consultar o [API specs](https://decentraland.github.io/catalyst-api-specs).

### Solução de problemas/FAQ

Algumas coisas podem dar errado ao iniciar seu servidor. Aqui estão alguns dos problemas mais comuns encontrados ao longo do tempo e como corrigi-los.

#### A porta 5432 está sendo usada pelo postgres local

Se você executar o nó em uma máquina usada para desenvolvimento, ou se ela já estiver hospedando outros serviços, há grande chance de já existir um servidor de banco de dados postgres em execução nessa máquina. Então a porta 5432 já estará ocupada.

A maneira mais fácil de resolver isso é parar o postgres que já está rodando localmente e então reiniciar o container postgres do docker usando `docker start postgres`.

Se você tem conhecimento em docker compose, pode começar a mexer em `docker-compose.yml` e variáveis de ambiente para tentar fazê-lo funcionar em uma porta diferente. Para manter as coisas simples aqui, vamos evitar esse caminho neste tutorial.

#### A porta 80 está sendo usada pelo nginx local

A mesma coisa pode acontecer com a porta 80 (e até com a porta 443). Se você estiver executando o nginx na máquina local, há grande chance de que as portas 80/443 já estejam vinculadas a esse serviço, então o container Docker do Catalyst não poderá usá-las.

Novamente, a abordagem mais simples seria parar o serviço nginx local e então reiniciar o container docker usando `docker start nginx`. Ou, alternativamente, você precisa usar `docker-compose.yml` e `.env` para fazê-lo funcionar em uma porta diferente.

### Documentos adicionais para referência

Se você quer entender melhor o que um servidor Catalyst faz, quais serviços ele inclui, etc., você pode consultar o repositório architecture <https://github.com/decentraland/architecture> que explica as partes em detalhe.

Se você gostaria de contribuir com o código dos servidores Catalyst, certifique-se de verificar o [contributing guide](https://github.com/decentraland/catalyst/blob/main/docs/CONTRIBUTING.md) para aprender sobre nosso processo de desenvolvimento, como propor correções de bugs e melhorias, e como construir e testar suas alterações.

E finalmente, se você precisar contatar a equipe, pode fazê-lo via [Discord](https://discord.com/channels/417796904760639509/948230185457696820) ou submetendo [GitHub issues](https://github.com/decentraland/catalyst/issues).
