Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/logic/mqtt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ import { State, TransactionRecord } from "../types";
import { getProverURL, sendPendingTransactionsToProver } from "./verify";
import { decodePayload } from "./decode";
import { verifyPayloadSignature } from "../utils";
import { pruneAndSyncOnchain } from "./sync";

const SYNC_EPOCH = 100; // after 100 transactions, sync with blockchain

export function handleUplinks() {
const client = connect({
Expand Down Expand Up @@ -52,10 +55,9 @@ export async function handleMessage(blob: Buffer) {

console.log("[info] Received uplink from device:", JSON.stringify(message));

const payload = Buffer.from(message["data"], "base64");
// encode transaction into standard format (payload is hex string)
// format: nonce | energy | signature | voltage | device_id | longitude | latitude
const transactionHex = payload;
const transactionHex = Buffer.from(message["data"], "base64");
const decoded = decodePayload(transactionHex);
let publicKey = decoded.extensions.deviceId;
let payloadHadPublicKey = !!publicKey;
Expand Down Expand Up @@ -110,12 +112,25 @@ export async function handleMessage(blob: Buffer) {
}
}

const m3ter = getMeterByPublicKey(`0x${publicKey}`) ?? null;
let m3ter = getMeterByPublicKey(`0x${publicKey}`) ?? null;

if (!m3ter) {
throw new Error("Meter not found for public key: " + publicKey);
}

if (m3ter.latestNonce % SYNC_EPOCH === 0) {
// sync with blockchain every SYNC_EPOCH transactions
await pruneAndSyncOnchain(m3ter.tokenId);

console.log("[info] Synced meter with blockchain:", m3ter.tokenId);

m3ter = getMeterByPublicKey(`0x${publicKey}`) ?? null;

if (!m3ter) {
throw new Error("Meter not found after sync for public key: " + publicKey);
}
}

console.log(
"[info] Received blob for meter",
m3ter?.tokenId,
Expand Down
31 changes: 17 additions & 14 deletions src/logic/sync.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import { getAllMeterRecords, pruneTransactionsBefore, updateMeterNonce } from "../store/sqlite";
import { getMeterByPublicKey, getMeterByTokenId, pruneTransactionsBefore, updateMeterNonce } from "../store/sqlite";
import { rollup as rollupContract } from "./context";

export async function pruneAndSyncWithBlockchain() {
// Get all meter records from the local database
const meters = getAllMeterRecords();
export async function pruneAndSyncOnchain(meterIdentifier: number | string): Promise<number> {
const meter = typeof meterIdentifier === "number" ? getMeterByTokenId(meterIdentifier) : getMeterByPublicKey(meterIdentifier);

for (const meter of meters) {
const { publicKey, latestNonce } = meter;
if (!meter) {
throw new Error(`Meter with identifier ${meterIdentifier} not found`);
}

// Check the latest nonce on the blockchain
const blockchainNonce = Number(await rollupContract.nonce(meter.tokenId));
// Check the latest nonce on the blockchain
const onchainNonce = Number(await rollupContract.nonce(meter.tokenId));
const latestNonce = meter.latestNonce;

if (blockchainNonce > latestNonce) {
// If the blockchain nonce is greater, update the local record
updateMeterNonce(publicKey, blockchainNonce);
// prune transactions with nonce less than or equal to blockchainNonce
pruneTransactionsBefore(meter.tokenId, blockchainNonce);
}
if (onchainNonce > latestNonce) {
const publicKey = meter.publicKey;
// If the onchain nonce is greater, update the local record
updateMeterNonce(publicKey, onchainNonce);
}
// prune transactions with nonce less than or equal to onchainNonce
pruneTransactionsBefore(meter.tokenId, onchainNonce);

return onchainNonce;
}
2 changes: 1 addition & 1 deletion src/store/sqlite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ export function getMeterByDevEui(devEui: string): MeterRecord | null {
}
}

export function getMeterByTokenId(tokenId: string): MeterRecord | null {
export function getMeterByTokenId(tokenId: number): MeterRecord | null {
try {
const result = getMeterByTokenIdQuery.get(tokenId) as MeterRecord | undefined;
return result || null;
Expand Down