-
Notifications
You must be signed in to change notification settings - Fork 110
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
363 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
*.jar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Let's build a sidecar | ||
FROM golang:1.20 AS go-builder | ||
WORKDIR /opt/sidecar | ||
COPY ./sidecar.go . | ||
RUN go build -o /opt/sidecar/sidecar sidecar.go | ||
|
||
FROM openjdk:24-slim AS ton-node | ||
|
||
ARG WORKDIR="/opt/my-local-ton" | ||
|
||
# Install dependencies && drop apt cache | ||
RUN apt-get update \ | ||
&& apt-get install -y --no-install-recommends \ | ||
curl jq vim lsb-release \ | ||
&& rm -rf /var/lib/apt/lists/* | ||
|
||
COPY ./my-local-ton.jar $WORKDIR/ | ||
COPY ./entrypoint.sh $WORKDIR/ | ||
|
||
COPY --from=go-builder /opt/sidecar $WORKDIR/ | ||
|
||
WORKDIR $WORKDIR | ||
|
||
# Ensure whether the build works or not. | ||
RUN chmod +x entrypoint.sh && chmod +x sidecar \ | ||
&& java -jar my-local-ton.jar debug nogui test-binaries; | ||
|
||
# Lite Client | ||
EXPOSE 4443 | ||
|
||
# Sidecar | ||
EXPOSE 8000 | ||
|
||
ENTRYPOINT ["/opt/my-local-ton/entrypoint.sh"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
#!/bin/bash | ||
|
||
script_dir=$(cd -- "$(dirname -- "$0")" &> /dev/null && pwd) | ||
|
||
# Downloads JAR outside of the Dockerfile to avoid re-downloading it every time during rebuilds. | ||
jar_version="v120" | ||
jar_url="https://github.com/neodix42/MyLocalTon/releases/download/${jar_version}/MyLocalTon-x86-64.jar" | ||
jar_file="$script_dir/my-local-ton.jar" | ||
|
||
if [ -f "$jar_file" ]; then | ||
echo "File $jar_file already exists. Skipping download." | ||
exit 0 | ||
fi | ||
|
||
echo "File not found. Downloading..." | ||
echo "URL: $jar_url" | ||
wget -q --show-progress -O "$jar_file" "$jar_url" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#!/bin/bash | ||
|
||
java -jar my-local-ton.jar with-validators-1 nogui debug & | ||
|
||
./sidecar & | ||
|
||
# Wait for both processes to finish | ||
wait -n |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# TON localnet | ||
|
||
This docker image represents a fully working TON node with 1 validator and a faucet wallet. | ||
|
||
## How it works | ||
|
||
- It uses [my-local-ton](https://github.com/neodix42/MyLocalTon) project without GUI. | ||
Port `4443` is used for [lite-client connection](https://docs.ton.org/participate/run-nodes/enable-liteserver-node). | ||
- It also has a convenient sidecar on port `8000` with some useful tools. | ||
- Please note that it might take **several minutes** to bootstrap the network. | ||
|
||
## Sidecar | ||
|
||
### Getting faucet wallet | ||
|
||
```shell | ||
curl -s http://ton:8000/faucet.json | jq | ||
{ | ||
"initialBalance": 1000001000000000, | ||
"privateKey": "...", | ||
"publicKey": "...", | ||
"walletRawAddress": "...", | ||
"mnemonic": "...", | ||
"walletVersion": "V3R2", | ||
"workChain": 0, | ||
"subWalletId": 42, | ||
"created": false | ||
} | ||
``` | ||
|
||
### Getting lite client config | ||
|
||
Please note that the config returns IP of localhost (`int 2130706433`). | ||
You need to replace it with the actual IP of the docker container. | ||
|
||
```shell | ||
curl -s http://ton:8000/lite-client.json | jq | ||
{ | ||
"@type": "config.global", | ||
"dht": { ... }, | ||
"liteservers": [ | ||
{ | ||
"id": { "key": "...", "@type": "pub.ed25519" }, | ||
"port": 4443, | ||
"ip": 2130706433 | ||
} | ||
], | ||
"validator": { ... } | ||
} | ||
``` | ||
### Checking the node status | ||
It checks for config existence and the fact of faucet wallet deployment | ||
```shell | ||
curl -s http://ton:8000/status | jq | ||
{ | ||
"status": "OK" | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"os" | ||
) | ||
|
||
const ( | ||
port = ":8000" | ||
|
||
basePath = "/opt/my-local-ton/myLocalTon" | ||
liteClientConfigPath = basePath + "/genesis/db/my-ton-local.config.json" | ||
settingsPath = basePath + "/settings.json" | ||
|
||
faucetJSONKey = "faucetWalletSettings" | ||
) | ||
|
||
func main() { | ||
http.HandleFunc("/faucet.json", errorWrapper(faucetHandler)) | ||
http.HandleFunc("/lite-client.json", errorWrapper(liteClientHandler)) | ||
http.HandleFunc("/status", errorWrapper(statusHandler)) | ||
|
||
//nolint:gosec | ||
if err := http.ListenAndServe(port, nil); err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func errorWrapper(handler func(w http.ResponseWriter, r *http.Request) error) http.HandlerFunc { | ||
return func(w http.ResponseWriter, r *http.Request) { | ||
if err := handler(w, r); err != nil { | ||
errResponse(w, http.StatusInternalServerError, err) | ||
} | ||
} | ||
} | ||
|
||
// Handler for the /faucet.json route | ||
func faucetHandler(w http.ResponseWriter, _ *http.Request) error { | ||
faucet, err := extractFaucetFromSettings(settingsPath) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
jsonResponse(w, http.StatusOK, faucet) | ||
return nil | ||
} | ||
|
||
func liteClientHandler(w http.ResponseWriter, _ *http.Request) error { | ||
data, err := os.ReadFile(liteClientConfigPath) | ||
if err != nil { | ||
return fmt.Errorf("could not read lite client config: %w", err) | ||
} | ||
|
||
jsonResponse(w, http.StatusOK, json.RawMessage(data)) | ||
return nil | ||
} | ||
|
||
// Handler for the /status route | ||
func statusHandler(w http.ResponseWriter, _ *http.Request) error { | ||
if _, err := os.Stat(liteClientConfigPath); err != nil { | ||
return fmt.Errorf("lite client config %q not found: %w", liteClientConfigPath, err) | ||
} | ||
|
||
faucet, err := extractFaucetFromSettings(settingsPath) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
type faucetShape struct { | ||
Created bool `json:"created"` | ||
} | ||
|
||
var fs faucetShape | ||
if err = json.Unmarshal(faucet, &fs); err != nil { | ||
return fmt.Errorf("failed to parse faucet settings: %w", err) | ||
} | ||
|
||
if !fs.Created { | ||
return errors.New("faucet is not created yet") | ||
} | ||
|
||
jsonResponse(w, http.StatusOK, map[string]string{"status": "OK"}) | ||
return nil | ||
} | ||
|
||
func extractFaucetFromSettings(filePath string) (json.RawMessage, error) { | ||
data, err := os.ReadFile(filePath) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not read faucet settings: %w", err) | ||
} | ||
|
||
var keyValue map[string]json.RawMessage | ||
if err := json.Unmarshal(data, &keyValue); err != nil { | ||
return nil, fmt.Errorf("failed to parse faucet settings: %w", err) | ||
} | ||
|
||
faucet, ok := keyValue[faucetJSONKey] | ||
if !ok { | ||
return nil, errors.New("faucet settings not found in JSON") | ||
} | ||
|
||
return faucet, nil | ||
} | ||
|
||
func errResponse(w http.ResponseWriter, status int, err error) { | ||
jsonResponse(w, status, map[string]string{"error": err.Error()}) | ||
} | ||
|
||
func jsonResponse(w http.ResponseWriter, status int, data any) { | ||
bytes, err := json.Marshal(data) | ||
if err != nil { | ||
bytes = []byte("Failed to marshal JSON") | ||
} | ||
|
||
w.Header().Set("Content-Type", "application/json") | ||
w.WriteHeader(status) | ||
|
||
//nolint:errcheck | ||
w.Write(bytes) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package observer | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
"github.com/tonkeeper/tongo/config" | ||
"github.com/tonkeeper/tongo/liteapi" | ||
) | ||
|
||
// todo tmp (will be resolved automatically) | ||
// taken from ton:8000/lite-client.json | ||
const configRaw = `{"@type":"config.global","dht":{"@type":"dht.config.global","k":3,"a":3,"static_nodes": | ||
{"@type":"dht.nodes","nodes":[]}},"liteservers":[{"id":{"key":"+DjLFqH/N5jO1ZO8PYVYU6a6e7EnnsF0GWFsteE+qy8=","@type": | ||
"pub.ed25519"},"port":4443,"ip":2130706433}],"validator":{"@type":"validator.config.global","zero_state": | ||
{"workchain":-1,"shard":-9223372036854775808,"seqno":0,"root_hash":"rR8EFZNlyj3rfYlMyQC8gT0A6ghDrbKe4aMmodiNw6I=", | ||
"file_hash":"fT2hXGv1OF7XDhraoAELrYz6wX3ue16QpSoWTiPrUAE="},"init_block":{"workchain":-1,"shard":-9223372036854775808, | ||
"seqno":0,"root_hash":"rR8EFZNlyj3rfYlMyQC8gT0A6ghDrbKe4aMmodiNw6I=", | ||
"file_hash":"fT2hXGv1OF7XDhraoAELrYz6wX3ue16QpSoWTiPrUAE="}}}` | ||
|
||
func TestObserver(t *testing.T) { | ||
t.Skip("skip test") | ||
|
||
ctx := context.Background() | ||
|
||
cfg, err := config.ParseConfig(strings.NewReader(configRaw)) | ||
require.NoError(t, err) | ||
|
||
client, err := liteapi.NewClient(liteapi.WithConfigurationFile(*cfg)) | ||
require.NoError(t, err) | ||
|
||
res, err := client.GetMasterchainInfo(ctx) | ||
require.NoError(t, err) | ||
|
||
// Outputs: | ||
// { | ||
// "Last": { | ||
// "Workchain": 4294967295, | ||
// "Shard": 9223372036854775808, | ||
// "Seqno": 915, | ||
// "RootHash": "2e9e312c5bd3b7b96d23ce1342ac76e5486012c9aac44781c2c25dbc55f5c8ad", | ||
// "FileHash": "d3745319bfaeebb168d9db6bb5b4752b6b28ab9041735c81d4a02fc820040851" | ||
// }, | ||
// "StateRootHash": "02538fb9dc802004012285a90a7af9ba279706e2deea9ca635decd80e94a7045", | ||
// "Init": { | ||
// "Workchain": 4294967295, | ||
// "RootHash": "ad1f04159365ca3deb7d894cc900bc813d00ea0843adb29ee1a326a1d88dc3a2", | ||
// "FileHash": "7d3da15c6bf5385ed70e1adaa0010bad8cfac17dee7b5e90a52a164e23eb5001" | ||
// } | ||
// } | ||
t.Logf("Masterchain info") | ||
logJSON(t, res) | ||
} | ||
|
||
func logJSON(t *testing.T, v any) { | ||
b, err := json.MarshalIndent(v, "", " ") | ||
require.NoError(t, err) | ||
|
||
t.Log(string(b)) | ||
} |
Oops, something went wrong.