Skip to content

Commit

Permalink
add github content uri validation (#52)
Browse files Browse the repository at this point in the history
* feat: validate github content uri

* fix: gitwork

* fix: remove test log
  • Loading branch information
ALPAC-4 authored Apr 24, 2024
1 parent a29e541 commit b182a40
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 200 deletions.
288 changes: 92 additions & 196 deletions .github/workflows/utility/validate_data.py
Original file line number Diff line number Diff line change
@@ -1,209 +1,105 @@
import json
import urllib.request
import os
from os import getcwd

rootdir = getcwd()

checkSlip173 = 0
slipWebsites = {}
slipMainnetPrefixes = {}
slipTestnetPrefixes = {}

def readSLIP173():
slip173URL = "https://raw.githubusercontent.com/satoshilabs/slips/master/slip-0173.md"
lines = []
for line in urllib.request.urlopen(slip173URL):
line = line.decode('utf-8')
if (len(line) > 2):
if (line[0] == "|" and line[2] == "["):
lines.append(line)
if lines:
for line in lines:
pretty = line[3:line.find("]")]
website = line[line.find("(")+1:line.find(")")]
slipWebsites[pretty] = website
secondPipe = line.find("|", 1)
thirdPipe = line.find("|", secondPipe + 1)
mainnetArea = line[secondPipe:thirdPipe]
firstQuote = mainnetArea.find("`")
if(firstQuote > 0):
secondQuote = mainnetArea.find("`", firstQuote + 1)
if(secondQuote > 0):
mainnetPrefix = mainnetArea[firstQuote + 1:secondQuote]
slipMainnetPrefixes[pretty] = mainnetPrefix
else:
print("Mainnet Bech32 Prefix undefined - missing second quote")
else:
print("Mainnet Bech32 Prefix undefined")
fourthPipe = line.find("|", thirdPipe + 1)
testnetArea = line[thirdPipe:fourthPipe]
firstQuote = testnetArea.find("`")
if(firstQuote > 0):
secondQuote = testnetArea.find("`", firstQuote + 1)
if(secondQuote > 0):
testnetPrefix = testnetArea[firstQuote + 1:testnetArea.find("`", firstQuote + 1)]
slipTestnetPrefixes[pretty] = testnetPrefix
else:
print("Mainnet Bech32 Prefix undefined - missing second quote")
else:
raise Exception("no SLIP-0173 entries recorded")

checkSlip44 = 1
slipCoinTypesByNum = {}
slipCoinTypesByName = {}
slip44Websites = {}

def readSLIP44():
slip44URL = "https://raw.githubusercontent.com/satoshilabs/slips/master/slip-0044.md"
lines = []
for line in urllib.request.urlopen(slip44URL):
line = line.decode('utf-8')
if(len(line) > 20):
if(line[0] == "|" and line[2] != "C" and line[2] != "-"):
lines.append(line)
if lines:
for line in lines:
coinNumber = int(line[2:line.find(" ", 2)])
if(line.find("[") > 0):
pretty = line[line.find("[")+1:line.find("]")]
website = line[line.find("(")+1:line.find(")")]
slip44Websites[pretty] = website
else:
firstPipe = line.find("|")
secondPipe = line.find("|", firstPipe + 1)
thirdPipe = line.find("|", secondPipe + 1)
pretty = line[thirdPipe+2:len(line)-1]
slipCoinTypesByNum[coinNumber] = pretty
slipCoinTypesByName[pretty] = coinNumber
else:
raise Exception("no SLIP-0044 entries recorded")

# -----FOR EACH CHAIN-----
def checkChains():
for chainfolder in os.listdir(rootdir):
chainjson = os.path.join(chainfolder, "chain.json")
print(chainjson + " - " + str(os.path.exists(chainjson)))
if not os.path.exists(chainjson):
continue
chainSchema = json.load(open(os.path.join(rootdir, chainjson)))
assetlistjson = os.path.join(chainfolder, "assetlist.json")
print(assetlistjson + " - " + str(os.path.exists(assetlistjson)))
if not os.path.exists(assetlistjson):
continue
assetlistSchema = json.load(open(os.path.join(rootdir, assetlistjson)))
bases = []
if "assets" in assetlistSchema:
if assetlistSchema["assets"]:
for asset in assetlistSchema["assets"]:
assetDenoms = []
if "denom_units" in asset:
if asset["denom_units"]:
for unit in asset["denom_units"]:
if "denom" in unit:
assetDenoms.append(unit["denom"])
else:
raise Exception("unit doesn't contain 'denom' string")
if "aliases" in unit:
for alias in unit["aliases"]:
assetDenoms.append(alias)
else:
raise Exception("'denon_units' array doesn't contain any units")
else:
raise Exception("asset doesn't contain 'denom_units' array")
if "base" in asset:
if asset["base"] in assetDenoms:
bases.append(asset["base"])
else:
raise Exception("base not in denom_units")
else:
raise Exception("asset doesn't contain 'base' string")
if "display" in asset:
if asset["display"] not in assetDenoms:
raise Exception("display " + asset["display"] + " not in denom_units")
else:
raise Exception("asset doesn't contain 'display' string")
else:
raise Exception("'assets' array doesn't contain any tokens")
else:
raise Exception("assetlist schema doesn't contain 'assets' array")
if "fees" in chainSchema:
if "fee_tokens" in chainSchema["fees"]:
if chainSchema["fees"]["fee_tokens"]:
for token in chainSchema["fees"]["fee_tokens"]:
if "denom" in token:
if token["denom"] not in bases:
raise Exception(token["denom"] + " is not in bases")
else:
raise Exception("token doesn't contain 'denom' string")
for networkfolder in os.listdir(rootdir):
if not os.path.isdir(networkfolder):
continue
for chainfolder in os.listdir(networkfolder):
chainjson = os.path.join(networkfolder, chainfolder, "chain.json")
print(chainjson + " - " + str(os.path.exists(chainjson)))
if not os.path.exists(chainjson):
continue
chainSchema = json.load(open(os.path.join(rootdir, chainjson)))
assetlistjson = os.path.join(networkfolder, chainfolder, "assetlist.json")
print(assetlistjson + " - " + str(os.path.exists(assetlistjson)))
if not os.path.exists(assetlistjson):
continue
assetlistSchema = json.load(open(os.path.join(rootdir, assetlistjson)))
bases = []
if "assets" in assetlistSchema:
if assetlistSchema["assets"]:
for asset in assetlistSchema["assets"]:
assetDenoms = []
if "denom_units" in asset:
if asset["denom_units"]:
for unit in asset["denom_units"]:
if "denom" in unit:
assetDenoms.append(unit["denom"])
if "aliases" in unit:
for alias in unit["aliases"]:
assetDenoms.append(alias)
else:
raise Exception("'denon_units' array doesn't contain any units")
if "base" in asset:
if asset["base"] in assetDenoms:
bases.append(asset["base"])
if "images" in asset:
for image in asset["images"]:
if "png" in image:
validateRawGithubContent(image["png"])
if "svg" in image:
validateRawGithubContent(image["svg"])
if "logo_URIs" in asset:
if "png" in asset["logo_URIs"]:
validateRawGithubContent(asset["logo_URIs"]["png"])
if "svg" in asset["logo_URIs"]:
validateRawGithubContent(asset["logo_URIs"]["svg"])
else:
raise Exception("'fee_tokens' array doesn't contain any tokens")
raise Exception("'assets' array doesn't contain any tokens")
else:
raise Exception("'fees' object doesn't contain 'fee_tokens' array")
else:
print("[OPTIONAL - Keplr Compliance] chain schema doesn't contain 'fees' object")
if "staking" in chainSchema:
if "staking_tokens" in chainSchema["staking"]:
if chainSchema["staking"]["staking_tokens"]:
for token in chainSchema["staking"]["staking_tokens"]:
if "denom" in token:
if token["denom"] not in bases:
raise Exception(token["denom"] + " is not in bases")
else:
raise Exception("token doesn't contain 'denom' string")
else:
raise Exception("'staking_tokens' array doesn't contain any tokens")
else:
raise Exception("'fees' object doesn't contain 'staking_tokens' array")
else:
print("[OPTIONAL - Keplr Compliance] chain schema doesn't contain 'staking' object")
if "network_type" in chainSchema:
networkType = chainSchema["network_type"]
if networkType == "mainnet":
slipPrefixes = slipMainnetPrefixes
elif networkType == "testnet":
slipPrefixes = slipTestnetPrefixes
else:
raise Exception("network type unknown (not Mainnet nor Testnet)")
else:
raise Exception("chain schema doesn't contain 'network_type'")
if "pretty_name" in chainSchema:
prettyName = chainSchema["pretty_name"]
if checkSlip173:
if "bech32_prefix" in chainSchema:
if prettyName == "Terra Classic" or prettyName == "Terra 2.0":
prettyName = "Terra"
if prettyName in slipWebsites:
if prettyName in slipPrefixes:
if chainSchema["bech32_prefix"] != slipPrefixes[prettyName]:
raise Exception("chain.json bech32 prefix " + chainSchema["bech32_prefix"] + " does not match SLIP-0173 prefix " + slipPrefixes[prettyName])
else:
raise Exception(prettyName + " SLIP-0173 registeration does not have prefix")
raise Exception("assetlist schema doesn't contain 'assets' array")
if "fees" in chainSchema:
if "fee_tokens" in chainSchema["fees"]:
if chainSchema["fees"]["fee_tokens"]:
for token in chainSchema["fees"]["fee_tokens"]:
if "denom" in token:
if token["denom"] not in bases:
raise Exception(token["denom"] + " is not in bases")
else:
raise Exception(prettyName + " not registered to SLIP-0173")
raise Exception("'fee_tokens' array doesn't contain any tokens")
if "staking" in chainSchema:
if "staking_tokens" in chainSchema["staking"]:
if chainSchema["staking"]["staking_tokens"]:
for token in chainSchema["staking"]["staking_tokens"]:
if "denom" in token:
if token["denom"] not in bases:
raise Exception(token["denom"] + " is not in bases")
else:
raise Exception("token doesn't contain 'denom' string")
else:
raise Exception(prettyName + " missing 'bech32_prefix'")
if checkSlip44:
if "slip44" in chainSchema:
coinType = chainSchema["slip44"]
if prettyName in slipCoinTypesByName:
if coinType != slipCoinTypesByName[prettyName]:
raise Exception("Chain schema Coin Type " + str(coinType) + " does not equal slip44 registration " + str(slipCoinTypesByName[prettyName]))
else:
if coinType in slipCoinTypesByNum:
if slipCoinTypesByNum[coinType] == "":
raise Exception("Coin Type " + str(coinType) + " is unregistered in SLIP44")
else:
raise Exception("Coin Type " + str(coinType) + " is unreserved in SLIP44")
else:
print("[OPTIONAL - Keplr Compliance] chain schema doesn't contain 'slip44' string")
else:
raise Exception("chainSchema does not contain 'pretty_name'")
raise Exception("'fees' object doesn't contain 'staking_tokens' array")
else:
print("[OPTIONAL - Keplr Compliance] chain schema doesn't contain 'staking' object")
# raw.githubusercontent uri check
if "images" in chainSchema:
for image in chainSchema["images"]:
if "png" in image:
validateRawGithubContent(image["png"])
if "svg" in image:
validateRawGithubContent(image["svg"])

if "logo_URIs" in chainSchema:
if "png" in chainSchema["logo_URIs"]:
validateRawGithubContent(chainSchema["logo_URIs"]["png"])
if "svg" in chainSchema["logo_URIs"]:
validateRawGithubContent(chainSchema["logo_URIs"]["svg"])



print("Done")

def runAll():
if checkSlip173:
readSLIP173()
if checkSlip44:
readSLIP44()
checkChains()

# check the file exists
def validateRawGithubContent(uri: str):
prefix = "https://raw.githubusercontent.com/initia-labs/initia-registry/main/"
# check only if initia-registry main branch
if not uri.startswith(prefix):
return
path = uri[len(prefix):]
if not os.path.exists(path):
raise Exception("file(" + path + ") doesn't exists")

6 changes: 3 additions & 3 deletions .github/workflows/validate_data.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ jobs:
python-version: 3.9

- name: Install Python dependencies
run: |
run: |
python -m pip install --upgrade pip
cd .github/workflows/utility
- name: Run Data Validation python script
shell: python
run: |
import sys
sys.path.insert(1, '.github/workflows/utility')
import validate_data
validate_data.runAll()
validate_data.checkChains()
2 changes: 1 addition & 1 deletion chain.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"title": "Cosmos Chain",
"description": "Cosmos Chain.json is a metadata file that contains information about a cosmos sdk based chain.",
"type": "object",
"required": ["chain_name", "chain_id", "bech32_prefix"],
"required": ["chain_name", "chain_id", "bech32_prefix", "network_type"],
"properties": {
"$schema": {
"type": "string",
Expand Down

0 comments on commit b182a40

Please sign in to comment.