-
Notifications
You must be signed in to change notification settings - Fork 4
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
7 changed files
with
463 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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,9 @@ | |
}, | ||
{ | ||
"location": "identity" | ||
}, | ||
{ | ||
"location": "spv" | ||
} | ||
] | ||
} |
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,11 @@ | ||
<div align="center"> | ||
<img src="../docs/img/dogebox-logo.png" alt="Dogebox Logo"/> | ||
<p>Libdogecoin SPV</p> | ||
</div> | ||
|
||
> [!CAUTION] | ||
> This pup does not have a stable release yet. | ||
This pup will install [Libdogecoin SPV](https://github.com/dogecoinfoundation/libdogecoin) as a pup on your node. | ||
|
||
It will generate a new wallet and start block sync from the last checkpoint. |
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,53 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"log" | ||
"os" | ||
"time" | ||
|
||
"path/filepath" | ||
) | ||
|
||
var storageDirectory string | ||
var debugLogFilePath = filepath.Join(storageDirectory, "output.log") | ||
|
||
func main() { | ||
|
||
for { | ||
if _, err := os.Stat(debugLogFilePath); os.IsNotExist(err) { | ||
log.Printf("Waiting for output.log file to be created at %s", debugLogFilePath) | ||
time.Sleep(5 * time.Second) | ||
continue | ||
} | ||
break | ||
} | ||
|
||
file, err := os.Open(debugLogFilePath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
defer file.Close() | ||
|
||
_, err = file.Seek(0, io.SeekEnd) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
for { | ||
time.Sleep(2 * time.Second) | ||
|
||
buffer := make([]byte, 1024) | ||
for { | ||
n, err := file.Read(buffer) | ||
if err != nil && err != io.EOF { | ||
log.Fatal(err) | ||
} | ||
if n == 0 { | ||
break | ||
} | ||
fmt.Print(string(buffer[:n])) | ||
} | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,113 @@ | ||
{ | ||
"manifestVersion": 1, | ||
"meta": { | ||
"name": "Libdogecoin SPV", | ||
"version": "0.0.3", | ||
"logoPath": "logo.png", | ||
"shortDescription": "Run a libdogecoin SPV node on your dogebox", | ||
"longDescription": "Libdogecoin SPV runs a minimal node on your dogebox", | ||
"upstreamVersions": { | ||
"Libdogecoin": "v0.1.4-dogebox-pre" | ||
} | ||
}, | ||
"config": { | ||
"sections": null | ||
}, | ||
"container": { | ||
"build": { | ||
"nixFile": "pup.nix", | ||
"nixFileSha256": "737d4364ead28d6300f203fccfee002681ee97b5a904474757e108aac46a7341" | ||
}, | ||
"services": [ | ||
{ | ||
"name": "spvnode", | ||
"command": { | ||
"exec": "/bin/run.sh", | ||
"cwd": "", | ||
"env": null | ||
} | ||
}, | ||
{ | ||
"name": "monitor", | ||
"command": { | ||
"exec": "/bin/monitor", | ||
"cwd": "", | ||
"env": null | ||
} | ||
}, | ||
{ | ||
"name": "logger", | ||
"command": { | ||
"exec": "/bin/logger", | ||
"cwd": "", | ||
"env": null | ||
} | ||
} | ||
], | ||
"exposes": [ | ||
{ | ||
"name": "p2p-port", | ||
"type": "tcp", | ||
"port": 22556, | ||
"interfaces": null, | ||
"listenOnHost": true | ||
}, | ||
{ | ||
"name": "rest-port", | ||
"type": "http", | ||
"port": 8888, | ||
"interfaces": ["lib-rest"], | ||
"listenOnHost": false | ||
} | ||
], | ||
"requiresInternet": true | ||
}, | ||
"interfaces": [ | ||
{ | ||
"name": "lib-rest", | ||
"version": "0.0.1", | ||
"permissionGroups": [ | ||
{ | ||
"name": "REST", | ||
"description": "Allows RESTful access to the Libdogecoin SPV node", | ||
"severity": 2, | ||
"routes": ["/*"], | ||
"port": 0 | ||
} | ||
] | ||
} | ||
], | ||
"dependencies": null, | ||
"metrics": [ | ||
{ | ||
"name": "chaintip", | ||
"label": "Chain Tip", | ||
"type": "string", | ||
"history": 1 | ||
}, | ||
{ | ||
"name": "addresses", | ||
"label": "Addresses", | ||
"type": "string", | ||
"history": 1 | ||
}, | ||
{ | ||
"name": "balance", | ||
"label": "Wallet Balance", | ||
"type": "string", | ||
"history": 1 | ||
}, | ||
{ | ||
"name": "transaction_count", | ||
"label": "Transaction Count", | ||
"type": "string", | ||
"history": 1 | ||
}, | ||
{ | ||
"name": "unspent_count", | ||
"label": "UTXO Count", | ||
"type": "string", | ||
"history": 1 | ||
} | ||
] | ||
} |
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,205 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
"fmt" | ||
"io" | ||
"log" | ||
"net/http" | ||
"os" | ||
"strings" | ||
"time" | ||
) | ||
|
||
type Metrics struct { | ||
Chaintip string `json:"chaintip"` | ||
Balance string `json:"balance"` | ||
Addresses string `json:"addresses"` | ||
TransactionCount string `json:"transaction_count"` | ||
UnspentCount string `json:"unspent_count"` | ||
} | ||
|
||
func fetchEndpoint(endpoint string) (string, error) { | ||
url := fmt.Sprintf("http://0.0.0.0:8888%s", endpoint) | ||
|
||
client := &http.Client{ | ||
Timeout: 10 * time.Second, | ||
Transport: &http.Transport{ | ||
DisableKeepAlives: true, | ||
}, | ||
} | ||
|
||
req, err := http.NewRequest("GET", url, nil) | ||
if err != nil { | ||
return "", fmt.Errorf("error creating request: %w", err) | ||
} | ||
|
||
req.Header.Set("Connection", "close") | ||
|
||
resp, err := client.Do(req) | ||
if err != nil { | ||
return "", fmt.Errorf("error sending request to %s: %w", endpoint, err) | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
body, _ := io.ReadAll(resp.Body) | ||
return "", fmt.Errorf("unexpected status code %d for %s: %s", resp.StatusCode, endpoint, string(body)) | ||
} | ||
|
||
body, err := io.ReadAll(resp.Body) | ||
if err != nil { | ||
return "", fmt.Errorf("error reading response body for %s: %w", endpoint, err) | ||
} | ||
|
||
return string(body), nil | ||
} | ||
|
||
func collectMetrics() (Metrics, error) { | ||
var metrics Metrics | ||
|
||
// Fetch chain tip | ||
chaintipStr, err := fetchEndpoint("/getChaintip") | ||
if err != nil { | ||
return metrics, err | ||
} | ||
chaintipLine := strings.TrimSpace(chaintipStr) | ||
if strings.HasPrefix(chaintipLine, "Chain tip: ") { | ||
metrics.Chaintip = strings.TrimPrefix(chaintipLine, "Chain tip: ") | ||
} else { | ||
metrics.Chaintip = chaintipLine // In case the format is different | ||
} | ||
|
||
// Fetch balance | ||
balanceStr, err := fetchEndpoint("/getBalance") | ||
if err != nil { | ||
return metrics, err | ||
} | ||
balanceLine := strings.TrimSpace(balanceStr) | ||
if strings.HasPrefix(balanceLine, "Wallet balance: ") { | ||
metrics.Balance = strings.TrimPrefix(balanceLine, "Wallet balance: ") | ||
} else { | ||
metrics.Balance = balanceLine // In case the format is different | ||
} | ||
|
||
// Fetch addresses | ||
addressesStr, err := fetchEndpoint("/getAddresses") | ||
if err != nil { | ||
return metrics, err | ||
} | ||
var addresses []string | ||
for _, line := range strings.Split(addressesStr, "\n") { | ||
line = strings.TrimSpace(line) | ||
if strings.HasPrefix(line, "address: ") { | ||
address := strings.TrimPrefix(line, "address: ") | ||
addresses = append(addresses, address) | ||
} | ||
} | ||
if len(addresses) > 0 { | ||
metrics.Addresses = strings.Join(addresses, "\n") | ||
} else { | ||
metrics.Addresses = "No addresses found" | ||
} | ||
|
||
// Fetch transaction count | ||
transactionsStr, err := fetchEndpoint("/getTransactions") | ||
if err != nil { | ||
return metrics, err | ||
} | ||
transactionCount := 0 | ||
for _, line := range strings.Split(transactionsStr, "\n") { | ||
if strings.HasPrefix(line, "----------------------") { | ||
transactionCount++ | ||
} | ||
} | ||
metrics.TransactionCount = fmt.Sprintf("%d", transactionCount) | ||
|
||
// Fetch unspent UTXO count | ||
utxosStr, err := fetchEndpoint("/getUTXOs") | ||
if err != nil { | ||
return metrics, err | ||
} | ||
unspentCount := 0 | ||
for _, line := range strings.Split(utxosStr, "\n") { | ||
if strings.HasPrefix(line, "----------------------") { | ||
unspentCount++ | ||
} | ||
} | ||
metrics.UnspentCount = fmt.Sprintf("%d", unspentCount) | ||
|
||
return metrics, nil | ||
} | ||
|
||
func submitMetrics(metrics Metrics) { | ||
client := &http.Client{ | ||
Timeout: 10 * time.Second, | ||
} | ||
|
||
// Create a nested structure for the metrics data | ||
jsonData := map[string]interface{}{ | ||
"chaintip": map[string]interface{}{"value": metrics.Chaintip}, | ||
"balance": map[string]interface{}{"value": metrics.Balance}, | ||
"addresses": map[string]interface{}{"value": metrics.Addresses}, | ||
"transaction_count": map[string]interface{}{"value": metrics.TransactionCount}, | ||
"unspent_count": map[string]interface{}{"value": metrics.UnspentCount}, | ||
} | ||
|
||
// Marshal the data to JSON | ||
marshalledData, err := json.Marshal(jsonData) | ||
if err != nil { | ||
log.Printf("Error marshalling metrics: %v", err) | ||
return | ||
} | ||
|
||
log.Printf("Submitting metrics: %+v", jsonData) | ||
|
||
url := fmt.Sprintf("http://%s:%s/dbx/metrics", os.Getenv("DBX_HOST"), os.Getenv("DBX_PORT")) | ||
|
||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(marshalledData)) | ||
if err != nil { | ||
log.Printf("Error creating request: %v", err) | ||
return | ||
} | ||
|
||
req.Header.Set("Content-Type", "application/json") | ||
req.Header.Set("Connection", "close") | ||
|
||
resp, err := client.Do(req) | ||
if err != nil { | ||
log.Printf("Error sending metrics: %v", err) | ||
return | ||
} | ||
defer resp.Body.Close() | ||
|
||
if resp.StatusCode != http.StatusOK { | ||
body, _ := io.ReadAll(resp.Body) | ||
log.Printf("Unexpected status code when submitting metrics: %d", resp.StatusCode) | ||
log.Printf("Response body: %s", string(body)) | ||
return | ||
} | ||
} | ||
|
||
func main() { | ||
log.Println("Sleeping to give spvnode time to start...") | ||
time.Sleep(10 * time.Second) | ||
|
||
ticker := time.NewTicker(10 * time.Second) | ||
defer ticker.Stop() | ||
|
||
for { | ||
select { | ||
case <-ticker.C: | ||
metrics, err := collectMetrics() | ||
if err != nil { | ||
log.Printf("Error collecting metrics: %v", err) | ||
continue | ||
} | ||
|
||
log.Printf("Metrics: %+v", metrics) | ||
submitMetrics(metrics) | ||
|
||
log.Printf("----------------------------------------") | ||
} | ||
} | ||
} |
Oops, something went wrong.