Skip to content

Commit a070f5c

Browse files
committed
feat: init
0 parents  commit a070f5c

12 files changed

Lines changed: 2939 additions & 0 deletions

File tree

.github/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!--suppress HtmlDeprecatedAttribute -->
2+
3+
<div align="center">
4+
<h1>KYVE + Substrate</h1>
5+
</div>
6+
7+
![banner](https://github.com/kyve-org/assets/raw/main/banners/Substrate.png)
8+
9+
## Configuration
10+
11+
```json
12+
{
13+
"rpc": "https://proxy.kyve.network/polkadot",
14+
"github": "https://github.com/kyve-org/substrate"
15+
}
16+
```
17+
18+
## Endpoints
19+
20+
- [`/blocks/{height}`](https://paritytech.github.io/substrate-api-sidecar/dist)

.github/webhook.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const Discord = require('webhook-discord');
2+
const client = new Discord.Webhook(process.env.DISCORD);
3+
4+
const message = new Discord.MessageBuilder()
5+
.setColor('#58C6B2')
6+
.setTitle(':new: New Release :new:')
7+
.setDescription(`\`@kyve/substrate\` ${process.env.VERSION} released.`)
8+
.setURL(
9+
`https://github.com/kyve-org/substrate/releases/tag/${process.env.VERSION}`
10+
)
11+
.setName('Release Bot');
12+
13+
// noinspection JSIgnoredPromiseFromCall
14+
client.send(message);

.github/workflows/release.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Release
2+
3+
on:
4+
release:
5+
types: [released]
6+
7+
# Allows you to run this workflow manually from the Actions tab
8+
workflow_dispatch:
9+
10+
jobs:
11+
binaries:
12+
name: Build release binaries.
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v2
17+
- uses: actions/setup-node@v3
18+
19+
- name: Install yarn.
20+
run: npm install -g yarn
21+
- name: Install dependencies.
22+
run: yarn install
23+
- name: Build.
24+
run: yarn build:binaries
25+
26+
- uses: actions/upload-artifact@v3
27+
with:
28+
name: kyve-substrate-linux
29+
path: ./out/substrate-linux
30+
- uses: actions/upload-artifact@v3
31+
with:
32+
name: kyve-substrate-macos
33+
path: ./out/substrate-macos
34+
- uses: actions/upload-artifact@v3
35+
with:
36+
name: kyve-substrate-win
37+
path: ./out/substrate-win.exe
38+
39+
docker:
40+
name: Build and publish Docker container.
41+
runs-on: ubuntu-latest
42+
43+
steps:
44+
- uses: actions/checkout@v2
45+
46+
- name: Login to Docker.
47+
run: docker login -u ${{ secrets.DOCKER_USER }} -p ${{ secrets.DOCKER_PASSWORD }}
48+
49+
- name: Build the Docker image.
50+
run: docker build -t kyve/substrate:${GITHUB_REF#refs/tags/} -t kyve/substrate:latest .
51+
52+
- name: Push to Docker hub.
53+
run: docker push -a kyve/substrate
54+
55+
webhook:
56+
name: Post a message to Discord.
57+
needs: [binaries, docker]
58+
runs-on: ubuntu-latest
59+
60+
steps:
61+
- uses: actions/checkout@v2
62+
- uses: actions/setup-node@v3
63+
64+
- name: Install yarn.
65+
run: npm install -g yarn
66+
- name: Install dependencies.
67+
run: yarn install
68+
69+
- name: Run script.
70+
run: DISCORD=${{ secrets.DISCORD }} VERSION=${GITHUB_REF#refs/tags/} node .github/webhook.js

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.idea
2+
db
3+
dist
4+
logs
5+
node_modules
6+
out
7+
.DS_Store

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
db
2+
dist

Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM node:current-alpine
2+
3+
COPY package.json .
4+
RUN yarn install
5+
COPY . .
6+
RUN yarn build
7+
8+
ENTRYPOINT [ "yarn", "start" ]

package.json

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "@kyve/substrate",
3+
"version": "0.0.0",
4+
"license": "MIT",
5+
"scripts": {
6+
"build": "rimraf dist && tsc",
7+
"build:binaries": "yarn build && rimraf out && pkg package.json",
8+
"start": "node ./dist/src/index.js",
9+
"format": "prettier --write ."
10+
},
11+
"bin": "./dist/src/index.js",
12+
"pkg": {
13+
"scripts": "./dist/src/index.js",
14+
"assets": "./node_modules/@kyve/sdk/dist/proto/*",
15+
"targets": [
16+
"latest-linux-x64",
17+
"latest-macos-x64",
18+
"latest-win-x64"
19+
],
20+
"outputPath": "out"
21+
},
22+
"prettier": {
23+
"singleQuote": true
24+
},
25+
"dependencies": {
26+
"@kyve/core": "KYVENetwork/core#v0.4.0",
27+
"@kyve/sdk": "KYVENetwork/sdk#main",
28+
"axios": "^0.27.2"
29+
},
30+
"devDependencies": {
31+
"pkg": "^5.6.0",
32+
"prettier": "^2.6.2",
33+
"rimraf": "^3.0.2",
34+
"typescript": "^4.6.4",
35+
"webhook-discord": "^3.7.8"
36+
}
37+
}

src/index.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import KYVE from '@kyve/core';
2+
import { Signature } from './types';
3+
import { fetchBlock, isHeightOutOfRange } from './utils';
4+
import { name, version } from '../package.json';
5+
6+
process.env.KYVE_RUNTIME = name;
7+
process.env.KYVE_VERSION = version;
8+
9+
KYVE.metrics.register.setDefaultLabels({
10+
app: process.env.KYVE_RUNTIME,
11+
});
12+
13+
class KyveSubstrate extends KYVE {
14+
public async getDataItem(key: number): Promise<{ key: number; value: any }> {
15+
let block;
16+
17+
try {
18+
block = await fetchBlock(
19+
this.pool.config.rpc,
20+
key,
21+
await this.getSignature()
22+
);
23+
} catch (err) {
24+
if (isHeightOutOfRange(err)) throw new Error();
25+
26+
this.logger.warn(
27+
`⚠️ EXTERNAL ERROR: Failed to fetch block ${key}. Retrying ...`
28+
);
29+
30+
throw err;
31+
}
32+
33+
return { key, value: block };
34+
}
35+
36+
private async getSignature(): Promise<Signature> {
37+
const address = await this.sdk.wallet.getAddress();
38+
const timestamp = new Date().valueOf().toString();
39+
40+
const message = `${address}//${this.poolId}//${timestamp}`;
41+
42+
const { signature, pub_key } = await this.sdk.signString(message);
43+
44+
return {
45+
signature,
46+
pubKey: pub_key.value,
47+
poolId: this.poolId.toString(),
48+
timestamp,
49+
};
50+
}
51+
}
52+
53+
// noinspection JSIgnoredPromiseFromCall
54+
new KyveSubstrate().start();

src/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export const UNABLE_TO_RETRIEVE =
2+
'Unable to retrieve header and parent from supplied hash';
3+
4+
export interface Signature {
5+
signature: string;
6+
pubKey: string;
7+
poolId: string;
8+
timestamp: string;
9+
}

src/utils.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import axios, { AxiosResponse } from 'axios';
2+
import { Signature, UNABLE_TO_RETRIEVE } from './types';
3+
4+
export async function fetchBlock(
5+
endpoint: string,
6+
height: number,
7+
signature: Signature
8+
) {
9+
return await requestSidecarAPI(`${endpoint}/blocks/${height}`, signature);
10+
}
11+
12+
export function isHeightOutOfRange(err: any): boolean {
13+
if (err.isAxiosError) {
14+
const response: AxiosResponse = err.response;
15+
16+
if (response && response.data && response.data.message) {
17+
if (response.data.message === UNABLE_TO_RETRIEVE) {
18+
return true;
19+
}
20+
}
21+
}
22+
23+
return false;
24+
}
25+
26+
async function requestSidecarAPI(endpoint: string, signature: Signature) {
27+
const { data } = await axios.get(endpoint, {
28+
headers: {
29+
Signature: signature.signature,
30+
'Public-Key': signature.pubKey,
31+
'Pool-ID': signature.poolId,
32+
Timestamp: signature.timestamp,
33+
},
34+
});
35+
36+
return data;
37+
}

0 commit comments

Comments
 (0)