Edge-Net Genesis Nodes on Google Cloud
Deploy genesis relay nodes as Google Cloud Functions for global edge distribution.
Manage rUv (Resource Utility Vouchers) ledger and bootstrap the network until self-sustaining.
Why Google Cloud Functions?
| Feature |
Benefit |
| Global Edge |
35+ regions, <50ms latency worldwide |
| Auto-scaling |
0 to millions of requests |
| Pay-per-use |
$0 when idle, pennies under load |
| Cold start |
<100ms with min instances |
| WebSocket |
Via Cloud Run for persistent connections |
Prerequisites
Deployment Steps
1. Create Firestore Database
2. Store Genesis Keys
3. Deploy Genesis Functions
4. Deploy WebSocket Relay (Cloud Run)
Genesis Node Code
index.js (Cloud Function)
const functions = require('@google-cloud/functions-framework');
const { Firestore } = require('@google-cloud/firestore');
const { SecretManagerServiceClient } = require('@google-cloud/secret-manager');
const firestore = new Firestore();
const secrets = new SecretManagerServiceClient();
// Genesis node state
let genesisKeys = null;
let ledgerState = null;
// Initialize genesis node
async function init() {
if (genesisKeys) return;
// Load genesis keys from Secret Manager
const [version] = await secrets.accessSecretVersion({
name: 'projects/YOUR_PROJECT/secrets/edge-net-genesis-keys/versions/latest',
});
genesisKeys = JSON.parse(version.payload.data.toString());
// Load or create genesis ledger
const genesisDoc = await firestore.collection('edge-net').doc('genesis').get();
if (!genesisDoc.exists) {
// Create genesis transaction
ledgerState = await createGenesisLedger();
await firestore.collection('edge-net').doc('genesis').set(ledgerState);
} else {
ledgerState = genesisDoc.data();
}
}
// Create genesis ledger with initial supply
async function createGenesisLedger() {
const crypto = require('crypto');
const genesis = {
id: crypto.randomBytes(32).toString('hex'),
type: 'genesis',
amount: 1_000_000_000_000_000, // 1 billion rUv (Resource Utility Vouchers)
recipient: genesisKeys.public,
timestamp: Date.now(),
transactions: [],
tips: [],
totalSupply: 1_000_000_000_000_000,
networkCompute: 0,
nodeCount: 0,
// Genesis sunset thresholds
sunsetPhase: 0, // 0=active, 1=transition, 2=read-only, 3=retired
sunsetThresholds: {
stopNewConnections: 10_000,
readOnlyMode: 50_000,
safeRetirement: 100_000,
},
};
return genesis;
}
// Main handler
functions.http('genesisHandler', async (req, res) => {
// CORS
res.set('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.set('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
return res.status(204).send('');
}
await init();
const { action, data } = req.body || {};
try {
switch (action) {
case 'status':
return res.json({
nodeId: `genesis-${process.env.REGION}`,
region: process.env.REGION,
ledger: {
totalSupply: ledgerState.totalSupply,
networkCompute: ledgerState.networkCompute,
nodeCount: ledgerState.nodeCount,
tipCount: ledgerState.tips.length,
},
multiplier: calculateMultiplier(ledgerState.networkCompute),
currency: 'rUv', // Resource Utility Vouchers
sunsetStatus: getSunsetStatus(ledgerState),
});
case 'register':
return await handleRegister(data, res);
case 'submitTransaction':
return await handleTransaction(data, res);
case 'getTips':
return res.json({ tips: ledgerState.tips.slice(-10) });
case 'sync':
return await handleSync(data, res);
default:
return res.status(400).json({ error: 'Unknown action' });
}
} catch (error) {
console.error('Error:', error);
return res.status(500).json({ error: error.message });
}
});
// Handle node registration
async function handleRegister(data, res) {
const { nodeId, pubkey, stake } = data;
// Validate registration
if (!nodeId || !pubkey) {
return res.status(400).json({ error: 'Missing nodeId or pubkey' });
}
// Store node in Firestore
await firestore.collection('edge-net').doc('nodes').collection(nodeId).set({
pubkey,
stake: stake || 0,
registeredAt: Date.now(),
region: process.env.REGION,
reputation: 0.5,
});
ledgerState.nodeCount++;
return res.json({
success: true,
nodeId,
multiplier: calculateMultiplier(ledgerState.networkCompute),
});
}
// Handle QDAG transaction
async function handleTransaction(data, res) {
const { transaction, signature } = data;
// Validate transaction
if (!validateTransaction(transaction, signature)) {
return res.status(400).json({ error: 'Invalid transaction' });
}
// Apply to ledger
await applyTransaction(transaction);
// Store in Firestore
await firestore.collection('edge-net').doc('transactions')
.collection(transaction.id).set(transaction);
// Update tips
ledgerState.tips = ledgerState.tips.filter(
tip => !transaction.validates.includes(tip)
);
ledgerState.tips.push(transaction.id);
// Sync to other genesis nodes
await syncToOtherNodes(transaction);
return res.json({
success: true,
txId: transaction.id,
newBalance: await getBalance(transaction.sender),
});
}
// Handle ledger sync from other genesis nodes
async function handleSync(data, res) {
const { transactions, fromNode } = data;
let imported = 0;
for (const tx of transactions) {
if (!ledgerState.transactions.find(t => t.id === tx.id)) {
if (validateTransaction(tx, tx.signature)) {
await applyTransaction(tx);
imported++;
}
}
}
return res.json({ imported, total: ledgerState.transactions.length });
}
// Validate transaction signature and structure
function validateTransaction(tx, signature) {
// TODO: Implement full Ed25519 verification
return tx && tx.id && tx.sender && tx.recipient && tx.amount >= 0;
}
// Apply transaction to ledger state
async function applyTransaction(tx) {
ledgerState.transactions.push(tx);
// Update network compute for reward calculation
if (tx.type === 'compute_reward') {
ledgerState.networkCompute += tx.computeHours || 0;
}
// Persist to Firestore
await firestore.collection('edge-net').doc('genesis').update({
transactions: ledgerState.transactions,
tips: ledgerState.tips,
networkCompute: ledgerState.networkCompute,
});
}
// Calculate contribution curve multiplier
function calculateMultiplier(networkCompute) {
const MAX_BONUS = 10.0;
const DECAY_CONSTANT = 1_000_000;
return 1 + (MAX_BONUS - 1) * Math.exp(-networkCompute / DECAY_CONSTANT);
}
// Get genesis sunset status
function getSunsetStatus(ledger) {
const thresholds = ledger.sunsetThresholds || {
stopNewConnections: 10_000,
readOnlyMode: 50_000,
safeRetirement: 100_000,
};
let phase = 0;
let phaseName = 'active';
if (ledger.nodeCount >= thresholds.safeRetirement) {
phase = 3;
phaseName = 'retired';
} else if (ledger.nodeCount >= thresholds.readOnlyMode) {
phase = 2;
phaseName = 'read_only';
} else if (ledger.nodeCount >= thresholds.stopNewConnections) {
phase = 1;
phaseName = 'transition';
}
return {
phase,
phaseName,
nodeCount: ledger.nodeCount,
nextThreshold: phase === 0 ? thresholds.stopNewConnections :
phase === 1 ? thresholds.readOnlyMode :
phase === 2 ? thresholds.safeRetirement : 0,
canRetire: phase >= 3,
message: phase >= 3 ?
'Network is self-sustaining. Genesis nodes can be safely retired.' :
`${((ledger.nodeCount / thresholds.safeRetirement) * 100).toFixed(1)}% to self-sustaining`
};
}
// Get balance for a node
async function getBalance(nodeId) {
let balance = 0;
for (const tx of ledgerState.transactions) {
if (tx.recipient === nodeId) balance += tx.amount;
if (tx.sender === nodeId) balance -= tx.amount;
}
return balance;
}
// Sync transaction to other genesis nodes
async function syncToOtherNodes(transaction) {
const regions = ['us-east1', 'europe-west1', 'asia-east1'];
const currentRegion = process.env.REGION;
for (const region of regions) {
if (region === currentRegion) continue;
try {
const url = `https://${region}-YOUR_PROJECT.cloudfunctions.net/edge-net-genesis-${region}`;
await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'sync',
data: {
transactions: [transaction],
fromNode: `genesis-${currentRegion}`,
},
}),
});
} catch (error) {
console.error(`Failed to sync to ${region}:`, error.message);
}
}
}
package.json
WebSocket Relay (Cloud Run)
Dockerfile
relay.js
Monitoring
Cloud Monitoring Dashboard
dashboard.json
Cost Estimate
| Component |
Monthly Cost (Low Traffic) |
Monthly Cost (High Traffic) |
| Cloud Functions (3 regions) |
$5 |
$50 |
| Cloud Run (WebSocket) |
$10 |
$100 |
| Firestore |
$1 |
$25 |
| Secret Manager |
$0.06 |
$0.06 |
| Total |
~$16 |
~$175 |
Security Checklist
Next Steps
- Deploy to all regions
- Initialize genesis ledger
- Configure DNS with global load balancer
- Set up monitoring and alerting
- Run load tests
- Enable Cloud CDN for static assets