Für wen das ist
Eine Maschine, die ohnehin läuft — ein NAS, ein Raspberry, ein kleiner Heimserver, eine Kiste im Rack, die du schon bezahlst — mit einem Gigabyte oder mehr Platz, den du nicht brauchst, im selben LAN wie ein Sensmos-Node. Linux mit Python 3, außer dem Skript selbst nichts zu installieren. Root braucht es nur, um die Zustandsdatei und die systemd-Unit zu schreiben.
Ein Käufer ist immer ein anderer Node-Besitzer: Store ist interner Handel zwischen Leuten, die Nodes betreiben, keine öffentliche Cloud. Mit dem Käufer hast du nie direkt zu tun; das Backend wählt Anbieter, bewegt die Bytes und rechnet die Tage ab.
Was du wirklich hältst
Verschlüsselte Blobs. Die App des Käufers verschlüsselt jede Datei auf dem Telefon mit einem Schlüssel aus der Wallet-Signatur des Käufers; bei dir kommt Chiffrat mit einer zufälligen ID an. Du bekommst keinen Schlüssel, keinen Dateinamen und nichts, was den Käufer erkennen lässt. Auf deiner Seite gibt es keinen Codepfad, der entschlüsseln könnte — der Agent ist eine einzige lesbare Datei, sieh selbst nach.
Seit store-py/0.2 liegt neben jedem Blob eine kleine .meta-Datei: der verpackte Dateischlüssel, der verschlüsselte Name, die Größen und die Blockhashes, signiert von der Wallet des Käufers. An dem, was du lesen kannst, ändert das nichts — der Schlüssel darin ist auf den Käufer versiegelt und für alle anderen wertlos. Sie existiert, damit die Dateien uns überleben: bisher lagen diese Daten nur in der Datenbank des Backends, und ihr Verlust hätte den Verlust der Dateien bedeutet, obwohl die Bytes auf deiner Platte liegen. Der Datensatz wandert mit den Bytes, die zweite Kopie trägt denselben.
Schnellstart
Führe das auf der Maschine aus, die die Daten halten wird. Sie spricht einmal über das LAN mit deinem Node und danach nur noch mit dem Backend.
# 1 — Agent holen (eine Datei, nur Standardbibliothek)
sudo curl -fsSL -o /usr/local/bin/sensmos-store.py https://sensmos.com/ext/sensmos-store.py
sudo chmod +x /usr/local/bin/sensmos-store.py
# 2 — über deinen Node koppeln: seine LAN-Adresse, seine PIN, ein Name, Ablageort der Blobs, angebotener Platz
sudo sensmos-store.py --pair 192.168.1.50 --pin 123456 --name "NAS im Keller" \
--dir /srv/sensmos-store --capacity 100G
# 3 — als Dienst installieren und starten, überlebt Neustarts
sudo sensmos-store.py --install-service
# 4 — zusehen
journalctl -u sensmos-store -f
Das Koppeln gibt OK — attachment …, token saved to /etc/sensmos-store.json aus. Im Dienstprotokoll steht danach:
21:14:02 store agent store-py/0.3 dir=/srv/sensmos-store capacity=100 GB used=0.00 GB
21:14:03 connected as 3f9a1c2e
Ab diesem Moment bist du im Pool. Der erste Käufer erscheint im Protokoll als put 7d0b… 18.1 MB …, gefolgt von put 7d0b… done, Beweise als proof 7d0b… block 3: answered (10 MB hashed).
Die LAN-Adresse des Nodes steht in der Client-Liste deines Routers; die PIN ist die Node-PIN aus der App. Der Node muss beim Koppeln online sein (mit dem Backend verbunden) — er reicht deine Anfrage und die Antwort des Backends weiter.
Wie du bezahlt wirst
| was | Bedingungen |
|---|---|
| Preis | 0,1 GALU pro GB pro Kopie pro Tag — der Käufer wählt die Größe, ab 1 GB, und kann sie später um je 1 GB ändern; 10 GB sind 1 GALU am Tag pro Kopie |
| dein Anteil | 70%; 30% fließen zurück in den Belohnungspool |
| bezahlt für | jeden Tag, an dem das Paket eines Käufers bei dir festgelegt ist und du da warst: liegen seine Dateien auf deiner Platte, hat deine Kopie einen Beweis bestanden; ist das Paket noch leer, hat sich dein Agent an dem Tag gemeldet — der Platz ist so oder so reserviert |
| nicht bezahlt für | Tage offline oder mit fehlgeschlagenem Beweis; Tage, an denen der Käufer kein GALU hatte — der Tag zählt für den Käufer als Rückstand (Uploads pausiert, Kopien nach 14 unbezahlten Tagen freigegeben), und du wirst dafür nicht bezahlt |
Die Abrechnung läuft einmal pro Stunde im Backend und bucht jedes Tripel (Tag, Käufer, Anbieter) genau einmal. GALU landet im Guthaben deiner Wallet wie jede andere Diensteinnahme.
Beweise — woher das Backend weiß, dass du die Datei noch hast
Dreimal am Tag pro Kopie wählt das Backend einen zufälligen 10-MB-Block einer zufälligen Datei, die du hältst, und schickt ein Salz. Dein Agent hasht den Block mit dem Salz und antwortet mit 32 Bytes — keine Daten bewegen sich, auf unserer Seite wird nichts gerechnet. Bei zwei Kopien bei zwei Anbietern werden die beiden Antworten miteinander verglichen. Weichen sie ab oder ist nur eine Kopie online, fordert das Backend den rohen Block an und prüft ihn gegen die Hash-Liste, die der Käufer beim Hochladen mitgegeben hat.
Drei fehlgeschlagene Beweise in Folge, und die Kopie gilt als fallen gelassen: keine Herausforderungen mehr, keine Bezahlung mehr. Eine weitere Strafe gibt es nicht — du verdienst an ihr einfach nichts mehr.
Kapazität und wie Anbieter gewählt werden
--capacityist dein Angebot. Es wird nicht geprüft — wer mehr deklariert, als er hat, scheitert an den Beweisen und verdient nichts, das ist die ganze Kontrolle.- Es zählt der freie Platz im eigenen Buch des Backends (was es bei dir abgelegt hat), nicht die Meldung deines Agenten; der Bericht alle fünf Minuten ist informativ.
- Ein Käufer wählt die Paketgröße beim Kauf — eine beliebige volle Gigabyte-Zahl, begrenzt durch das, was Anbieter wirklich frei haben — und vergrößert oder verkleinert sie danach gigabyteweise bei denselben Anbietern. Jedes volle freie Gigabyte deines Angebots lässt sich verkaufen.
- Anbieter werden nach freiem Platz gereiht; die zwei Kopien eines Käufers gehen immer an zwei verschiedene Besitzer und nie auf die Maschinen des Käufers selbst.
- Einmal gewählt bist du festgelegt: jede Datei, die dieser Käufer ab dann hochlädt, landet bei dir, und kauft er ein Gigabyte dazu, muss es bei dir passen. Er kann das Paket auch gigabyteweise verkleinern, bis auf das, was seine Dateien belegen. Sein Paket zieht von selbst nirgendwohin. Ein Käufer kann es jederzeit schließen: seine Dateien werden von deiner Platte gelöscht, der Platz ist wieder frei und die Zahlungen enden mit diesem Tag.
Um dein Angebot zu ändern, bearbeite capacity_b in /etc/sensmos-store.json und starte den Dienst neu. Um aufzuhören, stoppe den Dienst — ohne Beweise werden deine Kopien binnen eines Tages fallen gelassen und du verlässt den Pool; die Blobs in --dir darfst du löschen.
Netzwerk
Der Agent wählt sich ausgehend über TLS bei sensmos.com ein und hält diese eine Verbindung. Die Steuerung — welche Datei zu halten ist, welcher Block bewiesen wird, was gelöscht wird — kommt immer darüber, und das funktioniert hinter CGNAT ohne eingehenden Port.
Die Dateibytes sind eine andere Frage. Sie laufen direkt zwischen dir und der Eigentümerin der Datei, sobald sich eine der beiden Seiten anwählen lässt:
- du bist erreichbar — das Gerät der Eigentümerin verbindet sich mit deinem Port, die Datei geht direkt;
- die andere Seite ist erreichbar — dann wählst du sie an;
- keine von beiden — die Bytes laufen über das Backend, wie bisher.
Welche der drei es wird, entscheidet das Backend jedes Mal neu und prüft die Erreichbarkeit unmittelbar vor der Übertragung. Eine Adresse, die vor einer Stunde funktionierte, beweist nichts: Telefone wechseln das Netz, Portfreigaben verschwinden nach einem Neustart. Der Agent wählt nie selbst eine Route.
Der Port, auf dem er lauscht (standardmäßig 9033), antwortet auf jede Verbindung mit einer Zeile, die diesen Agenten benennt. So wird auch die Erreichbarkeit gemessen — das Backend wählt den Port selbst an, denn Verkäufer, die sich für öffentlich erreichbar halten und es nicht sind, gibt es zu viele, als dass eine Selbstauskunft etwas wert wäre. Spricht dein Router UPnP, wird der Port automatisch weitergeleitet; --no-upnp, wenn du das lieber selbst regelst, --no-direct, um gar nicht zu lauschen.
13:16:55 direct: listening on TCP 9033
13:21:55 direct_ok: Reachable from the internet at 203.0.113.9:9033.
13:24:03 direct recv 8f2a1c7d with 198.51.100.4: ok (12.4 MB)
Ein Host, der sich nicht anwählen lässt, verkauft genau wie bisher — seine Bytes nehmen einfach die dritte Route.
Was du prüfst
Jedes Byte, das bei dir ankommt, wird im Fluss gehasht und gegen den Datensatz geprüft, den die Eigentümerin signiert hat, bevor die Datei ihr Gerät überhaupt verlassen hat: Block für Block, dann die ganze Datei. Eine Datei, die nicht passt, entsteht gar nicht erst — du meldest den fehlerhaften Block, und nichts landet auf deiner Platte.
Das schützt dich, nicht uns. Ein kaputter Upload wurde bisher zu deinem Problem: die Datei lag da, fiel beim täglichen Beweis durch und kostete dich den Tageslohn für den Fehler eines anderen. Jetzt wird sie an der Tür abgewiesen. Die Prüfung läuft auf allen drei Routen, auch bei Kopien, die von einem anderen Host geholt werden.
Wo du es siehst
In der App (1.5.60 oder neuer), auf der Karte des Nodes, der für den Agenten bürgt, unter Erweiterungen: online oder nicht, angebotener und belegter Platz, gehaltene Kopien, Beweise der letzten sieben Tage, Verdienst. Langes Drücken trennt den Agenten (sein Token wird sofort entzogen). Das Dienstprotokoll zeigt dasselbe, Zeile für Zeile.
Flags
| Flag | Bedeutung |
|---|---|
--pair IP --pin PIN --name "…" | einmaliges Koppeln über einen Node |
--dir DIR | wo die Blobs liegen (Standard /var/lib/sensmos-store) |
--capacity 100G | angebotener Platz; Suffixe M, G, T |
--install-service | Kopie nach /usr/local/bin, systemd-Unit schreiben und aktivieren |
--be URL | anderes Backend, zum Testen |
--direct-port 9033 | eingehender Port, der mit der Kennzeile des Agenten antwortet |
--no-direct | auf keinem eingehenden Port lauschen |
--no-upnp | den Router NICHT um die Weiterleitung bitten (standardmäßig wird gefragt und laufend erneuert) |
Diese drei Einstellungen werden nach /etc/sensmos-store.json geschrieben, dann endet das Programm — der Dienst startet das Skript ohne Argumente, gib sie also einmal an und starte ihn neu.
Die Unit, die er schreibt:
# /etc/systemd/system/sensmos-store.service
[Unit]
Description=Sensmos store agent
After=network-online.target
Wants=network-online.target
[Service]
ExecStart=/usr/bin/python3 /usr/local/bin/sensmos-store.py
Restart=always
RestartSec=10
User=root
[Install]
WantedBy=multi-user.target
Koppeln — das Token
Der Agent hat keine eigenen Zugangsdaten. Er bittet deinen Node (mit der Node-PIN, aus dem LAN heraus), für ihn zu bürgen; der Node reicht die Anfrage an das Backend weiter, und das Backend stellt ein Token mit dem Scope store.serve aus — Store-Sitzungen bedienen, sonst nichts. Das Token liegt in /etc/sensmos-store.json (Modus 0600), der Agent erneuert es selbst. Ein Node kann für bis zu vier Anhänge bürgen. Der vollständige Vertrag steht unter Anhänge & die EXT-API.
Updates
Der Agent aktualisiert sich nie selbst: er läuft als root in deinem LAN, und ein Server, der ihm Code schicken könnte, wäre ein Weg in dein Netz. Zum Aktualisieren Schritt 1 wiederholen und neu starten:
sudo curl -fsSL -o /usr/local/bin/sensmos-store.py https://sensmos.com/ext/sensmos-store.py
sudo systemctl restart sensmos-store
Ab store-py/0.4 laufen Dateien direkt, und was du empfängst, wird geprüft. Ein älteres Skript verkauft, beweist und verdient weiterhin, aber jedes Byte läuft bei ihm über das Backend, und eine kaputte Datei nimmt es an, ohne es zu merken. Die App weist auf der Verkäuferkachel darauf hin, wenn es eine neuere Version gibt.
Ab store-py/0.5 wird eine abgebrochene Übertragung fortgesetzt statt neu begonnen. Reißt die Verbindung mitten in einer Datei ab, bleibt der bereits empfangene Teil auf der Platte und der nächste Versuch macht genau dort weiter — in beide Richtungen gleichermaßen, und ebenso beim Wiederaufbau von Kopien zwischen Hosts. Du bietest nur den Teil an, den du selbst geprüft hast; eine fortgesetzte Datei wird also genauso streng geprüft wie eine, die in einem Zug ankam.
Das Update nimmt dir nichts weg. Die Dateien, die du bereits hältst, das Format auf der Platte, der tägliche Beweis und dein Verdienst bleiben unangetastet — 0.5 liest sie und steht für sie gerade wie 0.4. Ein unfertiges Stück ist Arbeitsspeicherplatz, niemals gespeicherte Daten: Es verschwindet, sobald der Eigentümer den Upload abbricht, oder nach einer Woche, wenn niemand zurückkommt — in beiden Fällen wird es weder vergütet noch angerechnet.
Ein veralteter Agent bekommt keine neuen Dateien mehr. Ab store-py/0.2 schreibt der Agent den oben beschriebenen .meta-Datensatz; ein Skript, das das nicht kann, fällt bei der Anbieterwahl heraus — es liefert und beweist weiter, was es schon hält, bekommt aber nichts Neues. Die App sagt es auf der Anbieterkachel, das Protokoll bei jedem Verbinden.
Anfangszeit
Store ist neu und der Pool klein. Wenn du einen Anbieter aufsetzt und eine Weile nichts ankommt, ist das der ehrliche Stand der Nachfrage, kein Fehler auf deiner Seite — sag auf Discord Hallo, und wir sagen dir, wie der Pool aussieht.