ENPLDEPT
Flash
Toda a documentação
Store · vendedor

Um disco que já fica ligado. Deixe-o render.

Outros donos de nodes precisam de um lugar para cópias cifradas. O seu NAS, Raspberry ou servidor caseiro tem espaço que nunca usa. O agente Store liga as duas pontas — você guarda texto cifrado que não consegue ler, responde a uma prova algumas vezes por dia e recebe por cada dia em que a prova passa. Nada passa pelo seu node, nada se abre na sua firewall.

Para quem é

Uma máquina que já fica ligada — um NAS, um Raspberry, um pequeno servidor caseiro, uma caixa num rack que já paga — com um gigabyte ou mais de espaço de que não precisa, na mesma LAN que um node Sensmos. Linux com Python 3, nada para instalar além do próprio script. Root só é preciso para escrever o ficheiro de estado e a unit do systemd.

O comprador é sempre outro dono de node: o Store é comércio interno entre pessoas que têm nodes, não uma nuvem pública. Nunca lida com o comprador diretamente; o backend escolhe vendedores, move os bytes e fecha os dias.

O que guarda de facto

Blobs cifrados. A app do comprador cifra cada ficheiro no telemóvel com uma chave derivada da assinatura da carteira dele; o que lhe chega é texto cifrado com um id aleatório. Não recebe chave, nome de ficheiro nem nada que identifique o comprador. Do seu lado não existe caminho no código capaz de decifrar — o agente é um único ficheiro legível, veja por si.

Desde store-py/0.2 fica ao lado de cada blob um pequeno ficheiro .meta: a chave do ficheiro embrulhada, o nome cifrado, os tamanhos e os hashes dos blocos, assinados pela carteira do comprador. Não muda nada no que consegue ler — a chave lá dentro está selada para o comprador e não serve a mais ninguém. Existe para que os ficheiros nos sobrevivam: até agora esses dados viviam só na base de dados do backend, e perdê-la significaria perder os ficheiros apesar de os bytes estarem vivos no seu disco. O registo viaja com os bytes, por isso a segunda cópia leva um igual.

Início rápido

Execute isto na máquina que vai guardar os dados. Fala uma vez com o seu node, pela LAN, e daí em diante só com o backend.

# 1 — obter o agente (um ficheiro, só biblioteca padrão)
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 — emparelhar através do node: o endereço dele na LAN, o PIN, um nome, onde guardar os blobs, quanto oferece
sudo sensmos-store.py --pair 192.168.1.50 --pin 123456 --name "NAS na cave" \
                      --dir /srv/sensmos-store --capacity 100G

# 3 — instalar e arrancar como serviço que sobrevive a reinícios
sudo sensmos-store.py --install-service

# 4 — acompanhar
journalctl -u sensmos-store -f

O emparelhamento imprime OK — attachment …, token saved to /etc/sensmos-store.json. O registo do serviço mostra depois:

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

A partir desse momento está no pool. O primeiro comprador aparece no registo como put 7d0b… 18.1 MB … seguido de put 7d0b… done, e as provas como proof 7d0b… block 3: answered (10 MB hashed).

O endereço do node na LAN está na lista de clientes do router; o PIN é o PIN do node na app. O node tem de estar online (ligado ao backend) no momento do emparelhamento — encaminha o seu pedido e a resposta do backend.

Como é pago

o quêcondições
preço0,1 GALU por GB por cópia por dia — o comprador escolhe o tamanho, a partir de 1 GB, e pode alterá-lo depois em 1 GB; 10 GB são 1 GALU por dia por cópia
a sua parte70%; 30% voltam ao pool de recompensas
pago porcada dia em que o pacote de um comprador está fixo consigo e você esteve presente: com os ficheiros dele no seu disco, a sua cópia passou uma prova; enquanto o pacote ainda está vazio, o seu agente reportou nesse dia — o espaço está reservado de qualquer forma
não pago pordias offline ou com prova falhada; dias em que o comprador não tinha GALU — esse dia conta como atraso para o comprador (envios pausados, cópias libertadas após 14 dias sem pagamento) e você não é pago por ele

O acerto corre uma vez por hora no backend e regista cada (dia, comprador, vendedor) uma única vez. O GALU entra no saldo da sua carteira como qualquer outra receita de serviço.

Provas — como o backend sabe que ainda tem o ficheiro

Três vezes por dia por cópia, o backend escolhe um bloco aleatório de 10 MB de um ficheiro aleatório que guarda e envia um sal. O seu agente faz o hash do bloco com o sal e responde com 32 bytes — não se movem dados, do nosso lado não se calcula nada. Com duas cópias em dois vendedores, as duas respostas são comparadas entre si. Quando divergem, ou quando só uma cópia está online, o backend pede o bloco em bruto e confere-o com a lista de hashes que o comprador forneceu ao enviar.

Três provas falhadas seguidas e a cópia é marcada como descartada: acabam os desafios, acaba o pagamento. Não há outra penalização — simplesmente deixa de ganhar com ela.

Capacidade e como os vendedores são escolhidos

  • --capacity é o que oferece. Não é verificado — quem declara mais do que tem falha as provas e não ganha nada, e essa é toda a verificação.
  • O que conta é o espaço livre no livro do próprio backend (o que ele colocou consigo), não o que o seu agente reporta; o relatório de cinco em cinco minutos é informativo.
  • O comprador escolhe o tamanho do pacote na compra — qualquer número inteiro de gigabytes, limitado pelo que os vendedores têm realmente livre — e depois aumenta-o ou reduz gigabyte a gigabyte nos mesmos vendedores. Cada gigabyte inteiro livre da sua oferta pode ser vendido.
  • Os vendedores são ordenados por espaço livre; as duas cópias de um comprador vão sempre para dois donos diferentes e nunca para as máquinas do próprio comprador.
  • Uma vez escolhido fica fixo: todos os ficheiros que esse comprador enviar daí em diante ficam consigo, e quando ele compra mais um gigabyte, tem de caber consigo. Também pode encolher o pacote, um gigabyte de cada vez, até ao que os ficheiros dele ocupam. O pacote dele não se move sozinho para lado nenhum. O comprador pode fechá-lo a qualquer momento: os ficheiros dele são apagados do seu disco, o espaço fica livre de novo e os pagamentos terminam nesse dia.

Para mudar a oferta, edite capacity_b em /etc/sensmos-store.json e reinicie o serviço. Para deixar de vender, pare o serviço — sem provas as suas cópias são descartadas dentro de um dia e sai do pool; os blobs em --dir são seus para apagar.

Rede

O agente liga-se para fora a sensmos.com por TLS e mantém essa única ligação. O controlo — que ficheiro guardar, que bloco provar, o que apagar — chega sempre por ela, e isso funciona atrás de CGNAT sem porta de entrada.

Os bytes dos ficheiros são outra questão. Vão diretamente entre si e o dono do ficheiro sempre que um dos dois possa ser contactado:

  1. é possível ligar-lhe a si — o dispositivo do dono liga-se à sua porta e o ficheiro passa diretamente;
  2. é possível ligar-lhe a ele — então é você que liga;
  3. a nenhum dos dois — os bytes passam pelo backend, como sempre passaram.

Qual das três, decide o backend, de cada vez, e verifica a alcançabilidade mesmo antes da transferência. Um endereço que funcionou há uma hora não prova nada: os telemóveis mudam de rede e os reencaminhamentos do router desaparecem depois de um reinício. O agente nunca escolhe a rota sozinho.

A porta onde escuta (9033 por omissão) responde a cada ligação com uma linha que identifica este agente. É também assim que a alcançabilidade é medida — o backend liga à porta ele próprio, porque vendedores convencidos de que têm endereço público sem o ter há demasiados para confiar numa declaração. Se o seu router falar UPnP, a porta é reencaminhada automaticamente; --no-upnp se preferir tratar disso à sua maneira, --no-direct para não escutar de todo.

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)

Um anfitrião a que não se consegue ligar continua a vender tal como antes — os seus bytes seguem simplesmente pela terceira rota.

O que verifica

Cada byte que recebe é somado à medida que chega e comparado com o registo que o dono assinou antes de o ficheiro sequer sair do dispositivo dele: bloco a bloco, depois o ficheiro inteiro. Um ficheiro que não corresponda nunca chega a ser escrito — comunica o bloco defeituoso e nada chega ao seu disco.

Isto protege-o a si, não a nós. Um envio corrompido passava a ser problema seu: ficava lá, falhava a prova diária e custava-lhe o pagamento do dia pelo erro de outra pessoa. Agora é recusado à porta. A verificação corre nas três rotas, incluindo cópias trazidas de outro anfitrião.

Onde vê isto

Na app (1.5.60 ou mais recente), no cartão do node que responde pelo agente, na secção Adições: online ou não, espaço oferecido e usado, cópias guardadas, provas dos últimos sete dias, ganhos. Um toque longo desliga o agente (o token é revogado de imediato). O registo do serviço mostra o mesmo, linha a linha.

Flags

flagsignificado
--pair IP --pin PIN --name "…"emparelhamento único através de um node
--dir DIRonde ficam os blobs (predefinição /var/lib/sensmos-store)
--capacity 100Gespaço oferecido; sufixos M, G, T
--install-servicecopia para /usr/local/bin, escreve e ativa a unit do systemd
--be URLbackend alternativo, para testes
--direct-port 9033porta de entrada que responde com a linha de identificação do agente
--no-directnão escutar em nenhuma porta de entrada
--no-upnpnão pedir ao router o reencaminhamento dessa porta (por omissão pede e renova enquanto corre)

Estas três definições são gravadas em /etc/sensmos-store.json e o programa termina — o serviço arranca o script sem argumentos, por isso passe-as uma vez e reinicie-o.

A unit que escreve:

# /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

Emparelhamento — o token

O agente não tem credenciais próprias. Pede ao seu node (com o PIN do node, de dentro da LAN) que responda por ele; o node encaminha o pedido ao backend, e o backend emite um token com o âmbito store.serve — servir sessões Store, nada mais. O token fica em /etc/sensmos-store.json (modo 0600) e o agente renova-o sozinho. Um node pode responder por até quatro acessórios. O contrato completo está em Acessórios e a API EXT.

Atualizações

O agente nunca se atualiza sozinho: corre como root na sua LAN, e um servidor capaz de lhe enviar código seria uma porta para a sua rede. Para atualizar, repita o passo 1 e reinicie:

sudo curl -fsSL -o /usr/local/bin/sensmos-store.py https://sensmos.com/ext/sensmos-store.py
sudo systemctl restart sensmos-store

A partir de store-py/0.4 os ficheiros seguem diretamente e o que recebe é verificado. Um script mais antigo continua a vender, a provar e a ganhar, mas cada byte passa nele pelo backend e aceita um ficheiro corrompido sem dar por isso. A app mostra no cartão do vendedor quando existe uma versão mais recente.

A partir de store-py/0.5, uma transferência interrompida retoma em vez de recomeçar. Se a ligação cair a meio de um ficheiro, a parte já recebida fica no disco e a tentativa seguinte continua a partir daí — o mesmo nos dois sentidos e o mesmo na reconstrução de cópias entre anfitriões. Só oferece de volta a parte que verificou, por isso um ficheiro retomado é conferido com o mesmo rigor de um que chegou de uma só vez.

A atualização não lhe tira nada. Os ficheiros que já guarda, o formato no disco, a prova diária e os seus ganhos ficam intactos — a 0.5 lê-os e responde por eles tal como a 0.4. Um pedaço por terminar é espaço de trabalho, nunca dados guardados: desaparece no momento em que o dono cancela o envio, ou ao fim de uma semana se ninguém voltar — e em qualquer dos casos não é pago nem lhe é cobrado.

Um agente desatualizado deixa de receber ficheiros novos. A partir de store-py/0.2 o agente escreve o registo .meta descrito acima; um script que não o consiga fica de fora na escolha de vendedores — continua a servir e a provar o que já tem, mas nada de novo lhe chega. A app di-lo no cartão do vendedor, e o registo em cada ligação.

Primeiros tempos

O Store é novo e o pool é pequeno. Se montar um vendedor e durante algum tempo não chegar nada, é o estado honesto da procura, não uma falha do seu lado — diga olá no Discord e dizemos-lhe como está o pool.

Perguntas, respostas diretas

Posso ler o que guardo?

Não. O comprador cifra cada ficheiro no próprio telemóvel com uma chave derivada da carteira; você recebe texto cifrado, nunca uma chave, nunca um nome de ficheiro. O backend também não consegue ler — só encaminha bytes e guarda a lista de hashes do comprador.

O que acontece se a minha máquina estiver desligada?

Nesse dia não ganha nada. Uma prova sem resposta conta como falhada; após três provas falhadas seguidas a cópia é descartada. Quando a máquina voltar, a cópia é reconstruída automaticamente a partir do outro vendedor, mas os dias de intervalo perdem-se, e é exatamente por isso que a ideia é uma máquina sempre ligada.

Quanto ganho?

0,1 GALU por GB por cópia por dia, dos quais 70% são seus: o comprador escolhe o tamanho na compra e depois pode aumentá-lo ou reduzi-lo gigabyte a gigabyte, por isso um pacote de 10 GB consigo são 0,7 GALU por dia. Só nos dias em que um comprador tem um pacote consigo e você esteve presente: uma prova passada quando os ficheiros dele estão no seu disco, um relatório diário do seu agente enquanto o pacote ainda está vazio. Não prometemos quantos compradores haverá.

Posso oferecer 3 GB?

Sim. Os compradores escolhem na compra qualquer número inteiro de gigabytes e podem alterá-lo depois de um em um, por isso cada gigabyte inteiro da sua oferta pode ser vendido — a três compradores com um cada ou a um que leve os três.

O meu node precisa de rádio ou de algo especial?

Não. Qualquer node Sensmos na mesma LAN, online, com o seu PIN. Só responde pelo agente uma vez; depois fica de fora.

Há imagem Docker?

Ainda não. O caminho suportado é o serviço systemd num host Linux.

Atualizado: 2026-09-09