diff --git a/.github/workflows/dev.yaml b/.github/workflows/dev.yaml
index 11f06218..3ec426ba 100644
--- a/.github/workflows/dev.yaml
+++ b/.github/workflows/dev.yaml
@@ -18,7 +18,7 @@ jobs:
repository: stats-api
file: ./api/Dockerfile
secrets: inherit
-
+
build_and_deploy_backend_cerestats_crawler:
uses: Cerebellum-Network/reusable-workflows/.github/workflows/deploy-to-ecr.yaml@master
with:
@@ -32,7 +32,7 @@ jobs:
uses: Cerebellum-Network/reusable-workflows/.github/workflows/build-and-upload-static.yaml@1.0.0
with:
runs-on: '["self-hosted", "cere-network-large-workers"]'
- build_container: 'node:14-buster-slim'
+ build_container: 'node:16-buster-slim'
deploy_container: 'ubuntu:20.04'
install_packages_command: 'cp -rf frontend/frontend.config-cere-dev.js frontend/frontend.config.js; yarn install'
build_command: 'yarn workspace frontend generate'
diff --git a/.github/workflows/prod.yaml b/.github/workflows/prod.yaml
index 22093628..11db50f8 100644
--- a/.github/workflows/prod.yaml
+++ b/.github/workflows/prod.yaml
@@ -55,7 +55,7 @@ jobs:
uses: Cerebellum-Network/reusable-workflows/.github/workflows/build-and-upload-static.yaml@1.0.0
with:
runs-on: '["self-hosted", "cere-network-large-workers"]'
- build_container: 'node:14-buster-slim'
+ build_container: 'node:16-buster-slim'
deploy_container: 'ubuntu:20.04'
install_packages_command: 'cp -rf frontend/frontend.config-cere-prd.js frontend/frontend.config.js; yarn install'
build_command: 'yarn workspace frontend generate'
diff --git a/.github/workflows/stage.yaml b/.github/workflows/stage.yaml
index e99dbb9a..7130b414 100644
--- a/.github/workflows/stage.yaml
+++ b/.github/workflows/stage.yaml
@@ -35,7 +35,7 @@ jobs:
uses: Cerebellum-Network/reusable-workflows/.github/workflows/build-and-upload-static.yaml@master
with:
runs-on: '["self-hosted", "cere-network-large-workers"]'
- build_container: 'node:14-buster-slim'
+ build_container: 'node:16-buster-slim'
deploy_container: 'ubuntu:20.04'
install_packages_command: 'cp -rf frontend/frontend.config-cere-dev.js frontend/frontend.config.js; yarn install'
build_command: 'yarn workspace frontend generate'
diff --git a/README.md b/README.md
index d16ef264..b9048afc 100644
--- a/README.md
+++ b/README.md
@@ -34,9 +34,9 @@ apt install docker-ce
sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
```
-# node v14
+# node v16
```bash
-curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh
+curl -fsSL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh
bash nodesource_setup.sh
apt install nodejs
```
diff --git a/api/Dockerfile b/api/Dockerfile
index 5868c953..55afba71 100644
--- a/api/Dockerfile
+++ b/api/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:fermium
+FROM node:galium
WORKDIR /usr/app/api
@@ -9,6 +9,6 @@ COPY ./db /usr/app/db
EXPOSE 8000
-RUN yarn
+RUN yarn
CMD ["yarn", "start"]
diff --git a/backend/crawlers/blockHarvester.js b/backend/crawlers/blockHarvester.js
index 102a9a90..a211de2b 100644
--- a/backend/crawlers/blockHarvester.js
+++ b/backend/crawlers/blockHarvester.js
@@ -9,6 +9,7 @@ const {
processExtrinsics,
processEvents,
processLogs,
+ processMetadata,
getDisplayName,
wait,
logHarvestError,
@@ -101,6 +102,31 @@ const harvestBlock = async (api, client, blockNumber) => {
// ToDo fix with CBI-1451
const isElection = false;
+ // Runtime upgrade
+ const runtimeUpgrade = blockEvents.find(
+ ({ event: { section, method } }) => section === 'system' && method === 'CodeUpdated',
+ );
+
+ if (runtimeUpgrade) {
+ const { specName } = runtimeVersion.toJSON();
+ const { specVersion } = runtimeVersion;
+
+ // TODO: enable again
+ // see: https://github.com/polkadot-js/api/issues/4596
+ // const metadata = await api.rpc.state.getMetadata(blockHash);
+
+ await processMetadata(
+ client,
+ api,
+ blockNumber,
+ blockHash.toString(),
+ specName.toString(),
+ specVersion.toNumber(),
+ timestamp,
+ loggerOptions,
+ );
+ }
+
// Store block extrinsics (async)
processExtrinsics(
api,
diff --git a/backend/crawlers/blockListener.js b/backend/crawlers/blockListener.js
index c1128900..ddc1492e 100644
--- a/backend/crawlers/blockListener.js
+++ b/backend/crawlers/blockListener.js
@@ -7,6 +7,7 @@ const {
isNodeSynced,
wait,
shortHash,
+ processMetadata,
processExtrinsics,
processEvents,
processLogs,
@@ -199,6 +200,24 @@ const crawler = async () => {
),
]);
+ // Process Metadata
+ try {
+ const { specName } = runtimeVersion.toJSON();
+ const { specVersion } = runtimeVersion;
+ await processMetadata(
+ client,
+ api,
+ blockNumber,
+ blockHash.toString(),
+ specName.toString(),
+ specVersion.toNumber(),
+ timestamp,
+ loggerOptions,
+ );
+ } catch (e) {
+ console.log('Failed to store Metatdata', e);
+ }
+
// Update finalized blocks
await updateFinalized(client, finalizedBlock, loggerOptions);
diff --git a/backend/docker/crawler/Dockerfile b/backend/docker/crawler/Dockerfile
index 8e5eb367..fe93b7e7 100644
--- a/backend/docker/crawler/Dockerfile
+++ b/backend/docker/crawler/Dockerfile
@@ -1,4 +1,4 @@
-FROM node:fermium
+FROM node:galium
WORKDIR /usr/app/crawler
@@ -7,6 +7,6 @@ COPY ./yarn.lock /usr/app
COPY ./backend /usr/app/crawler
COPY ./db /usr/app/db
-RUN yarn
+RUN yarn
CMD ["yarn", "start"]
diff --git a/backend/lib/utils.js b/backend/lib/utils.js
index 4302de4a..5ebf174e 100644
--- a/backend/lib/utils.js
+++ b/backend/lib/utils.js
@@ -238,6 +238,63 @@ module.exports = {
logger.error(loggerOptions, `Error adding extrinsic ${blockNumber}-${index}: ${JSON.stringify(error)}`);
}
},
+ processMetadata: async (
+ client,
+ api,
+ blockNumber,
+ blockHash,
+ specName,
+ specVersion,
+ timestamp,
+ loggerOptions,
+ ) => {
+ let metadata;
+ try {
+ metadata = await api.rpc.state.getMetadata(blockHash);
+ logger.debug(loggerOptions, `Got runtime metadata at ${blockHash}!`);
+ } catch (error) {
+ logger.error(
+ loggerOptions,
+ `Error fetching runtime metadata at ${blockHash}: ${JSON.stringify(
+ error,
+ )}`,
+ );
+ }
+
+ const data = [
+ blockNumber,
+ specName,
+ specVersion,
+ Object.keys(metadata.toJSON().metadata)[0],
+ metadata.magicNumber,
+ metadata.toJSON().metadata,
+ timestamp,
+ ];
+ const query = `
+ INSERT INTO runtime (
+ block_number,
+ spec_name,
+ spec_version,
+ metadata_version,
+ metadata_magic_number,
+ metadata,
+ timestamp
+ ) VALUES (
+ $1,
+ $2,
+ $3,
+ $4,
+ $5,
+ $6,
+ $7
+ )
+ ON CONFLICT (spec_version)
+ DO UPDATE SET
+ block_number = EXCLUDED.block_number
+ WHERE EXCLUDED.block_number < runtime.block_number;`;
+
+ await module.exports.dbParamQuery(client, query, data, loggerOptions);
+ },
processEvents: async (
client, blockNumber, blockEvents, timestamp, loggerOptions,
) => {
diff --git a/db/migrations/20231009110035-create-runtime-table.js b/db/migrations/20231009110035-create-runtime-table.js
new file mode 100644
index 00000000..f95f06d0
--- /dev/null
+++ b/db/migrations/20231009110035-create-runtime-table.js
@@ -0,0 +1,53 @@
+'use strict';
+
+var dbm;
+var type;
+var seed;
+var fs = require('fs');
+var path = require('path');
+var Promise;
+
+/**
+ * We receive the dbmigrate dependency from dbmigrate initially.
+ * This enables us to not have to rely on NODE_PATH.
+ */
+exports.setup = function(options, seedLink) {
+ dbm = options.dbmigrate;
+ type = dbm.dataType;
+ seed = seedLink;
+ Promise = options.Promise;
+};
+
+exports.up = function(db) {
+ var filePath = path.join(__dirname, 'sqls', '20231009110035-create-runtime-table-up.sql');
+ return new Promise( function( resolve, reject ) {
+ fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
+ })
+ .then(function(data) {
+ return db.runSql(data);
+ });
+};
+
+exports.down = function(db) {
+ var filePath = path.join(__dirname, 'sqls', '20231009110035-create-runtime-table-down.sql');
+ return new Promise( function( resolve, reject ) {
+ fs.readFile(filePath, {encoding: 'utf-8'}, function(err,data){
+ if (err) return reject(err);
+ console.log('received data: ' + data);
+
+ resolve(data);
+ });
+ })
+ .then(function(data) {
+ return db.runSql(data);
+ });
+};
+
+exports._meta = {
+ "version": 1
+};
diff --git a/db/migrations/sqls/20231009110035-create-runtime-table-down.sql b/db/migrations/sqls/20231009110035-create-runtime-table-down.sql
new file mode 100644
index 00000000..eae7bdbf
--- /dev/null
+++ b/db/migrations/sqls/20231009110035-create-runtime-table-down.sql
@@ -0,0 +1 @@
+DROP TABLE IF EXISTS runtime;
diff --git a/db/migrations/sqls/20231009110035-create-runtime-table-up.sql b/db/migrations/sqls/20231009110035-create-runtime-table-up.sql
new file mode 100644
index 00000000..c0fe9917
--- /dev/null
+++ b/db/migrations/sqls/20231009110035-create-runtime-table-up.sql
@@ -0,0 +1,10 @@
+CREATE TABLE IF NOT EXISTS runtime (
+ block_number BIGINT NOT NULL,
+ spec_name TEXT NOT NULL,
+ spec_version INT NOT NULL,
+ metadata_version TEXT NOT NULL,
+ metadata_magic_number INT NOT NULL,
+ metadata JSON NOT NULL,
+ timestamp BIGINT NOT NULL,
+ PRIMARY KEY ( spec_version )
+);
diff --git a/frontend/locales/en.json b/frontend/locales/en.json
index 393b3fb1..a8dccacf 100644
--- a/frontend/locales/en.json
+++ b/frontend/locales/en.json
@@ -200,7 +200,12 @@
"extrinsics": {
"title": "Extrinsics",
"head_title": "Cere Stats - Extrinsics",
- "head_content": "{networkName} Extrinsics"
+ "head_content": "{networkName} Extrinsics",
+ "id": "ID",
+ "timestamp": "Date",
+ "hash": "Hash",
+ "extrinsic": "Extrinsic",
+ "success": "Status"
},
"transfers": {
"title": "Transfers",
diff --git a/frontend/pages/events.vue b/frontend/pages/events.vue
index 3bc110ac..8be10e87 100644
--- a/frontend/pages/events.vue
+++ b/frontend/pages/events.vue
@@ -6,47 +6,109 @@
{{ $t('pages.events.title') }}
- [{{ formatNumber(totalRows) }}]
+
+ [{{ formatNumber(totalRows) }}]
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+ runtime
+
+
+
+
+
+ pallet
+
+
+
+
+
+ event
+
+
+
+
+
+
+
+
+
- #{{ formatNumber(data.item.block_number) }}
+ #{{ formatNumber(data.item.block_number) }}-{{
+ data.item.event_index
+ }}
+
+
+ {{ fromNow(data.item.timestamp) }}
+
+
{{ data.item.section }} ➡
{{ data.item.method }}
+
+
+ {{ data.item.data.substring(0, 32)
+ }}{{ data.item.data.length > 32 ? '...' : '' }}
+
+
@@ -76,7 +138,7 @@
{{ option }}
@@ -115,7 +177,6 @@ export default {
data() {
return {
network,
- loading: true,
filter: '',
events: [],
paginationOptions,
@@ -127,25 +188,35 @@ export default {
fields: [
{
key: 'block_number',
- label: 'Block',
- sortable: true,
+ label: 'Event',
+ sortable: false,
+ },
+ {
+ key: 'timestamp',
+ label: 'Age',
+ sortable: false,
},
{
key: 'event_index',
label: 'Index',
- sortable: true,
+ sortable: false,
},
{
key: 'section',
label: 'Event',
- sortable: true,
+ sortable: false,
},
{
key: 'data',
label: 'Data',
- sortable: true,
+ sortable: false,
},
],
+ runtimeVersions: [],
+ palletsAndEvents: [],
+ selectedRuntimeVersion: null,
+ selectedPalletName: null,
+ selectedPalletEvent: null,
}
},
head() {
@@ -164,64 +235,244 @@ export default {
],
}
},
+ computed: {
+ runtimeSpecVersionOptions() {
+ const runtimeSpecVersionOptions = this.runtimeVersions.map(
+ (specVersion) => ({
+ value: specVersion.spec_version,
+ text: specVersion.spec_version,
+ })
+ )
+ return runtimeSpecVersionOptions
+ },
+ palletNameOptions() {
+ const palletNames = this.palletsAndEvents
+ .filter(({ events }) => events.length !== 0)
+ .map(({ name }) => name)
+ .sort()
+ .map((palletName) => ({
+ value: this.uncapitalize(palletName),
+ text: palletName,
+ }))
+ // console.log('modules:', palletNames)
+ return [{ value: null, text: 'All' }].concat(palletNames)
+ },
+ palletEventOptions() {
+ const vm = this
+ let palletEvents = []
+ if (this.selectedPalletName) {
+ const selectedPallet = this.palletsAndEvents.find(
+ ({ name }) => name === vm.capitalize(vm.selectedPalletName)
+ )
+ palletEvents = selectedPallet.events.sort().map((moduleEvent) => ({
+ value: moduleEvent,
+ text: moduleEvent,
+ }))
+ }
+ // console.log('events:', palletEvents)
+ return [{ value: null, text: 'All' }].concat(palletEvents)
+ },
+ },
methods: {
setPageSize(num) {
localStorage.paginationOptions = num
this.perPage = parseInt(num)
},
+ reloadQueries() {
+ this.$apollo.queries.event.refetch()
+ this.$apollo.queries.total.refetch()
+ this.$apollo.queries.event_aggregate.refetch()
+ this.$apollo.queries.spec_version.refetch()
+ this.$apollo.queries.runtime.refetch()
+ },
},
apollo: {
- $subscribe: {
- event: {
- query: gql`
- subscription events(
- $blockNumber: bigint
- $perPage: Int!
- $offset: Int!
- ) {
- event(
- limit: $perPage
- offset: $offset
- where: { block_number: { _eq: $blockNumber } }
- order_by: { block_number: desc, event_index: desc }
- ) {
- block_number
- event_index
- data
- method
- phase
- section
+ event: {
+ query: gql`
+ query events(
+ $blockNumber: bigint
+ $section: String
+ $method: String
+ $perPage: Int!
+ $offset: Int!
+ ) {
+ event(
+ limit: $perPage
+ offset: $offset
+ where: {
+ block_number: { _eq: $blockNumber }
+ section: { _eq: $section }
+ method: { _eq: $method }
}
+ order_by: { block_number: desc, event_index: desc }
+ ) {
+ block_number
+ event_index
+ data
+ method
+ phase
+ section
+ timestamp
}
- `,
- variables() {
- return {
- blockNumber: this.filter ? parseInt(this.filter) : undefined,
- perPage: this.perPage,
- offset: (this.currentPage - 1) * this.perPage,
- }
- },
- result({ data }) {
- this.events = data.event
- if (this.filter) {
- this.totalRows = this.events.length
+ }
+ `,
+ variables() {
+ return {
+ blockNumber: this.filter ? parseInt(this.filter) : undefined,
+ section: this.selectedPalletName
+ ? this.selectedPalletName
+ : undefined,
+ method: this.selectedPalletEvent
+ ? this.selectedPalletEvent
+ : undefined,
+ perPage: this.perPage,
+ offset: (this.currentPage - 1) * this.perPage,
+ }
+ },
+ result({ data }) {
+ this.events = data.event
+ },
+ },
+ total: {
+ query: gql`
+ query total {
+ total(where: { name: { _eq: "events" } }, limit: 1) {
+ count
}
- this.loading = false
- },
+ }
+ `,
+ variables() {
+ // not needed in query, but we want the query to be
+ // realoded if some variable change its value
+ return {
+ blockNumber: this.filter ? parseInt(this.filter) : undefined,
+ section: this.selectedPalletName
+ ? this.selectedPalletName
+ : undefined,
+ method: this.selectedPalletEvent
+ ? this.selectedPalletEvent
+ : undefined,
+ }
+ },
+ result({ data }) {
+ if (
+ this.filter === '' &&
+ this.selectedPalletName === null &&
+ this.selectedPalletEvent === null
+ ) {
+ this.totalRows = data.total[0].count
+ }
},
- totalEvents: {
- query: gql`
- subscription total {
- total(where: { name: { _eq: "events" } }, limit: 1) {
+ },
+ event_aggregate: {
+ query: gql`
+ query events($blockNumber: bigint, $section: String, $method: String) {
+ event_aggregate(
+ where: {
+ block_number: { _eq: $blockNumber }
+ section: { _eq: $section }
+ method: { _eq: $method }
+ }
+ ) {
+ aggregate {
count
}
}
- `,
- result({ data }) {
- if (!this.filter) {
- this.totalRows = data.total[0].count
+ }
+ `,
+ variables() {
+ return {
+ blockNumber: this.filter ? parseInt(this.filter) : undefined,
+ section: this.selectedPalletName
+ ? this.selectedPalletName
+ : undefined,
+ method: this.selectedPalletEvent
+ ? this.selectedPalletEvent
+ : undefined,
+ }
+ },
+ result({ data }) {
+ if (
+ this.filter !== '' ||
+ this.selectedPalletName !== null ||
+ this.selectedPalletEvent !== null
+ ) {
+ this.totalRows = data.event_aggregate.aggregate.count
+ }
+ },
+ },
+ spec_version: {
+ query: gql`
+ query runtime {
+ spec_version: runtime(order_by: { block_number: desc }) {
+ spec_version
}
- },
+ }
+ `,
+ result({ data }) {
+ this.runtimeVersions = data.spec_version
+ this.selectedRuntimeVersion = data.spec_version[0].spec_version
+ // console.log('runtime specs:', this.runtimeVersions)
+ },
+ },
+ runtime: {
+ query: gql`
+ query runtime($specVersion: Int!) {
+ runtime(where: { spec_version: { _eq: $specVersion } }, limit: 1) {
+ metadata_version
+ metadata
+ }
+ }
+ `,
+ skip() {
+ return this.runtimeVersions.length === 0
+ },
+ variables() {
+ return {
+ specVersion: this.selectedRuntimeVersion,
+ }
+ },
+ result({ data }) {
+ // get pallets and events from runtime metadata
+ const metadataVersion = data.runtime[0].metadata_version
+ this.metadata = data.runtime[0].metadata[metadataVersion]
+ const palletsAndEvents = []
+ if (metadataVersion !== 'v14') {
+ this.metadata.modules.forEach((module) => {
+ const palletAndEvents = {
+ name: module.name,
+ events:
+ module.events !== null
+ ? module.events.map((event) => event.name)
+ : [],
+ }
+ palletsAndEvents.push(palletAndEvents)
+ })
+ } else {
+ this.metadata.pallets.forEach((pallet) => {
+ const eventsId = pallet.events?.type || null
+ const events = []
+ const palletAndEvents = {
+ name: pallet.name,
+ eventsId,
+ events,
+ }
+ if (eventsId) {
+ this.metadata.lookup.types
+ .filter(
+ ({ id, type }) =>
+ type.path.includes('Event') && id === eventsId
+ )
+ .forEach(({ type }) => {
+ type.def.variant.variants.forEach((variant) => {
+ palletAndEvents.events.push(variant.name.toString())
+ })
+ })
+ }
+ palletsAndEvents.push(palletAndEvents)
+ })
+ }
+ this.palletsAndEvents = palletsAndEvents
},
},
},
diff --git a/frontend/pages/extrinsics.vue b/frontend/pages/extrinsics.vue
index a48ec8ba..ab1fda15 100644
--- a/frontend/pages/extrinsics.vue
+++ b/frontend/pages/extrinsics.vue
@@ -6,36 +6,85 @@
{{ $t('pages.extrinsics.title') }}
- [{{ formatNumber(totalRows) }}]
+
+ [{{ formatNumber(totalRows) }}]
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+ runtime
+
+
+
+
+
+ pallet
+
+
+
+
+
+ extrinsic
+
+
+
+
+
+
+
+
+
{{ data.item.block_number }}-{{
data.item.extrinsic_index
@@ -46,6 +95,11 @@
{{ shortHash(data.item.hash) }}
+
+
+ {{ fromNow(data.item.timestamp) }}
+
+
{{ data.item.section }} ➡
@@ -95,7 +149,7 @@
{{ option }}
@@ -133,7 +187,6 @@ export default {
mixins: [commonMixin],
data() {
return {
- loading: true,
filter: '',
extrinsics: [],
paginationOptions,
@@ -145,25 +198,35 @@ export default {
fields: [
{
key: 'block_number',
- label: 'Extrinsic',
- sortable: true,
+ label: this.$t('pages.extrinsics.id'),
+ sortable: false,
+ },
+ {
+ key: 'timestamp',
+ label: this.$t('pages.extrinsics.timestamp'),
+ sortable: false,
},
{
key: 'hash',
- label: 'Hash',
- sortable: true,
+ label: this.$t('pages.extrinsics.hash'),
+ sortable: false,
},
{
key: 'section',
- label: 'Extrinsic',
- sortable: true,
+ label: this.$t('pages.extrinsics.extrinsic'),
+ sortable: false,
},
{
key: 'success',
- label: 'Success',
- sortable: true,
+ label: this.$t('pages.extrinsics.success'),
+ sortable: false,
},
],
+ runtimeVersions: [],
+ palletsAndExtrinsics: [],
+ selectedRuntimeVersion: null,
+ selectedPalletName: null,
+ selectedPalletExtrinsic: null,
}
},
head() {
@@ -182,66 +245,256 @@ export default {
],
}
},
+ computed: {
+ runtimeSpecVersionOptions() {
+ const runtimeSpecVersionOptions = this.runtimeVersions.map(
+ (specVersion) => ({
+ value: specVersion.spec_version,
+ text: specVersion.spec_version,
+ })
+ )
+ return runtimeSpecVersionOptions
+ },
+ palletNameOptions() {
+ const palletNames = this.palletsAndExtrinsics
+ .filter(({ calls }) => calls.length !== 0)
+ .map(({ name }) => name)
+ .sort()
+ .map((palletName) => ({
+ value: this.uncapitalize(palletName),
+ text: palletName,
+ }))
+ // console.log('modules:', palletNames)
+ return [{ value: null, text: 'All' }].concat(palletNames)
+ },
+ palletExtrinsicsOptions() {
+ const vm = this
+ let palletExtrinsics = []
+ if (this.selectedPalletName) {
+ const selectedPallet = this.palletsAndExtrinsics.find(
+ ({ name }) => name === vm.capitalize(vm.selectedPalletName)
+ )
+ palletExtrinsics = selectedPallet.calls
+ .sort()
+ .map((moduleExtrinsic) => ({
+ value: this.snakeToCamel(moduleExtrinsic),
+ text: this.snakeToCamel(moduleExtrinsic),
+ }))
+ }
+ // console.log('extrinsics:', palletExtrinsics)
+ return [{ value: null, text: 'All' }].concat(palletExtrinsics)
+ },
+ },
methods: {
setPageSize(num) {
localStorage.paginationOptions = num
this.perPage = parseInt(num)
},
+ reloadQueries() {
+ this.$apollo.queries.extrinsic.refetch()
+ this.$apollo.queries.total.refetch()
+ this.$apollo.queries.extrinsic_aggregate.refetch()
+ this.$apollo.queries.spec_version.refetch()
+ this.$apollo.queries.runtime.refetch()
+ },
},
apollo: {
- $subscribe: {
- extrinsic: {
- query: gql`
- subscription extrinsics(
- $blockNumber: bigint
- $perPage: Int!
- $offset: Int!
- ) {
- extrinsic(
- limit: $perPage
- offset: $offset
- where: { block_number: { _eq: $blockNumber } }
- order_by: { block_number: desc, extrinsic_index: desc }
- ) {
- block_number
- extrinsic_index
- is_signed
- signer
- section
- method
- hash
- success
+ extrinsic: {
+ query: gql`
+ query extrinsics(
+ $blockNumber: bigint
+ $section: String
+ $method: String
+ $perPage: Int!
+ $offset: Int!
+ ) {
+ extrinsic(
+ limit: $perPage
+ offset: $offset
+ where: {
+ block_number: { _eq: $blockNumber }
+ section: { _eq: $section }
+ method: { _eq: $method }
}
+ order_by: { block_number: desc, extrinsic_index: desc }
+ ) {
+ block_number
+ extrinsic_index
+ is_signed
+ signer
+ section
+ method
+ hash
+ success
+ timestamp
}
- `,
- variables() {
- return {
- blockNumber: this.filter ? parseInt(this.filter) : undefined,
- perPage: this.perPage,
- offset: (this.currentPage - 1) * this.perPage,
- }
- },
- result({ data }) {
- this.extrinsics = data.extrinsic
- if (this.filter) {
- this.totalRows = this.extrinsics.length
+ }
+ `,
+ variables() {
+ return {
+ blockNumber: this.filter ? parseInt(this.filter) : undefined,
+ section: this.selectedPalletName
+ ? this.selectedPalletName
+ : undefined,
+ method: this.selectedPalletExtrinsic
+ ? this.selectedPalletExtrinsic
+ : undefined,
+ perPage: this.perPage,
+ offset: (this.currentPage - 1) * this.perPage,
+ }
+ },
+ result({ data }) {
+ this.extrinsics = data.extrinsic
+ if (this.filter) {
+ this.totalRows = this.extrinsics.length
+ }
+ },
+ },
+ total: {
+ query: gql`
+ query total {
+ total(where: { name: { _eq: "extrinsics" } }, limit: 1) {
+ count
}
- this.loading = false
- },
+ }
+ `,
+ variables() {
+ return {
+ blockNumber: this.filter ? parseInt(this.filter) : undefined,
+ section: this.selectedPalletName
+ ? this.selectedPalletName
+ : undefined,
+ method: this.selectedPalletExtrinsic
+ ? this.selectedPalletExtrinsic
+ : undefined,
+ }
+ },
+ result({ data }) {
+ if (
+ this.filter === '' &&
+ this.selectedPalletName === null &&
+ this.selectedPalletExtrinsic === null
+ ) {
+ this.totalRows = data.total[0].count
+ }
},
- totalExtrinsics: {
- query: gql`
- subscription total {
- total(where: { name: { _eq: "extrinsics" } }, limit: 1) {
+ },
+ extrinsic_aggregate: {
+ query: gql`
+ query extrinsics(
+ $blockNumber: bigint
+ $section: String
+ $method: String
+ ) {
+ extrinsic_aggregate(
+ where: {
+ block_number: { _eq: $blockNumber }
+ section: { _eq: $section }
+ method: { _eq: $method }
+ }
+ ) {
+ aggregate {
count
}
}
- `,
- result({ data }) {
- if (!this.filter) {
- this.totalRows = data.total[0].count
+ }
+ `,
+ variables() {
+ return {
+ blockNumber: this.filter ? parseInt(this.filter) : undefined,
+ section: this.selectedPalletName
+ ? this.selectedPalletName
+ : undefined,
+ method: this.selectedPalletExtrinsic
+ ? this.selectedPalletExtrinsic
+ : undefined,
+ }
+ },
+ result({ data }) {
+ if (
+ this.filter !== '' ||
+ this.selectedPalletName !== null ||
+ this.selectedPalletExtrinsic !== null
+ ) {
+ this.totalRows = data.extrinsic_aggregate.aggregate.count
+ }
+ },
+ },
+ spec_version: {
+ query: gql`
+ query runtime {
+ spec_version: runtime(order_by: { block_number: desc }) {
+ spec_version
}
- },
+ }
+ `,
+ result({ data }) {
+ this.runtimeVersions = data.spec_version
+ this.selectedRuntimeVersion = data.spec_version[0].spec_version
+ // console.log('runtime specs:', this.runtimeVersions)
+ },
+ },
+ runtime: {
+ query: gql`
+ query runtime($specVersion: Int!) {
+ runtime(where: { spec_version: { _eq: $specVersion } }, limit: 1) {
+ metadata_version
+ metadata
+ }
+ }
+ `,
+ skip() {
+ return this.runtimeVersions.length === 0
+ },
+ variables() {
+ return {
+ specVersion: this.selectedRuntimeVersion,
+ }
+ },
+ result({ data }) {
+ // get pallets and extrinsics from runtime metadata
+ const metadataVersion = data.runtime[0].metadata_version
+ this.metadata = data.runtime[0].metadata[metadataVersion]
+ const palletsAndExtrinsics = []
+ if (metadataVersion !== 'v14') {
+ this.metadata.modules.forEach((module) => {
+ const palletAndExtrinsics = {
+ name: module.name,
+ calls:
+ module.calls !== null
+ ? module.calls.map((call) => call.name)
+ : [],
+ }
+ palletsAndExtrinsics.push(palletAndExtrinsics)
+ })
+ } else {
+ this.metadata.pallets.forEach((pallet) => {
+ const callsId = pallet.calls?.type || null
+ const calls = []
+ const palletAndExtrinsics = {
+ name: pallet.name,
+ callsId,
+ calls,
+ }
+ if (callsId) {
+ this.metadata.lookup.types
+ .filter(
+ ({ id, type }) => type.path.includes('Call') && id === callsId
+ )
+ .forEach(({ type }) => {
+ type.def.variant.variants.forEach((variant) => {
+ palletAndExtrinsics.calls.push(variant.name.toString())
+ })
+ })
+ }
+ palletsAndExtrinsics.push(palletAndExtrinsics)
+ })
+ }
+ // console.log(
+ // 'palletsAndExtrinsics:',
+ // JSON.stringify(palletsAndExtrinsics, null, 2)
+ // )
+ this.palletsAndExtrinsics = palletsAndExtrinsics
},
},
},