Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: init command support for starknet #455

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
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
76 changes: 76 additions & 0 deletions cmd/substreams/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var (
devInitProtocol = os.Getenv("SUBSTREAMS_DEV_INIT_PROTOCOL")
devInitEthereumTrackedContract = os.Getenv("SUBSTREAMS_DEV_INIT_ETHEREUM_TRACKED_CONTRACT")
devInitEthereumChain = os.Getenv("SUBSTREAMS_DEV_INIT_ETHEREUM_CHAIN")
devInitStarknetChain = os.Getenv("SUBSTREAMS_DEV_INIT_STARKNET_CHAIN")
)

var errInitUnsupportedChain = errors.New("unsupported chain")
Expand Down Expand Up @@ -173,6 +174,43 @@ func runSubstreamsInitE(cmd *cobra.Command, args []string) error {
return fmt.Errorf("render Ethereum %s project: %w", chain.DisplayName, err)
}

case codegen.ProtocolStarknet:
chainSelected, err := promptStarknetChain()
if err != nil {
return fmt.Errorf("running chain prompt: %w", err)
}
if chainSelected == codegen.StarknetChainOther {
fmt.Println()
fmt.Println("We haven't added any templates for your selected chain quite yet")
fmt.Println()
fmt.Println("Come join us in discord at https://discord.gg/u8amUbGBgF and suggest templates/chains you want to see!")
fmt.Println()
return errInitUnsupportedChain
}

// Since Starknet contract ABI decoding has not been implemented yet, for any chain selected we
// would simply generate a template that collects block information. Unlike with Ethereum, We
// don't need to prompt users for any additional info here.

chain := templates.StarknetChainsByID[chainSelected.String()]
if chain == nil {
return fmt.Errorf("unknown chain: %s", chainSelected.String())
}

fmt.Println("Writing project files")
project, err := templates.NewStarknetProject(
projectName,
moduleName,
chain,
)
if err != nil {
return fmt.Errorf("new Starknet %s project: %w", chain.DisplayName, err)
}

if err := renderProjectFilesIn(project, absoluteProjectDir); err != nil {
return fmt.Errorf("render Starknet %s project: %w", chain.DisplayName, err)
}

case codegen.ProtocolOther:
fmt.Println()
fmt.Println("We haven't added any templates for your selected protocol quite yet")
Expand Down Expand Up @@ -579,6 +617,44 @@ func promptEthereumChain() (codegen.EthereumChain, error) {
return chain, nil
}

func promptStarknetChain() (codegen.StarknetChain, error) {
if devInitStarknetChain != "" {
// It's ok to panic, we expect the dev to put in a valid Starknet chain
chain, err := codegen.ParseStarknetChain(devInitStarknetChain)
if err != nil {
panic(fmt.Errorf("invalid chain: %w", err))
}

return chain, nil
}

choice := promptui.Select{
Label: "Select Starknet chain",
Items: codegen.StarknetChainNames(),
Templates: &promptui.SelectTemplates{
Selected: `{{ "Starknet chain:" | faint }} {{ . }}`,
},
HideHelp: true,
}

_, selection, err := choice.Run()
if err != nil {
if errors.Is(err, promptui.ErrInterrupt) {
// We received Ctrl-C, users wants to abort, nothing else to do, quit immediately
os.Exit(1)
}

return codegen.StarknetChainOther, fmt.Errorf("running chain prompt: %w", err)
}

var chain codegen.StarknetChain
if err := chain.UnmarshalText([]byte(selection)); err != nil {
panic(fmt.Errorf("impossible, selecting hard-coded value from enum itself, something is really wrong here"))
}

return chain, nil
}

type promptOptions struct {
Validate promptui.ValidateFunc
IsConfirm bool
Expand Down
1 change: 1 addition & 0 deletions codegen/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package codegen
// ENUM(
//
// Ethereum
// Starknet
// Other
//
// )
Expand Down
20 changes: 13 additions & 7 deletions codegen/protocol_enum.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions codegen/starknet_chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package codegen

//go:generate go-enum -f=$GOFILE --marshal --names --nocase

// ENUM(
//
// Mainnet
// Sepolia
// Other
//
// )
type StarknetChain uint
96 changes: 96 additions & 0 deletions codegen/starknet_chain_enum.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions codegen/templates/starknet/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/build/
/target/
buf.gen.yaml
*.spkg
21 changes: 21 additions & 0 deletions codegen/templates/starknet/Cargo.toml.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "{{ .name }}"
version = "0.0.1"
edition = "2021"

[lib]
name = "substreams"
crate-type = ["cdylib"]

[dependencies]
prost = "0.11"
prost-types = "0.11"
substreams = "0.5"
substreams-database-change = "1"
substreams-entity-change = "1"
substreams-starknet = "0.1"

[profile.release]
lto = true
opt-level = 's'
strip = "debuginfo"
26 changes: 26 additions & 0 deletions codegen/templates/starknet/Makefile.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
CARGO_VERSION := $(shell cargo version 2>/dev/null)

.PHONY: build
build:
ifdef CARGO_VERSION
cargo build --target wasm32-unknown-unknown --release
else
@echo "Building substreams target using Docker. To speed up this step, install a Rust development environment."
docker run --rm -ti --init -v ${PWD}:/usr/src --workdir /usr/src/ rust:bullseye cargo build --target wasm32-unknown-unknown --release
endif

.PHONY: run
run: build
substreams run substreams.yaml $(if $(MODULE),$(MODULE),map_blocks) $(if $(START_BLOCK),-s $(START_BLOCK)) $(if $(STOP_BLOCK),-t $(STOP_BLOCK))

.PHONY: gui
gui: build
substreams gui substreams.yaml $(if $(MODULE),$(MODULE),map_blocks) $(if $(START_BLOCK),-s $(START_BLOCK)) $(if $(STOP_BLOCK),-t $(STOP_BLOCK))

.PHONY: protogen
protogen:
substreams protogen ./substreams.yaml --exclude-paths="sf/substreams,google"

.PHONY: pack
pack: build
substreams pack substreams.yaml
14 changes: 14 additions & 0 deletions codegen/templates/starknet/proto/block.proto.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
syntax = "proto3";

import "google/protobuf/timestamp.proto";

package block.v1;

message Block {
uint64 height = 1;
bytes hash = 2;
bytes prev_hash = 3;
uint64 timestamp = 4;
uint64 tx_count = 5;
uint64 event_count = 6;
}
4 changes: 4 additions & 0 deletions codegen/templates/starknet/rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[toolchain]
channel = "1.77"
components = ["rustfmt"]
targets = ["wasm32-unknown-unknown"]
8 changes: 8 additions & 0 deletions codegen/templates/starknet/schema.clickhouse.sql.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS block (
"height" INT,
"hash" VARCHAR(64),
"prev_hash" VARCHAR(64),
"timestamp" INT,
"tx_count" INT,
"event_count" INT
) ENGINE = MergeTree PRIMARY KEY ("hash");
8 changes: 8 additions & 0 deletions codegen/templates/starknet/schema.graphql.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type Block @entity {
id: ID!
height: BigInt!
prev_hash: Bytes!
timestamp: BigInt!
tx_count: BigInt!
event_count: BigInt!
}
9 changes: 9 additions & 0 deletions codegen/templates/starknet/schema.sql.gotmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CREATE TABLE IF NOT EXISTS block (
"height" INT,
"hash" VARCHAR(64),
"prev_hash" VARCHAR(64),
"timestamp" INT,
"tx_count" INT,
"event_count" INT,
PRIMARY KEY(hash)
);
Loading