Skip to content

Commit d8596a6

Browse files
authored
v0.5.0
v0.5.0
2 parents 8a16a16 + b1cd833 commit d8596a6

82 files changed

Lines changed: 3717 additions & 2828 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release.yml

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,11 @@ jobs:
115115
username: ${{ github.actor }}
116116
password: ${{ secrets.GITHUB_TOKEN }}
117117

118-
- name: Build and push Docker image
118+
- name: Build and push Docker Indexer image
119119
uses: docker/build-push-action@v5
120120
with:
121121
context: .
122+
file: Dockerfile
122123
push: true
123124
platforms: linux/amd64
124125
tags: |
@@ -130,4 +131,22 @@ jobs:
130131
GIT_TAG=${{ steps.gitmeta.outputs.git_tag }}
131132
GIT_BRANCH=${{ steps.gitmeta.outputs.git_branch }}
132133
cache-from: type=gha
134+
cache-to: type=gha,mode=max
135+
136+
- name: Build and push Docker API image
137+
uses: docker/build-push-action@v5
138+
with:
139+
context: .
140+
file: Dockerfile-api
141+
push: true
142+
platforms: linux/amd64
143+
tags: |
144+
ghcr.io/cogwheel-validator/spectra-gnoland-api:${{ steps.version.outputs.version }}
145+
ghcr.io/cogwheel-validator/spectra-gnoland-api:${{ steps.version.outputs.docker_tag }}
146+
build-args: |
147+
VERSION=${{ steps.version.outputs.version }}
148+
GIT_COMMIT=${{ steps.gitmeta.outputs.git_commit }}
149+
GIT_TAG=${{ steps.gitmeta.outputs.git_tag }}
150+
GIT_BRANCH=${{ steps.gitmeta.outputs.git_branch }}
151+
cache-from: type=gha
133152
cache-to: type=gha,mode=max

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ config.yml
3838
test_config.yml
3939
.env
4040
config-api.yml
41+
training-config.yml
4142

4243
# State dumps and diagnostics directories
4344
state_dumps/
@@ -48,4 +49,8 @@ server.crt
4849
server.key
4950

5051
# Jet Brains
51-
.idea/
52+
.idea/
53+
54+
# Docker
55+
.dockerignore
56+
docker-compose-local.yml

Dockerfile

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.25.4-trixie AS builder
1+
FROM golang:1.25 AS builder
22

33
WORKDIR /app
44

@@ -14,14 +14,18 @@ RUN if [ -z "$VERSION" ]; then \
1414
else VERSION="${GIT_BRANCH}-${GIT_COMMIT}"; \
1515
fi; \
1616
fi && \
17-
go build -ldflags="-X 'github.com/Cogwheel-Validator/spectra-gnoland-indexer/indexer/cmd.Commit=${GIT_COMMIT}' -X 'github.com/Cogwheel-Validator/spectra-gnoland-indexer/indexer/cmd.Version=${VERSION}'" -o indexer ./indexer
17+
go build -ldflags="-s -w -X 'github.com/Cogwheel-Validator/spectra-gnoland-indexer/indexer/cmd.Commit=${GIT_COMMIT}' -X 'github.com/Cogwheel-Validator/spectra-gnoland-indexer/indexer/cmd.Version=${VERSION}'" -o indexer ./indexer
1818

1919
RUN chmod +x indexer
20+
RUN touch config.yml
2021

21-
FROM debian:trixie-slim
22+
FROM gcr.io/distroless/base-debian13:latest
2223

2324
WORKDIR /app
2425

25-
COPY --from=builder /app/indexer /app/indexer
26+
COPY --from=builder /app/indexer .
27+
COPY --from=builder --chown=nonroot:nonroot /app/config.yml .
28+
29+
USER nonroot
2630

2731
ENTRYPOINT ["/app/indexer"]

Dockerfile-api

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
FROM golang:1.25 AS builder
2+
3+
WORKDIR /app
4+
5+
COPY . .
6+
7+
ARG GIT_COMMIT=""
8+
ARG GIT_TAG=""
9+
ARG GIT_BRANCH=""
10+
ARG VERSION=""
11+
12+
RUN if [ -z "$VERSION" ]; then \
13+
if [ -n "$GIT_TAG" ]; then VERSION="$GIT_TAG"; \
14+
else VERSION="${GIT_BRANCH}-${GIT_COMMIT}"; \
15+
fi; \
16+
fi && \
17+
go build -ldflags="-s -w -X main.Commit=${GIT_COMMIT} -X main.Version=${VERSION}" -o build/api ./api
18+
19+
RUN touch config-api.yml
20+
RUN chmod +x build/api
21+
22+
FROM gcr.io/distroless/base-debian13:latest
23+
WORKDIR /app
24+
25+
COPY --from=builder --chown=nonroot:nonroot /app/build/api .
26+
COPY --from=builder --chown=nonroot:nonroot /app/config-api.yml .
27+
28+
USER nonroot
29+
30+
ENTRYPOINT ["/app/api"]

Makefile

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
.PHONY: build install clean build-experimental install-experimental build-api test-race integration-test test
1+
.PHONY: build
2+
install
3+
clean
4+
build-experimental
5+
install-experimental
6+
build-api
7+
integration-test
8+
test
9+
vulnerability-scan
10+
snyk
11+
semgrep
12+
code-quality
213

314
########################################################
415
# Build and install the indexer
@@ -37,8 +48,37 @@ build-experimental:
3748
test:
3849
go test -v ./...
3950

40-
test-race:
41-
go test -v -race ./...
42-
4351
integration-test:
44-
cd integration && go test -v -tags=integration -timeout=20m ./...
52+
cd integration && go test -v -tags=integration -timeout=20m ./...
53+
54+
########################################################
55+
# Vulnerability scanning
56+
########################################################
57+
58+
vulnerability-scan:
59+
govulncheck ./...
60+
61+
snyk:
62+
snyk test
63+
64+
semgrep:
65+
semgrep ci
66+
67+
########################################################
68+
# Code quality
69+
########################################################
70+
71+
code-quality:
72+
golangci-lint run
73+
74+
########################################################
75+
# Train the zstd dictionary
76+
########################################################
77+
78+
.PHONY: train-zstd
79+
80+
train-zstd:
81+
@echo "Training the zstd dictionary"
82+
@read -p "Enter the amount of events to collect (default: 10000): " amount; \
83+
amount=$${amount:-10000}; \
84+
go run compression/cmd/main.go --config training-config.yml --amount $$amount --chain-name gnoland --dict-path ./pkgs/dict_loader/events.zstd.bin

README.md

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,99 +4,109 @@
44
</div>
55
<p align="center" style="font-style: italic;">This project is still in development. Future releases might have some breaking changes.</p>
66

7-
The Spectra Gnoland Indexer(SGI) is a tool that records the data from the Gnoland blockchain and stores the data
8-
in the timeseries database, Timescale DB. This indexer will be a part of the Spectra explorer and will be used to
7+
The Spectra Gnoland Indexer(SGI) is a tool that records the data from the Gnoland blockchain and stores the data
8+
in the timeseries database, Timescale DB. This indexer will be a part of the Spectra explorer and will be used to
99
store the data for the explorer. This program can be used for any kind of data/analytics program or app.
1010

11-
The biggest problem when dealing with the blockchain data is how to store the data in a way that is easy to query
12-
and analyze. Some projects rely on the direct access to the data from the blockchain nodes and the problem in this
13-
case is that the nodes are meant for multiple purposes.
11+
The biggest problem when dealing with the blockchain data is how to store the data in a way that is easy to query
12+
and analyze. Some projects rely on the direct access to the data from the blockchain nodes and the problem in this
13+
case is that the nodes are meant for multiple purposes.
1414

15-
They usually provide at least one, sometimes even more, endpoints for querying the data, then this node need to be
16-
able to work with other nodes and to acquire the block data from other nodes via P2P network. Most nodes can be
15+
They usually provide at least one, sometimes even more, endpoints for querying the data, then this node need to be
16+
able to work with other nodes and to acquire the block data from other nodes via P2P network. Most nodes can be
1717
used as a miners/validators that need to sign the blocks. Even if these nodes are only to be used as a RPC nodes
18-
they can still provide the data but depending on the underlying SDK, tech stack and other factors it might be
18+
they can still provide the data but depending on the underlying SDK, tech stack and other factors it might be
1919
not the best choice. And finally the nodes are not the best when it comes to storing the data and scalability.
2020

2121
## Table of content
22+
2223
- [Table of content](#table-of-content)
2324
- [The solution](#the-solution)
2425
- [Why TimescaleDB? And can it work on other SQL databases?](#why-timescaledb-and-can-it-work-on-other-sql-databases)
2526
- [How does the indexer work?](#how-does-the-indexer-work)
2627
- [What data is stored in the database?](#what-data-is-stored-in-the-database)
27-
- [Blocks:](#blocks)
28-
- [Validator signings:](#validator-signings)
29-
- [Transactions:](#transactions)
28+
- [Blocks](#blocks)
29+
- [Validator signings](#validator-signings)
30+
- [Transactions](#transactions)
3031
- [Pros and cons of the SGI](#pros-and-cons-of-the-sgi)
31-
- [🦾 Pros:](#-pros)
32-
- [🐞 Cons:](#-cons)
32+
- [🦾 Pros](#-pros)
33+
- [🐞 Cons](#-cons)
3334
- [In depth documentation](#in-depth-documentation)
3435

3536
## The solution
3637

37-
The data in the blockchain is mostly tied to blocks, however when any kind of analytics is needed we need some
38+
The data in the blockchain is mostly tied to blocks, however when any kind of analytics is needed we need some
3839
parameter that falls familiar to us from the daily life. So it comes more natural to compare the data with some
39-
sort of time parameter then to a block height. Then the data needs to be stored in a way that is easy to query and
40-
analyze. And since we are dealing with the time parameter, we need to have the ability to aggregate the data over
40+
sort of time parameter then to a block height. Then the data needs to be stored in a way that is easy to query and
41+
analyze. And since we are dealing with the time parameter, we need to have the ability to aggregate the data over
4142
some time period so we can timeseries and easily plot the data.
4243

43-
A lot of indexers use NoSQL databases for this use case. However they usually have their own problems and
44+
A lot of indexers use NoSQL databases for this use case. However they usually have their own problems and
4445
limitations. They are not as flexible as the SQL databases when it comes to the data types and the query language.
4546
that is the reason why the TimescaleDB is a perfect fit for this use case.
4647

4748
Anyone with some experience with the SQL, especially with the PostgreSQL, can easily understand the TimescaleDB.
48-
It is a extension of the PostgreSQL that adds the ability to store the time series data in a way that is easy to
49+
It is a extension of the PostgreSQL that adds the ability to store the time series data in a way that is easy to
4950
query and analyze.
5051

5152
## Why TimescaleDB? And can it work on other SQL databases?
5253

53-
TimescaleDB (Tiger Data is their commercial version) is a extension of the PostgreSQL that adds the ability to
54-
store the time series data in a way that is easy to query and analyze. It also has a lot of features that can
54+
TimescaleDB (Tiger Data is their commercial version) is a extension of the PostgreSQL that adds the ability to
55+
store the time series data in a way that is easy to query and analyze. It also has a lot of features that can
5556
extend the capabilities of the PostgreSQL and make it more powerful.
5657

58+
The TimescaleDB sits between the OLTP and the OLAP databases. It is a hybrid database that can be used for both.
59+
It is a good fit for the time series data and it is a good fit for the analytics and the exploration of the data.
60+
5761
The TimescaleDB has also feature of it's own that is not present in the Postgres. The user could extend the indexer
5862
by adding the data aggregation features, automatic jobs scheduling, hyperfunctions and more.
5963

60-
This database extension also has a data compression feature that can be used to reduce the storage space and
64+
This database extension also has a data compression feature that can be used to reduce the storage space and
6165
segment the data into smaller chunks by using time based intervals making the queries faster.
6266

63-
Technically speaking the indexer can work on Postgres database, however you would need to create the tables and
64-
types manually. This might be added later in the future if there is a demand for it but for now the focus is on the
67+
Technically speaking the indexer can work on Postgres database, however you would need to create the tables and
68+
types manually. This might be added later in the future if there is a demand for it but for now the focus is on the
6569
TimescaleDB.
6670

6771
There are some other SQL databases that could work in theory. For them to work they would need to have:
72+
6873
- The postgres wire protocol
6974
- Equivalent of Numeric type ( some databases might have it as DECIMAL, but not all of them )
7075
- The ability to create custom types
7176

72-
If all of the above are met then the indexer can work on them. It might work on CockroachDB for example but this is
77+
If all of the above are met then the indexer can work on them. It might work on CockroachDB for example but this is
7378
out of the scope of this project. Maybe in the future it might be an interesting idea to support it.
7479

7580
## How does the indexer work?
7681

7782
The indexer has 2 main modes of operation:
83+
7884
- Live mode
7985
- Historic mode
8086

81-
Live mode is the mode that is used to index the data in the real time. It will sync up the database to the latest
82-
block height and will continue to index the data in the real time.
87+
Live mode is the mode that is used to index the data in the real time. It will sync up the database to the latest
88+
block height and will continue to index the data in the real time. It works by using near-real-time batch processing method. It will collect all of the data up to the latest block height and then it will process it in
89+
batches. So the process is not instant but it is very fast and it is able to keep up with the latest block height.
8390

84-
Historic mode is the mode that allows the user to index a certain range of blocks. For example you might not need
85-
the whole chain history or just need a part of it. This mode is useful for the testing, partial indexing of the
91+
Historic mode is the mode that allows the user to index a certain range of blocks. For example you might not need
92+
the whole chain history or just need a part of it. This mode is useful for the testing, partial indexing of the
8693
chain or gradual indexing of the chain.
8794

88-
Durring both modes the indexer will use fan out method to send the requests to the RPC node. Then all of the data
89-
is collected and processed and decoded in parallel. All of the addresses are collected and stored in the database
90-
and the indexer stores them in it's own cache. Then any address that is found in the transaction is referanced by
91-
the integer value in the transaction tables. At the end of the processing the data is inserted in batches into the
95+
During both modes the indexer will use fan out method to send the requests to the RPC node. Then all of the data
96+
is collected and processed and decoded in parallel. All of the addresses are collected and stored in the database
97+
and the indexer stores them in it's own cache. Then any address that is found in the transaction is referenced by
98+
the integer value in the transaction tables. At the end of the processing the data is inserted in batches into the
9299
database.
93100

94101
## What data is stored in the database?
95102

96-
The indexer stores the esential data that is related to the blocks, transactions, messages, and accounts.
103+
The indexer stores the essential data that is related to the blocks, transactions, messages, and accounts.
97104
It also stores the validator block signings and the validator addresses.
98-
This way it is able to provide a lot of data for the analytics and the explorer.
105+
The data schema is denormalized to decrease the space needed and to provide the easy and fast access for the
106+
explorer and any other visualizations and analytics tools.
107+
99108
The data is stored in the following tables:
109+
100110
- blocks
101111
- transactions general data
102112
- transaction messages (each message type has its own table)
@@ -107,8 +117,10 @@ The data is stored in the following tables:
107117

108118
Some of the data is not indexed and it is not planned to be indexed in the future. Such as:
109119

110-
### Blocks:
120+
### Blocks
121+
111122
Stored data:
123+
112124
- Basic block hash
113125
- Block height
114126
- Block timestamp
@@ -117,47 +129,52 @@ Stored data:
117129
- Block transactions hashes
118130

119131
Not stored:
132+
120133
- Last commit hash
121134
- App hash
122135
- Data hash
123136
- Validators hash
124137
- Next validators hash
125138
- Consensus hash
126139

127-
### Validator signings:
140+
### Validator signings
141+
128142
Stored data:
143+
129144
- Validator block signing height
130145
- Validator block signing timestamp
131146
- Validator block signing signed validators
132147
- Proposer address
133148

134149
Not stored:
150+
135151
- Missed validators
136152
- Precommits and all of the hashes and other data, so only a confirmation that the validator signed the block
137153

138-
### Transactions:
139-
Almost all of the data regarding to the transaction and the messages are stored with the exception for the
154+
### Transactions
155+
156+
Almost all of the data regarding to the transaction and the messages are stored with the exception for the
140157
VM message Add Package and Call where in theory one could extract even the body of the smart contract. So this is unnecessary to store for explorers and other analytics tools. This might be added in the future if there is a demand for it.
141158

142159
## Pros and cons of the SGI
143160

144-
### 🦾 Pros:
161+
### 🦾 Pros
145162

146163
- The indexer process the data using goroutines and channels, which can provide a faster processing of the data.
147164
- Fast data processing. [see benchmarks](./docs/benchmarks.md)
148165
- The program has 2 modes that can be used for the indexing of the data. This can be useful for the testing, partial indexing of the chain or gradual indexing of the chain.
149166
- The data is stored ready to be used for any kind of analytics and visualization with any programming language.
150-
- No need to deal with Amino encoding and decoding for the messagess as the indexer decodes the messages and stores them in the database.
167+
- No need to deal with Amino encoding and decoding for the messages as the indexer decodes the messages and stores them in the database.
151168
- It comes with a REST API to get you started quickly.
152169
- It relies on a SQL database, which can provide a easier experience for any user that is familiar with the SQL.
153-
- It uses TimescaleDB, a PostgresSQL extenstion that can be extended with any other extensions, plus the TimescaleDB has a lot of features that are not present in the Postgres.
170+
- It uses TimescaleDB, a PostgresSQL extension that can be extended with any other extensions, plus the TimescaleDB has a lot of features that are not present in the Postgres.
154171

155-
### 🐞 Cons:
172+
### 🐞 Cons
156173

157-
- The indexer has a address cache of all of the addresses that were ever used in the transactions. This gives the indexer ability to swap the addresses with the their integer index in the database. However this intorduces complexity. Anyone who plans to use the indexer and plans to make some custom solution on working with the data will need to fully understand the data structure and how to use it. The REST API provides a easy way to interact with the data and to get the data in a readable format.
174+
- The indexer has a address cache of all of the addresses that were ever used in the transactions. This gives the indexer ability to swap the addresses with the their integer index in the database. However this introduces complexity. Anyone who plans to use the indexer and plans to make some custom solution on working with the data will need to fully understand the data structure and how to use it. The REST API provides a easy way to interact with the data and to get the data in a readable format.
158175
- The indexer relies on the RPC node for the data. If the RPC node is not available the indexer will not be able to index the data. ( although in the future the indexer might be able to use multiple RPC nodes )
159176
- Technically the indexer has a limit of 2 billion addresses. If at any point the Gnoland grows to that size the indexer would need to be updated to support it. It is not a problem for now but it is something to keep in mind.
160177

161178
## In depth documentation
162179

163-
For more detailed documentation, please refer to the [docs](./docs/README.md) directory.
180+
For more detailed documentation, please refer to the [docs](./docs/README.md) directory.

0 commit comments

Comments
 (0)