Last active
June 4, 2025 09:47
-
-
Save blahah/44f0d06bc2cbc53d89f195f2febe4ab2 to your computer and use it in GitHub Desktop.
Distributed n-n RPC with request-fulfilment pattern using Autobase/blind-pairing/hypercore ecosystem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const BlindPairing = require('blind-pairing') | |
const Autobase = require('autobase') | |
const Corestore = require('corestore') | |
const Hyperswarm = require('hyperswarm') | |
const crypto = require('hypercore-crypto') | |
const z32 = require('z32') | |
const FUNCTIONS = { | |
add: (a, b) => Number(a) + Number(b), | |
multiply: (a, b) => Number(a) * Number(b), | |
greet: (name) => `Hello ${name} from ${process.pid}!`, | |
fibonacci: (n) => { | |
const num = Number(n) | |
if (num <= 1) return num | |
return FUNCTIONS.fibonacci(num - 1) + FUNCTIONS.fibonacci(num - 2) | |
}, | |
processData: (data) => ({ | |
processed: true, | |
length: data.length, | |
uppercase: data.toUpperCase(), | |
processedBy: process.pid | |
}) | |
} | |
class BlindPairingRPCPeer { | |
constructor(name, isCreator = false) { | |
this.name = name | |
this.isCreator = isCreator | |
this.store = null | |
this.autobase = null | |
this.swarm = new Hyperswarm() | |
this.pairing = new BlindPairing(this.swarm) | |
this.member = null | |
this.pendingRequests = new Map() | |
this.processedMessages = new Set() | |
this.stats = { sent: 0, fulfilled: 0, received: 0 } | |
this.invite = null | |
} | |
log(message, type = 'info') { | |
const time = new Date().toISOString().substr(11, 8) | |
const colors = { alice: 'π΅', bob: 'π’', charlie: 'π£' } | |
const icon = colors[this.name.toLowerCase()] || 'π' | |
console.log(`[${time}] ${icon} ${this.name}: ${message}`) | |
} | |
async start(invite = null) { | |
this.store = new Corestore(`./blind-rpc-${this.name.toLowerCase()}`) | |
// Setup networking FIRST | |
const store = this.store | |
this.swarm.on('connection', async (connection) => { | |
this.log('Connected to peer, setting up replication') | |
await store.replicate(connection) | |
}) | |
if (this.isCreator) { | |
await this.startAsCreator() | |
} else { | |
await this.joinWithInvite(invite) | |
} | |
// Listen for updates | |
this.autobase.on('update', () => { | |
this.processMessages() | |
}) | |
await this.processMessages() | |
} | |
async startAsCreator() { | |
this.log('Starting as creator...') | |
// Create autobase | |
this.autobase = new Autobase(this.store, null, { | |
apply: this.apply.bind(this), | |
open: this.open.bind(this), | |
valueEncoding: 'json' | |
}) | |
await this.autobase.ready() | |
this.log(`Created autobase: ${this.autobase.key.toString('hex').substr(0, 16)}...`) | |
// Get our local writer key and add ourselves as the first writer | |
const localCore = this.store.get({ name: 'local' }) | |
await localCore.ready() | |
const localKey = localCore.key | |
// Add ourselves as the first writer | |
await this.autobase.append({ | |
type: 'addWriter', | |
key: localKey.toString('hex'), | |
addedBy: this.name, | |
timestamp: Date.now() | |
}) | |
await this.autobase.update() | |
this.log(`Added self as first writer - inputs: ${this.autobase.inputs?.length || 0}`) | |
// Setup pairing member to accept joiners | |
this.member = this.pairing.addMember({ | |
discoveryKey: this.autobase.discoveryKey, | |
onadd: (candidate) => this.onAddMember(candidate) | |
}) | |
await this.member.flushed() | |
// Create invite | |
this.invite = await this.createInvite() | |
this.log(`Invite created: ${this.invite}`) | |
// Join swarm | |
const discovery = this.swarm.join(this.autobase.discoveryKey) | |
await discovery.flushed() | |
} | |
async joinWithInvite(invite) { | |
if (!invite) { | |
throw new Error('Invite required for joiners') | |
} | |
this.log(`Joining with invite: ${invite}`) | |
// Get our local writer key to send as userData | |
const localCore = this.store.get({ name: 'writer' }) | |
await localCore.ready() | |
const localKey = localCore.key | |
this.localCore = this.store.get({ name: 'local' }) | |
await this.localCore.ready() | |
const localKey = this.localCore.key | |
// Add candidate to join the creator | |
const candidate = this.pairing.addCandidate({ | |
invite: z32.decode(invite), | |
userData: localKey, | |
onadd: (result) => this.onJoinSuccess(result) | |
}) | |
return new Promise((resolve, reject) => { | |
this.resolveJoin = resolve | |
this.rejectJoin = reject | |
}) | |
} | |
async onJoinSuccess(result) { | |
this.log('Join successful, creating autobase...') | |
// Ensure our local writer core is available in the store before creating autobase | |
if (!this.localCore) { | |
this.localCore = this.store.get({ name: 'local' }) | |
await this.localCore.ready() | |
} | |
this.autobase = new Autobase(this.store, result.key, { | |
apply: this.apply.bind(this), | |
open: this.open.bind(this), | |
valueEncoding: 'json', | |
encryptionKey: result.encryptionKey | |
}) | |
await this.autobase.ready() | |
// Check if autobase uses our local writer core | |
this.log(`Local core key: ${this.localCore.key.toString('hex').substr(0, 16)}...`) | |
this.log(`Autobase local key: ${this.autobase.local.key.toString('hex').substr(0, 16)}...`) | |
this.log(`Joined autobase: ${this.autobase.key.toString('hex').substr(0, 16)}...`) | |
this.log(`Initially writable: ${this.autobase.writable}`) | |
// Join swarm like FlockManager | |
const discovery = this.swarm.join(this.autobase.discoveryKey) | |
await discovery.flushed() | |
// Sync with existing autobase state to receive addWriter messages | |
await this.autobase.update() | |
this.log(`After initial sync - writable: ${this.autobase.writable}, inputs: ${this.autobase.inputs?.length || 0}`) | |
// Wait for autobase to become writable | |
if (this.resolveJoin) { | |
this.waitForWritable() | |
// Give networking time to establish before checking writable status | |
setTimeout(() => { | |
this.waitForWritable() | |
}, 2000) | |
} | |
} | |
waitForWritable() { | |
if (this.autobase.writable) { | |
this.log('β Already writable, resolving join!') | |
this.resolveJoin() | |
return | |
} | |
this.log('β³ Waiting for autobase to become writable...') | |
const check = () => { | |
if (this.autobase.writable) { | |
this.log('β Now writable! Resolving join.') | |
this.autobase.off('update', check) | |
this.resolveJoin() | |
} else { | |
this.log(`β³ Still not writable... inputs: ${this.autobase.inputs?.length || 0}`) | |
} | |
} | |
this.autobase.on('update', check) | |
} | |
async createInvite() { | |
const { invite, publicKey } = BlindPairing.createInvite(this.autobase.key) | |
this.invitePublicKey = publicKey | |
return z32.encode(invite) | |
} | |
async onAddMember(candidate) { | |
this.log(`Received join request from candidate: ${candidate.inviteId.toString('hex').substr(0, 16)}...`) | |
candidate.open(this.invitePublicKey) | |
const writerKey = candidate.userData | |
if (!writerKey) { | |
this.log('No userData received from candidate') | |
return | |
} | |
this.log(`Adding new writer: ${writerKey.toString('hex').substr(0, 16)}...`) | |
// Add the new peer as a writer to the autobase (convert Buffer to hex for JSON encoding) | |
await this.autobase.append({ | |
type: 'addWriter', | |
key: writerKey.toString('hex'), | |
addedBy: this.name, | |
timestamp: Date.now() | |
}) | |
// Update to sync the new writer | |
await this.autobase.update() | |
this.log(`Alice updated after adding writer - inputs: ${this.autobase.inputs?.length || 0}`) | |
// Confirm the pairing | |
candidate.confirm({ | |
key: this.autobase.key, | |
encryptionKey: this.autobase.encryptionKey | |
}) | |
this.log('New writer added successfully') | |
} | |
open(store) { | |
return store.get('messages', { valueEncoding: 'json' }) | |
} | |
async apply(nodes, view, host) { | |
for (const node of nodes) { | |
const message = node.value | |
if (message.type === 'addWriter') { | |
this.log(`Adding writer: ${message.key.substr(0, 16)}... (by ${message.addedBy})`) | |
// Convert hex string back to Buffer | |
await host.addWriter(Buffer.from(message.key, 'hex')) | |
this.log(`Writer added. Now writable: ${this.autobase?.writable || false}`) | |
continue | |
} | |
// Store regular messages | |
if (message.type === 'request' || message.type === 'fulfillment') { | |
await view.append(message) | |
} | |
// Store all non-addWriter messages in view (like FlockManager does) | |
await view.append(message) | |
} | |
} | |
async processMessages() { | |
try { | |
// Force update to sync with other writers | |
await this.autobase.update() | |
if (!this.autobase.view) { | |
this.log('No view available yet') | |
return | |
} | |
this.log(`Processing messages, view length: ${this.autobase.view.length}, writable: ${this.autobase.writable}, inputs: ${this.autobase.inputs?.length || 0}`) | |
const length = this.autobase.view.length | |
for (let i = 0; i < length; i++) { | |
const message = await this.autobase.view.get(i) | |
if (!message) continue | |
const messageId = `${message.id || i}-${message.type}-${message.from}` | |
if (this.processedMessages.has(messageId)) continue | |
this.processedMessages.add(messageId) | |
await this.handleMessage(message) | |
} | |
} catch (error) { | |
this.log(`Error processing messages: ${error.message}`) | |
} | |
} | |
async handleMessage(message) { | |
switch (message.type) { | |
case 'request': | |
await this.handleRequest(message) | |
break | |
case 'fulfillment': | |
this.handleFulfillment(message) | |
break | |
} | |
} | |
async handleRequest(request) { | |
const { id, functionName, args, from } = request | |
if (from === this.name) return | |
this.log(`RPC request: ${functionName}(${args.join(', ')}) from ${from}`) | |
// Check if already fulfilled | |
const fulfilled = await this.findFulfillment(id) | |
if (fulfilled) { | |
this.log(`Already fulfilled by ${fulfilled.fulfilledBy}`) | |
return | |
} | |
// Random chance to fulfill | |
if (Math.random() > 0.5) { | |
this.log('Decided not to fulfill') | |
return | |
} | |
// Fulfill after delay | |
setTimeout(() => this.fulfillRequest(request), Math.random() * 1500 + 500) | |
} | |
async findFulfillment(requestId) { | |
if (!this.autobase.view) return null | |
const length = this.autobase.view.length | |
for (let i = 0; i < length; i++) { | |
const message = await this.autobase.view.get(i) | |
if (message && message.type === 'fulfillment' && message.requestId === requestId) { | |
return message | |
} | |
} | |
return null | |
} | |
async fulfillRequest(request) { | |
const { id, functionName, args, from } = request | |
// Double-check not fulfilled | |
const existing = await this.findFulfillment(id) | |
if (existing) { | |
this.log(`Race lost to ${existing.fulfilledBy}`) | |
return | |
} | |
this.log(`Fulfilling: ${functionName}(${args.join(', ')})`) | |
try { | |
if (!FUNCTIONS[functionName]) { | |
throw new Error(`Unknown function: ${functionName}`) | |
} | |
const result = FUNCTIONS[functionName](...args) | |
await this.autobase.append({ | |
type: 'fulfillment', | |
id: crypto.randomBytes(16).toString('hex'), | |
requestId: id, | |
result, | |
success: true, | |
fulfilledBy: this.name, | |
originalRequester: from, | |
timestamp: Date.now() | |
}) | |
this.stats.fulfilled++ | |
this.log(`β Fulfilled: ${JSON.stringify(result)}`) | |
} catch (error) { | |
await this.autobase.append({ | |
type: 'fulfillment', | |
id: crypto.randomBytes(16).toString('hex'), | |
requestId: id, | |
error: error.message, | |
success: false, | |
fulfilledBy: this.name, | |
originalRequester: from, | |
timestamp: Date.now() | |
}) | |
this.log(`β Failed: ${error.message}`) | |
} | |
} | |
handleFulfillment(fulfillment) { | |
const { requestId, result, error, success, fulfilledBy, originalRequester } = fulfillment | |
if (originalRequester !== this.name) return | |
if (this.pendingRequests.has(requestId)) { | |
const { resolve, reject, startTime } = this.pendingRequests.get(requestId) | |
const duration = Date.now() - startTime | |
if (success) { | |
this.log(`Got result from ${fulfilledBy} (${duration}ms): ${JSON.stringify(result)}`) | |
resolve(result) | |
} else { | |
this.log(`Got error from ${fulfilledBy}: ${error}`) | |
reject(new Error(error)) | |
} | |
this.pendingRequests.delete(requestId) | |
this.stats.received++ | |
} | |
} | |
async callFunction(functionName, ...args) { | |
if (!this.autobase.writable) { | |
this.log(`Cannot call function - writable: ${this.autobase.writable}, inputs: ${this.autobase.inputs?.length || 0}`) | |
throw new Error('Not a writer yet') | |
} | |
return new Promise(async (resolve, reject) => { | |
const requestId = crypto.randomBytes(16).toString('hex') | |
const request = { | |
type: 'request', | |
id: requestId, | |
functionName, | |
args, | |
from: this.name, | |
timestamp: Date.now() | |
} | |
this.pendingRequests.set(requestId, { | |
resolve, | |
reject, | |
startTime: Date.now() | |
}) | |
setTimeout(() => { | |
if (this.pendingRequests.has(requestId)) { | |
this.pendingRequests.delete(requestId) | |
reject(new Error('Request timeout')) | |
} | |
}, 8000) | |
this.log(`Calling: ${functionName}(${args.join(', ')})`) | |
await this.autobase.append(request) | |
this.stats.sent++ | |
}) | |
} | |
async cleanup() { | |
if (this.member) await this.member.close() | |
await this.pairing.close() | |
await this.swarm.destroy() | |
await this.store.close() | |
} | |
} | |
class BlindPairingDemo { | |
constructor() { | |
this.peers = [] | |
} | |
log(message) { | |
const time = new Date().toISOString().substr(11, 8) | |
console.log(`[${time}] π¬ DEMO: ${message}`) | |
} | |
sleep(ms) { | |
return new Promise(resolve => setTimeout(resolve, ms)) | |
} | |
async run() { | |
console.log('π Distributed RPC with Blind-Pairing Multi-Writer') | |
console.log('===================================================') | |
console.log('This demo shows:') | |
console.log('1. Alice creates autobase and invite') | |
console.log('2. Bob and Charlie use invite to join securely') | |
console.log('3. All peers become writers automatically') | |
console.log('4. Distributed RPC calls work between all peers\n') | |
try { | |
// Create Alice (creator) | |
this.log('Creating Alice as creator...') | |
const alice = new BlindPairingRPCPeer('Alice', true) | |
await alice.start() | |
const invite = alice.invite | |
this.log(`Alice created invite: ${invite}`) | |
await this.sleep(2000) | |
// Create Bob and Charlie as joiners | |
this.log('Bob and Charlie joining with invite...') | |
const bob = new BlindPairingRPCPeer('Bob', false) | |
const charlie = new BlindPairingRPCPeer('Charlie', false) | |
this.peers = [alice, bob, charlie] | |
// Join simultaneously | |
await Promise.all([ | |
bob.start(invite), | |
charlie.start(invite) | |
]) | |
this.log('All peers connected, waiting for writer setup...') | |
// Wait for all peers to become writable | |
this.log('Waiting for all peers to become writable...') | |
let attempts = 0 | |
while (attempts < 30) { // 30 second timeout | |
// Force updates on all peers | |
for (const peer of this.peers) { | |
if (peer.autobase) { | |
await peer.autobase.update() | |
} | |
} | |
const writableStatus = this.peers.map(p => `${p.name}:${p.autobase?.writable || false}(${p.autobase?.inputs?.length || 0})`).join(', ') | |
this.log(`Writable status: ${writableStatus}`) | |
if (this.peers.every(p => p.autobase?.writable)) { | |
this.log('β All peers are now writable!') | |
break | |
} | |
await this.sleep(1000) | |
attempts++ | |
} | |
if (attempts >= 30) { | |
this.log('β οΈ Timeout waiting for all peers to become writable') | |
} | |
// Test RPC calls | |
this.log('Testing distributed RPC calls...') | |
const requests = [ | |
{ peer: alice, func: 'add', args: ['15', '25'] }, | |
{ peer: bob, func: 'greet', args: ['World'] }, | |
{ peer: charlie, func: 'fibonacci', args: ['7'] }, | |
{ peer: alice, func: 'processData', args: ['test-data'] }, | |
{ peer: bob, func: 'multiply', args: ['6', '7'] } | |
] | |
for (const req of requests) { | |
try { | |
const result = await req.peer.callFunction(req.func, ...req.args) | |
req.peer.log(`π Result: ${JSON.stringify(result)}`) | |
} catch (error) { | |
req.peer.log(`π₯ Failed: ${error.message}`) | |
} | |
await this.sleep(2000) | |
} | |
this.log('β Blind-pairing RPC demo completed!') | |
this.log('Key features demonstrated:') | |
this.log('- Secure writer addition via blind-pairing') | |
this.log('- No manual key exchange needed') | |
this.log('- Automatic multi-writer setup') | |
this.log('- Distributed RPC with race conditions') | |
// Show stats | |
for (const peer of this.peers) { | |
console.log(` ${peer.name}: Sent=${peer.stats.sent}, Fulfilled=${peer.stats.fulfilled}, Received=${peer.stats.received}`) | |
} | |
} catch (error) { | |
this.log(`β Demo failed: ${error.message}`) | |
console.error(error) | |
} finally { | |
// Cleanup | |
for (const peer of this.peers) { | |
try { | |
await peer.cleanup() | |
} catch (e) { | |
// Ignore cleanup errors | |
} | |
} | |
// Clean up demo files | |
try { | |
const fs = require('fs') | |
const files = fs.readdirSync('.') | |
for (const file of files) { | |
if (file.startsWith('blind-rpc-')) { | |
fs.rmSync(file, { recursive: true, force: true }) | |
} | |
} | |
} catch (e) { | |
// Ignore cleanup errors | |
} | |
process.exit(0) | |
} | |
} | |
} | |
if (require.main === module) { | |
const demo = new BlindPairingDemo() | |
demo.run().catch(console.error) | |
} | |
module.exports = BlindPairingRPCPeer |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
β distributed-rpc node blind-pairing-rpc.js | |
π Distributed RPC with Blind-Pairing Multi-Writer | |
=================================================== | |
This demo shows: | |
1. Alice creates autobase and invite | |
2. Bob and Charlie use invite to join securely | |
3. All peers become writers automatically | |
4. Distributed RPC calls work between all peers | |
[16:26:43] π¬ DEMO: Creating Alice as creator... | |
[16:26:43] π΅ Alice: Starting as creator... | |
[16:26:43] π΅ Alice: Created autobase: d8a35450a2958ced... | |
[16:26:43] π΅ Alice: Adding writer: d8a35450a2958ced... (by Alice) | |
[16:26:43] π΅ Alice: Writer added. Now writable: true | |
[16:26:43] π΅ Alice: Added self as first writer - inputs: 0 | |
[16:26:48] π΅ Alice: Invite created: yryss9yrwkag4nsa5s78jtqbq8s567mrhxux9psp389w8sxbfspxj3ccu8nna4rh1jeoatsk1ddsm9ecg9xci5bmdnbkcknr47a4b8scnc | |
[16:26:50] π΅ Alice: Processing messages, view length: 0, writable: true, inputs: 0 | |
[16:26:50] π¬ DEMO: Alice created invite: yryss9yrwkag4nsa5s78jtqbq8s567mrhxux9psp389w8sxbfspxj3ccu8nna4rh1jeoatsk1ddsm9ecg9xci5bmdnbkcknr47a4b8scnc | |
[16:26:52] π¬ DEMO: Bob and Charlie joining with invite... | |
[16:26:52] π’ Bob: Joining with invite: yryss9yrwkag4nsa5s78jtqbq8s567mrhxux9psp389w8sxbfspxj3ccu8nna4rh1jeoatsk1ddsm9ecg9xci5bmdnbkcknr47a4b8scnc | |
[16:26:52] π£ Charlie: Joining with invite: yryss9yrwkag4nsa5s78jtqbq8s567mrhxux9psp389w8sxbfspxj3ccu8nna4rh1jeoatsk1ddsm9ecg9xci5bmdnbkcknr47a4b8scnc | |
[16:26:55] π’ Bob: Connected to peer, setting up replication | |
[16:26:55] π΅ Alice: Connected to peer, setting up replication | |
[16:26:55] π΅ Alice: Received join request from candidate: f94b867a638f2781... | |
[16:26:55] π΅ Alice: Adding new writer: 5bda8aff3fa2a126... | |
[16:26:55] π΅ Alice: Adding writer: 5bda8aff3fa2a126... (by Alice) | |
[16:26:55] π΅ Alice: Writer added. Now writable: true | |
[16:26:55] π΅ Alice: Processing messages, view length: 0, writable: true, inputs: 0 | |
[16:26:55] π΅ Alice: Alice updated after adding writer - inputs: 0 | |
[16:26:55] π΅ Alice: New writer added successfully | |
[16:26:55] π’ Bob: Join successful, creating autobase... | |
[16:26:55] π’ Bob: Local core key: 5bda8aff3fa2a126... | |
[16:26:55] π’ Bob: Autobase local key: 5bda8aff3fa2a126... | |
[16:26:55] π’ Bob: Joined autobase: d8a35450a2958ced... | |
[16:26:55] π’ Bob: Initially writable: false | |
[16:26:55] π’ Bob: Adding writer: d8a35450a2958ced... (by Alice) | |
[16:26:55] π’ Bob: Writer added. Now writable: false | |
[16:26:55] π’ Bob: Adding writer: 5bda8aff3fa2a126... (by Alice) | |
[16:26:55] π’ Bob: Writer added. Now writable: true | |
[16:26:55] π’ Bob: Adding writer: 5bda8aff3fa2a126... (by Alice) | |
[16:26:55] π’ Bob: Writer added. Now writable: true | |
[16:26:55] π£ Charlie: Connected to peer, setting up replication | |
[16:26:55] π΅ Alice: Connected to peer, setting up replication | |
[16:26:55] π΅ Alice: Received join request from candidate: f94b867a638f2781... | |
[16:26:55] π΅ Alice: Adding new writer: 7518f9756d5935a8... | |
[16:26:55] π΅ Alice: Adding writer: 7518f9756d5935a8... (by Alice) | |
[16:26:55] π΅ Alice: Writer added. Now writable: true | |
[16:26:55] π΅ Alice: Processing messages, view length: 0, writable: true, inputs: 0 | |
[16:26:55] π΅ Alice: Alice updated after adding writer - inputs: 0 | |
[16:26:55] π΅ Alice: New writer added successfully | |
[16:26:55] π£ Charlie: Join successful, creating autobase... | |
[16:26:55] π’ Bob: Adding writer: 7518f9756d5935a8... (by Alice) | |
[16:26:55] π’ Bob: Writer added. Now writable: true | |
[16:26:55] π£ Charlie: Local core key: 7518f9756d5935a8... | |
[16:26:55] π£ Charlie: Autobase local key: 7518f9756d5935a8... | |
[16:26:55] π£ Charlie: Joined autobase: d8a35450a2958ced... | |
[16:26:55] π£ Charlie: Initially writable: false | |
[16:26:55] π£ Charlie: Adding writer: d8a35450a2958ced... (by Alice) | |
[16:26:55] π£ Charlie: Writer added. Now writable: false | |
[16:26:55] π£ Charlie: Adding writer: 5bda8aff3fa2a126... (by Alice) | |
[16:26:55] π£ Charlie: Writer added. Now writable: false | |
[16:26:55] π£ Charlie: Adding writer: 7518f9756d5935a8... (by Alice) | |
[16:26:55] π£ Charlie: Writer added. Now writable: true | |
[16:26:55] π£ Charlie: Adding writer: 5bda8aff3fa2a126... (by Alice) | |
[16:26:55] π£ Charlie: Writer added. Now writable: false | |
[16:26:55] π£ Charlie: Adding writer: 7518f9756d5935a8... (by Alice) | |
[16:26:55] π£ Charlie: Writer added. Now writable: true | |
[16:26:59] π£ Charlie: After initial sync - writable: true, inputs: 0 | |
[16:27:00] π’ Bob: After initial sync - writable: true, inputs: 0 | |
[16:27:01] π’ Bob: Connected to peer, setting up replication | |
[16:27:01] π£ Charlie: Connected to peer, setting up replication | |
[16:27:01] π΅ Alice: Processing messages, view length: 0, writable: true, inputs: 0 | |
[16:27:01] π΅ Alice: Processing messages, view length: 0, writable: true, inputs: 0 | |
[16:27:01] π£ Charlie: β Already writable, resolving join! | |
[16:27:01] π£ Charlie: Processing messages, view length: 0, writable: true, inputs: 0 | |
[16:27:02] π’ Bob: β Already writable, resolving join! | |
[16:27:02] π’ Bob: Processing messages, view length: 0, writable: true, inputs: 0 | |
[16:27:02] π¬ DEMO: All peers connected, waiting for writer setup... | |
[16:27:02] π¬ DEMO: Waiting for all peers to become writable... | |
[16:27:02] π¬ DEMO: Writable status: Alice:true(0), Bob:true(0), Charlie:true(0) | |
[16:27:02] π¬ DEMO: β All peers are now writable! | |
[16:27:02] π¬ DEMO: Testing distributed RPC calls... | |
[16:27:02] π΅ Alice: Calling: add(15, 25) | |
[16:27:02] π΅ Alice: Processing messages, view length: 1, writable: true, inputs: 0 | |
[16:27:02] π’ Bob: Processing messages, view length: 1, writable: true, inputs: 0 | |
[16:27:02] π’ Bob: RPC request: add(15, 25) from Alice | |
[16:27:02] π£ Charlie: Processing messages, view length: 1, writable: true, inputs: 0 | |
[16:27:02] π’ Bob: Decided not to fulfill | |
[16:27:02] π£ Charlie: RPC request: add(15, 25) from Alice | |
[16:27:02] π£ Charlie: Decided not to fulfill | |
[16:27:10] π΅ Alice: π₯ Failed: Request timeout | |
[16:27:12] π’ Bob: Calling: greet(World) | |
[16:27:12] π’ Bob: Processing messages, view length: 2, writable: true, inputs: 0 | |
[16:27:12] π£ Charlie: Processing messages, view length: 2, writable: true, inputs: 0 | |
[16:27:12] π£ Charlie: RPC request: greet(World) from Bob | |
[16:27:12] π΅ Alice: Processing messages, view length: 2, writable: true, inputs: 0 | |
[16:27:12] π£ Charlie: Decided not to fulfill | |
[16:27:12] π΅ Alice: RPC request: greet(World) from Bob | |
[16:27:12] π΅ Alice: Decided not to fulfill | |
[16:27:20] π’ Bob: π₯ Failed: Request timeout | |
[16:27:22] π£ Charlie: Calling: fibonacci(7) | |
[16:27:22] π£ Charlie: Processing messages, view length: 3, writable: true, inputs: 0 | |
[16:27:22] π΅ Alice: Processing messages, view length: 3, writable: true, inputs: 0 | |
[16:27:22] π’ Bob: Processing messages, view length: 3, writable: true, inputs: 0 | |
[16:27:22] π΅ Alice: RPC request: fibonacci(7) from Charlie | |
[16:27:22] π’ Bob: RPC request: fibonacci(7) from Charlie | |
[16:27:22] π’ Bob: Decided not to fulfill | |
[16:27:24] π΅ Alice: Fulfilling: fibonacci(7) | |
[16:27:24] π΅ Alice: β Fulfilled: 13 | |
[16:27:24] π΅ Alice: Processing messages, view length: 4, writable: true, inputs: 0 | |
[16:27:24] π£ Charlie: Processing messages, view length: 4, writable: true, inputs: 0 | |
[16:27:24] π’ Bob: Processing messages, view length: 4, writable: true, inputs: 0 | |
[16:27:24] π£ Charlie: Got result from Alice (1944ms): 13 | |
[16:27:24] π£ Charlie: π Result: 13 | |
[16:27:26] π΅ Alice: Calling: processData(test-data) | |
[16:27:26] π΅ Alice: Processing messages, view length: 5, writable: true, inputs: 0 | |
[16:27:26] π’ Bob: Processing messages, view length: 5, writable: true, inputs: 0 | |
[16:27:26] π£ Charlie: Processing messages, view length: 5, writable: true, inputs: 0 | |
[16:27:26] π’ Bob: RPC request: processData(test-data) from Alice | |
[16:27:26] π£ Charlie: RPC request: processData(test-data) from Alice | |
[16:27:26] π£ Charlie: Fulfilling: processData(test-data) | |
[16:27:26] π£ Charlie: β Fulfilled: {"processed":true,"length":9,"uppercase":"TEST-DATA","processedBy":20442} | |
[16:27:26] π£ Charlie: Processing messages, view length: 6, writable: true, inputs: 0 | |
[16:27:26] π£ Charlie: Processing messages, view length: 6, writable: true, inputs: 0 | |
[16:27:26] π΅ Alice: Processing messages, view length: 6, writable: true, inputs: 0 | |
[16:27:26] π’ Bob: Processing messages, view length: 6, writable: true, inputs: 0 | |
[16:27:26] π΅ Alice: Got result from Charlie (536ms): {"processed":true,"length":9,"uppercase":"TEST-DATA","processedBy":20442} | |
[16:27:26] π΅ Alice: π Result: {"processed":true,"length":9,"uppercase":"TEST-DATA","processedBy":20442} | |
[16:27:27] π’ Bob: Race lost to Charlie | |
[16:27:28] π’ Bob: Calling: multiply(6, 7) | |
[16:27:28] π’ Bob: Processing messages, view length: 7, writable: true, inputs: 0 | |
[16:27:28] π£ Charlie: Processing messages, view length: 7, writable: true, inputs: 0 | |
[16:27:28] π΅ Alice: Processing messages, view length: 7, writable: true, inputs: 0 | |
[16:27:28] π£ Charlie: RPC request: multiply(6, 7) from Bob | |
[16:27:28] π΅ Alice: RPC request: multiply(6, 7) from Bob | |
[16:27:28] π΅ Alice: Decided not to fulfill | |
[16:27:29] π£ Charlie: Fulfilling: multiply(6, 7) | |
[16:27:29] π£ Charlie: β Fulfilled: 42 | |
[16:27:29] π£ Charlie: Processing messages, view length: 8, writable: true, inputs: 0 | |
[16:27:29] π£ Charlie: Processing messages, view length: 8, writable: true, inputs: 0 | |
[16:27:29] π΅ Alice: Processing messages, view length: 8, writable: true, inputs: 0 | |
[16:27:29] π’ Bob: Processing messages, view length: 8, writable: true, inputs: 0 | |
[16:27:29] π’ Bob: Got result from Charlie (927ms): 42 | |
[16:27:29] π’ Bob: π Result: 42 | |
[16:27:31] π¬ DEMO: β Blind-pairing RPC demo completed! | |
[16:27:31] π¬ DEMO: Key features demonstrated: | |
[16:27:31] π¬ DEMO: - Secure writer addition via blind-pairing | |
[16:27:31] π¬ DEMO: - No manual key exchange needed | |
[16:27:31] π¬ DEMO: - Automatic multi-writer setup | |
[16:27:31] π¬ DEMO: - Distributed RPC with race conditions | |
Alice: Sent=2, Fulfilled=1, Received=1 | |
Bob: Sent=2, Fulfilled=0, Received=1 | |
Charlie: Sent=1, Fulfilled=2, Received=1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment