Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,18 @@ make install
```shell
GITHUB_USERNAME=rollchains

# Available Features:
# * tokenfactory,globalfee,ibc-packetforward,ibc-ratelimit,cosmwasm,wasm-light-client,optimistic-execution,ignite-cli,block-explorer

spawn new rollchain \
--consensus=proof-of-authority `# proof-of-authority,proof-of-stake,interchain-security` \
--bech32=roll `# the prefix for addresses` \
--denom=uroll `# the coin denomination to create` \
--bin=rolld `# the name of the binary` \
--disabled=cosmwasm,globalfee `# disable features. [tokenfactory,globalfee,ibc-packetforward,ibc-ratelimit,cosmwasm,wasm-light-client,ignite-cli]` \
--disabled=cosmwasm,globalfee,block-explorer `# disable features.` \
--org=${GITHUB_USERNAME} `# the github username or organization to use for the module imports, optional`


```

> *NOTE:* `spawn` creates a ready to use repository complete with `git` and GitHub CI. It can be quickly pushed to a new repository getting you and your team up and running quickly.
Expand Down
1 change: 1 addition & 0 deletions cmd/spawn/new_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ var (
{ID: "wasm-light-client", IsSelected: false, Details: "08 Wasm Light Client"},
{ID: "optimistic-execution", IsSelected: false, Details: "Pre-process blocks ahead of consensus request"},
{ID: "ignite-cli", IsSelected: false, Details: "Ignite-CLI Support"},
{ID: "block-explorer", IsSelected: true, Details: "Ping Pub Explorer"},
}...)

// parentDeps is a list of modules that are disabled if a parent module is disabled.
Expand Down
4 changes: 4 additions & 0 deletions simapp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,10 @@ sh-testnet: mod-tidy
### help ###
###############################################################################

.PHONY: explorer
explorer:
docker compose up

help:
@echo "Usage: make <target>"
@echo ""
Expand Down
6 changes: 5 additions & 1 deletion simapp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@
## Testing

- `go test ./... -v` *Unit test*
- `make ictest-*` *E2E testing*
- `make ictest-*` *E2E testing*

## Launch Block Explorer Locally

[Reference Guide](./nginx/README.md)
38 changes: 38 additions & 0 deletions simapp/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
version: '3'

# Runs the explorer & reverse proxy
#
# NOTE: Must add the following to your /etc/hosts file:
#
# 127.0.0.1 api.localhost
# 127.0.0.1 rpc.localhost
# 127.0.0.1:5173 pingpub.localhost
#
# Then:
# docker compose up

services:
nginx:
image: nginx
network_mode: "host"
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf
- ./nginx/nginx-selfsigned.crt:/etc/nginx/nginx-selfsigned.crt
- ./nginx/nginx-selfsigned.key:/etc/nginx/nginx-selfsigned.key
pingpub:
depends_on:
- nginx
image: pingpub:latest
network_mode: "host"
build:
context: pingpub
dockerfile: ./explorer/Dockerfile

volumes:
- ./explorer/chains:/app/chains/
ports:
- "80:80"
- "443:443"
2 changes: 1 addition & 1 deletion simapp/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (

// !IMPORTANT: interchaintest/ has its own `InterchainTest` embed.FS that will need to be iterated on.

//go:embed .github/* app/* chains/* cmd/* contrib/* scripts/* Makefile Dockerfile proto/*.* *.*
//go:embed .github/* app/* chains/* cmd/* contrib/* scripts/* Makefile Dockerfile nginx/* proto/*.* *.*
var SimAppFS embed.FS

// To embed the interchaintest/ directory, rename the go.mod file to `go.mod_`
Expand Down
22 changes: 22 additions & 0 deletions simapp/nginx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Nginx Explorer

To run the explorer locally, this nginx configuration is required to get local https to work.

## Running

Update your `/etc/hosts` file to include the following:

```
127.0.0.1 api.localhost
127.0.0.1 rpc.localhost
127.0.0.1 pingpub.localhost
```

Start the testnet with: `make sh-testnet` or the full IBC network with `make testnet`

Then `docker compose up` to start the reverse proxy, explorer, and the RPC/REST API Services.

<!-- markdown-link-check-disable-next-line -->
Visit: https://pingpub.localhost to view the explorer.

> Attempting to view as a standard http:// instance will break the block explorer due to pesky CORS errors.
21 changes: 21 additions & 0 deletions simapp/nginx/nginx-selfsigned.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDazCCAlOgAwIBAgIUVgGX1ixwRoR1zlI8hTotdUKYLv4wDQYJKoZIhvcNAQEL
BQAwRTELMAkGA1UEBhMCVVMxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDA3MjEyMTM4MDVaFw0yNDA4
MjAyMTM4MDVaMEUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDPiqGL1t3RFFkhFJXRb1qO249wODwhUmMIYr3Kn4Tv
RzgZg8+6U95djp6j5ToOnZpW+HGk87y/QKdnc4j23rVLUhWjIOJNsdttB/iBY3bY
4kGpTByeM0/INE1ccjjE/+0e8Zmi/EpAGOtaQc8XWW4w7XUr7PtvXt8hlOSJWfd6
+1gtiN/uHiAjWAudDyQw06ldhFyBBbIjTgF5jFVUFflPg7rB1RJFquDJGjaW3kDQ
Jz4BLlRhspgQqz1bzJTwqXivXp3nk9na2wesMcMDK0NSLBoqxqqTx06UZmlMm2/R
vRFg6F66/wqUhhxHvw2iLqBhoirhRiIL9IgTu388cE/DAgMBAAGjUzBRMB0GA1Ud
DgQWBBQD++PJjWJKDdNPv+t6aoMyCiF6TDAfBgNVHSMEGDAWgBQD++PJjWJKDdNP
v+t6aoMyCiF6TDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCn
+nuVpVpetc83BTOoJopqosaVZuk87NGutvMiua/dHosfwgVqz0PAmg3DZ47eVOeH
trgFW3XINXxPdV8RL9cLAq3sppmSMBHMxHDu54uJ/9nJcEX2zCXYlCeJgcLShLv8
BB7M1VFPRiaPpAwrE/UgaVumeD+XWNVs6INGB0n74SZG1aRr7JWbm9HG02Hon/MG
5OpUfhpCL13P78x1KuHCMAxAK16Ifpb0Vk17RNqbrDx6yHnhcDOWOCH29RdMB7I9
fwf62r70hGjhOavgaVKGcbiOIfQoGh8rLOOQUcHXdpbx7lKtjgAnytMIQ6Fx9wNI
WMRBwh/Vql5nhzioWSmB
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions simapp/nginx/nginx-selfsigned.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDPiqGL1t3RFFkh
FJXRb1qO249wODwhUmMIYr3Kn4TvRzgZg8+6U95djp6j5ToOnZpW+HGk87y/QKdn
c4j23rVLUhWjIOJNsdttB/iBY3bY4kGpTByeM0/INE1ccjjE/+0e8Zmi/EpAGOta
Qc8XWW4w7XUr7PtvXt8hlOSJWfd6+1gtiN/uHiAjWAudDyQw06ldhFyBBbIjTgF5
jFVUFflPg7rB1RJFquDJGjaW3kDQJz4BLlRhspgQqz1bzJTwqXivXp3nk9na2wes
McMDK0NSLBoqxqqTx06UZmlMm2/RvRFg6F66/wqUhhxHvw2iLqBhoirhRiIL9IgT
u388cE/DAgMBAAECggEALQBn3/0SsuvBGcmvZK7LCY/1LcWb0DPfkmlqst1dA09D
jFDHAaV+4XVz06D4MkQdO796UOSi6Ct6QRXNvI307KSbWXhfaa5noGAqk8+/7O4+
g5mj2O/SXFxu690+jwTZYyzK/grLhNOCcNs1LuBu4sASeJhVusPtCQiSd2/hGDK0
3AtN561z3QEAseV+yIVyAutAL0Xj+w8g1g0sKGkojypAwWnhX9I02xBhNFCyMkBp
/Tuts48QEomYbEI91wEa6PumD9EMtHV5JSiHJm59jbn7GPd38fqORB2Qhh580lg6
zINAOHZb9BwXJYo5tRLZI/tKUQKj8PCactDM+hmQiQKBgQDuFB96a44R7xII8P6o
OE3ECHEsaaiywQ6FX3rVfC2AYySIXVIcrng//ITbwW8Tv26jAfCxkaTV+XN2UplH
tksSj3Ll9f9qCdeog9UJhT7TFR6uwSHTZ9ninhS0J5HEalkYwYo7i4uQaIrjK4Ll
4fLMqiGoFVU1g4REJlNiz/ecqwKBgQDfKgujoCL73akWqVKdEFNWKWlHaTr7Ihhb
wMAmSkK6L29+Ig+0Q+Cs5ndtZP8UFGTndVoi++yU2oXYdXwUcyS+cyzi7X9Zmp+F
xSa8zq5+oOGOfRAOtlp/Sf3/xJO6NxCT7uS0Q5u3BHuldU/Lx5wagA20uCldh5dO
Nx5zubfpSQKBgCvHMX6eVnJ/xo40Wm9uYwZgEwd6qlWsYFIwG3M0MV3BXU9h8Z5q
ipwhgAC00gsMkXiR+8N7J5ddFlk0mRDxuV5BWHxmvr+t7aUEEOF+Se4gnRK/Wsv3
9b3RGbeC6y/16ko+FIAcid5VCuz47En/QVlXE3dH7PI5K9IoRf8OhNafAoGAKNaP
5LSUUlUA8WWw+Y8YQQc4/dly8qwNmxTN1PP3/AxcMc/X4dweDGXsavd1el41DOo7
wXUqmR7YKYFuYGulyLhY+XoOuP4DvT4T1a9Y3VFhlWqrepXCP9LxiVGW2xfij7/C
2H4ay8YlPmUWYis4FN1kJLMi1rvOY4DQsMrGrgkCgYEAg/nASsYYpOUxEg8Z2X7r
PvDIPu6S51o74Qwukq4tXG0ALpNHQQJfh4kG2+Dy9gYYuSYHyyRw3I1P68JDQzHB
4qnRaVLQn5rk4++xD01P22juvT+XHqeiRAGl+8n/xqj/qdwoI4LEyhgXH5TpjpCw
gcH/cDxQQbmkHxLCQ3bzuJ8=
-----END PRIVATE KEY-----
53 changes: 53 additions & 0 deletions simapp/nginx/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
server {
listen 80;
listen 443 ssl;

server_name api.localhost;
ssl_certificate nginx-selfsigned.crt;
ssl_certificate_key nginx-selfsigned.key;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Expose-Headers Content-Length;

location / {
proxy_pass http://127.0.0.1:1317;
}
}

server {
listen 80;
listen 443 ssl;

server_name rpc.localhost;
ssl_certificate nginx-selfsigned.crt;
ssl_certificate_key nginx-selfsigned.key;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Expose-Headers Content-Length;

location / {
proxy_pass http://127.0.0.1:26657;
}
}

server {
listen 80;
listen 443 ssl;

server_name pingpub.localhost;
ssl_certificate nginx-selfsigned.crt;
ssl_certificate_key nginx-selfsigned.key;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Expose-Headers Content-Length;

location / {
proxy_pass http://127.0.0.1:5173;
}
}
4 changes: 4 additions & 0 deletions spawn/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,10 @@ func (cfg *NewChainConfig) CreateNewChain() error {
cfg.GitInitNewProjectRepo()
}

if !cfg.IsFeatureDisabled("block-explorer") {
cfg.NewPingPubExplorer()
}

return nil
}

Expand Down
130 changes: 130 additions & 0 deletions spawn/explorer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package spawn

import (
"encoding/json"
"fmt"
"os"
"path"
"strings"
)

type (
ChainExplorerAsset struct {
Base string `json:"base"`
Symbol string `json:"symbol"`
Exponent string `json:"exponent"`
CoingeckoId string `json:"coingecko_id"`
Logo string `json:"logo"`
}

Endpoint struct {
Provider string `json:"provider"`
Address string `json:"address"`
}

ChainExplorer struct {
ChainName string `json:"chain_name"`
Api []Endpoint `json:"api"`
Rpc []Endpoint `json:"rpc"`
SdkVersion string `json:"sdk_version"`
CoinType string `json:"coin_type"`
MinTxFee string `json:"min_tx_fee"`
AddrPrefix string `json:"addr_prefix"`
Logo string `json:"logo"`
ThemeColor string `json:"theme_color"`
Assets []ChainExplorerAsset `json:"assets"`
}
)

// hacky: pingpub does not have a docker file for some reason...
const dockerFile = `# docker build . -t pingpub:latest

FROM node:20-alpine

RUN apk add --no-cache yarn npm

WORKDIR /app

COPY . .

# install node_modules to the image
RUN yarn --ignore-engines

CMD [ "yarn", "--ignore-engines", "serve", "--host", "0.0.0.0" ]`

func NewEndpoint(provider, address string) Endpoint {
return Endpoint{
Provider: provider,
Address: address,
}
}

func (cfg NewChainConfig) NewPingPubExplorer() error {
if err := os.Chdir(cfg.ProjectName); err != nil {
cfg.Logger.Error("chdir", "err", err)
}
if err := ExecCommand("git", "clone", "https://github.com/ping-pub/explorer.git"); err != nil {
cfg.Logger.Error("git clone", "err", err)
}
if err := os.Chdir(".."); err != nil {
cfg.Logger.Error("chdir", "err", err)
}

mainnet := path.Join(cfg.ProjectName, "explorer", "chains", "mainnet")
cfg.clearDir(mainnet)
cfg.clearDir(path.Join(cfg.ProjectName, "explorer", "chains", "testnet"))

// Create JSON config file for explorer
explorer := cfg.NewChainExplorerConfig()
bz, err := json.MarshalIndent(explorer, "", " ")
if err != nil {
cfg.Logger.Error("Error marshalling chain explorer config", "err", err)
}

err = os.WriteFile(path.Join(mainnet, fmt.Sprintf("%s.json", cfg.ProjectName)), bz, 0644)
if err != nil {
cfg.Logger.Error("Error writing chain explorer config", "err", err)
}

err = os.WriteFile(path.Join(cfg.ProjectName, "explorer", "Dockerfile"), []byte(dockerFile), 0644)
if err != nil {
cfg.Logger.Error("Error writing docker file", "err", err)
}

return nil
}

func (cfg NewChainConfig) NewChainExplorerConfig() ChainExplorer {
logo := "https://img.freepik.com/free-vector/letter-s-box-logo-design-template_474888-3345.jpg?size=338&ext=jpg&ga=GA1.1.2008272138.1721260800&semt=ais_user"
return ChainExplorer{
ChainName: cfg.ProjectName,
Api: []Endpoint{NewEndpoint("api.localhost", "https://api.localhost")},
Rpc: []Endpoint{NewEndpoint("rpc.localhost", "https://rpc.localhost")},
SdkVersion: "0.50",
CoinType: "118",
MinTxFee: "800",
AddrPrefix: cfg.Bech32Prefix,
Logo: logo,
ThemeColor: "#001be7",
Assets: []ChainExplorerAsset{
{
Base: cfg.Denom,
Symbol: strings.ToUpper(cfg.Denom),
Exponent: "6",
CoingeckoId: "",
Logo: logo,
},
},
}
}

func (cfg NewChainConfig) clearDir(dirLoc ...string) {
dir := path.Join(dirLoc...)

if err := os.RemoveAll(dir); err != nil {
cfg.Logger.Error("Error removing directory", "err", err)
}
if err := os.MkdirAll(dir, 0755); err != nil {
cfg.Logger.Error("Error creating directory", "err", err)
}
}
4 changes: 1 addition & 3 deletions spawn/file_content.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,7 @@ func (fc *FileContent) DeleteFile(path string) {
}

func (fc *FileContent) DeleteDirectoryContents(path string) {
if fc.ContainsPath(path) && !AlreadyCheckedDeletion[path] {
AlreadyCheckedDeletion[path] = true

if fc.ContainsPath(path) {
fc.Logger.Debug("Deleting contents for", "path", path)
fc.Contents = ""
}
Expand Down
Loading