Now remotes can send links to stratum 0

This commit is contained in:
Jonathan Bennett
2025-12-15 18:32:56 -06:00
parent d5839ad348
commit ba71941fdc
2 changed files with 116 additions and 8 deletions

View File

@@ -6,6 +6,8 @@
// TODO: non-stratum0 nodes need to be pointed at their upstream source? Maybe
// TODO: Work without sending some of the hashes/ short hashes
// things may get weird if there are multiple stratum-0 nodes on a single mesh. Come up with mitigations
// Basic design:
@@ -142,6 +144,10 @@ StoreForwardPlusPlusModule::StoreForwardPlusPlusModule()
encrypted_bytes, message_hash, rx_time, payload) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?);",
-1, &scratch_insert_stmt, NULL);
sqlite3_prepare_v2(ppDb, "select destination, sender, packet_id, encrypted_bytes, message_hash, rx_time \
from local_messages where channel_hash=? order by rx_time desc LIMIT 1;", // earliest first
-1, &fromScratchStmt, NULL);
sqlite3_prepare_v2(ppDb, "SELECT COUNT(*) from channel_messages where message_hash=?", -1, &checkDup, NULL);
sqlite3_prepare_v2(ppDb, "SELECT COUNT(*) from local_messages where message_hash=?", -1, &checkScratch, NULL);
@@ -195,7 +201,13 @@ bool StoreForwardPlusPlusModule::handleReceivedProtobuf(const meshtastic_MeshPac
if (portduino_config.sfpp_stratum0) {
LOG_WARN("Received a CANON_ANNOUNCE while stratum 0");
// honestly this is fine, and if the announce is not end of chain, just treat it like a request for next
uint8_t next_chain_hash[32] = {0};
if (getNextHash(t->root_hash.bytes, t->chain_hash.bytes, next_chain_hash)) {
printBytes("next chain hash: ", next_chain_hash, 32);
broadcastLink(next_chain_hash, t->root_hash.bytes);
}
} else {
uint8_t tmp_root_hash_bytes[32] = {0};
@@ -220,6 +232,7 @@ bool StoreForwardPlusPlusModule::handleReceivedProtobuf(const meshtastic_MeshPac
if (getChainEnd(router->p_encrypted->channel, last_message_chain_hash, last_message_hash)) {
if (memcmp(last_message_chain_hash, t->chain_hash.bytes, 32) == 0) {
LOG_WARN("End of chain matches!");
sendFromScratch(router->p_encrypted->channel);
// TODO: Send a message from the local queue
} else {
// TODO: Check for a matching message in the scratch, and do this automatically if possible
@@ -251,15 +264,59 @@ bool StoreForwardPlusPlusModule::handleReceivedProtobuf(const meshtastic_MeshPac
//
if (portduino_config.sfpp_stratum0) {
// check for message_hash in db
if (isInDB(t->message_hash.bytes)) {
LOG_WARN("Received link already in chain");
// TODO: respond with last link?
}
uint8_t root_hash_bytes[32] = {0};
if (!getRootFromChannelHash(router->p_encrypted->channel, root_hash_bytes)) {
LOG_WARN("Hash bytes not found for incoming link");
return true;
}
if (t->root_hash.size != 32 || memcmp(root_hash_bytes, t->root_hash.bytes, 32) != 0) {
LOG_WARN("Hash bytes mismatch for incoming link");
return true;
}
SHA256 chain_hash;
uint8_t last_message_hash[32] = {0};
uint8_t last_chain_hash[32] = {0};
uint8_t chain_hash_bytes[32] = {0};
chain_hash.reset();
if (getChainEnd(router->p_encrypted->channel, last_chain_hash, last_message_hash)) {
printBytes("last message: 0x", last_chain_hash, 32);
chain_hash.update(last_chain_hash, 32);
} else {
printBytes("new chain root: 0x", root_hash_bytes, 32);
chain_hash.update(root_hash_bytes, 32);
}
chain_hash.update(t->message_hash.bytes, 32);
// message_hash.update(&mp.rx_time, sizeof(mp.rx_time));
chain_hash.finalize(chain_hash_bytes, 32);
// calculate the chain_hash
LOG_ERROR("TODO calculate chain");
addToChain(t->encapsulated_to, t->encapsulated_from, t->encapsulated_id, false, _channel_hash, t->message.bytes,
t->message.size, t->message_hash.bytes, t->chain_hash.bytes, t->root_hash.bytes, t->encapsulated_rxtime,
"", 0);
// auto pAck = routingModule->allocAckNak(meshtastic_Routing_Error_NONE, getFrom(e.packet), e.packet->id, ch.index);
// pAck->transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_MQTT;
// router->sendLocal(pAck);
t->message.size, t->message_hash.bytes, chain_hash_bytes, root_hash_bytes, t->encapsulated_rxtime, "", 0);
canonAnnounce(t->message_hash.bytes, chain_hash_bytes, root_hash_bytes);
LOG_WARN("Attempting to Rebroadcast");
meshtastic_MeshPacket *p = router->allocForSending();
p->to = t->encapsulated_to;
p->from = t->encapsulated_from;
p->id = t->encapsulated_id;
p->channel = _channel_hash;
p->which_payload_variant = meshtastic_MeshPacket_encrypted_tag;
p->encrypted.size = t->message.size;
memcpy(p->encrypted.bytes, t->message.bytes, t->message.size);
p->transport_mechanism = meshtastic_MeshPacket_TransportMechanism_TRANSPORT_LORA; // only a tiny white lie
router->sendLocal(p);
} else {
addToChain(t->encapsulated_to, t->encapsulated_from, t->encapsulated_id, false, _channel_hash, t->message.bytes,
t->message.size, t->message_hash.bytes, t->chain_hash.bytes, t->root_hash.bytes, t->encapsulated_rxtime,
@@ -368,7 +425,7 @@ ProcessMessage StoreForwardPlusPlusModule::handleReceived(const meshtastic_MeshP
if (getChainEnd(router->p_encrypted->channel, last_chain_hash, last_message_hash)) {
printBytes("last message: 0x", last_chain_hash, 32);
chain_hash.update(last_message_hash, 32);
chain_hash.update(last_chain_hash, 32);
} else {
printBytes("new chain root: 0x", root_hash_bytes, 32);
chain_hash.update(root_hash_bytes, 32);
@@ -647,6 +704,54 @@ bool StoreForwardPlusPlusModule::broadcastLink(uint8_t *_chain_hash, uint8_t *_r
return true;
}
bool StoreForwardPlusPlusModule::sendFromScratch(uint8_t _channel_hash)
{
// "select destination, sender, packet_id, channel_hash, encrypted_bytes, message_hash, rx_time \
// from local_messages order by rx_time desc LIMIT 1;"
sqlite3_bind_int(fromScratchStmt, 1, _channel_hash);
if (sqlite3_step(fromScratchStmt) == SQLITE_DONE) {
LOG_WARN("No messages in scratch to forward");
return false;
}
uint8_t _root_hash[32] = {0};
if (!getRootFromChannelHash(_channel_hash, _root_hash)) {
LOG_ERROR("Error getting root hash");
return false;
}
meshtastic_StoreForwardPlusPlus storeforward = meshtastic_StoreForwardPlusPlus_init_zero;
storeforward.sfpp_message_type = meshtastic_StoreForwardPlusPlus_SFPP_message_type_LINK_PROVIDE;
storeforward.encapsulated_to = sqlite3_column_int(fromScratchStmt, 0);
storeforward.encapsulated_from = sqlite3_column_int(fromScratchStmt, 1);
storeforward.encapsulated_id = sqlite3_column_int(fromScratchStmt, 2);
uint8_t *_encrypted = (uint8_t *)sqlite3_column_blob(fromScratchStmt, 3);
storeforward.message.size = sqlite3_column_bytes(fromScratchStmt, 3);
memcpy(storeforward.message.bytes, _encrypted, storeforward.message.size);
uint8_t *_message_hash = (uint8_t *)sqlite3_column_blob(fromScratchStmt, 4);
storeforward.message_hash.size = 32;
memcpy(storeforward.message_hash.bytes, _message_hash, storeforward.message_hash.size);
storeforward.encapsulated_rxtime = sqlite3_column_int(fromScratchStmt, 5);
storeforward.root_hash.size = 32;
memcpy(storeforward.root_hash.bytes, _root_hash, 32);
sqlite3_finalize(fromScratchStmt);
meshtastic_MeshPacket *p = allocDataProtobuf(storeforward);
p->to = NODENUM_BROADCAST;
p->decoded.want_response = false;
p->priority = meshtastic_MeshPacket_Priority_BACKGROUND;
p->channel = 0;
LOG_INFO("Send link to mesh");
service->sendToMesh(p, RX_SRC_LOCAL, true);
return true;
}
bool StoreForwardPlusPlusModule::addToChain(uint32_t to, uint32_t from, uint32_t id, bool want_ack, ChannelHash channel_hash,
uint8_t *encrypted_bytes, size_t encrypted_len, uint8_t *_message_hash,
uint8_t *_chain_hash, uint8_t *_root_hash, uint32_t _rx_time, char *payload_bytes,

View File

@@ -51,6 +51,7 @@ class StoreForwardPlusPlusModule : public ProtobufModule<meshtastic_StoreForward
sqlite3_stmt *removeScratch;
sqlite3_stmt *updatePayloadStmt;
sqlite3_stmt *getPayloadFromScratchStmt;
sqlite3_stmt *fromScratchStmt;
// returns wasfound
bool getRootFromChannelHash(ChannelHash, uint8_t *);
@@ -71,6 +72,8 @@ class StoreForwardPlusPlusModule : public ProtobufModule<meshtastic_StoreForward
bool broadcastLink(uint8_t *, uint8_t *);
bool sendFromScratch(uint8_t);
bool addToChain(uint32_t, uint32_t, uint32_t, bool, ChannelHash, uint8_t *, size_t, uint8_t *, uint8_t *, uint8_t *, uint32_t,
char *, size_t);
bool addToScratch(uint32_t, uint32_t, uint32_t, bool, ChannelHash, uint8_t *, size_t, uint8_t *, uint8_t *, uint32_t, char *,