Implementing this Node.js blockhain on a network - node.js

I am looking at this Blockchain from firebase. https://github.com/fireship-io/node-blockchain/blob/main/index.ts
The Blockchain is simple enough. There are many similar examples of blockchain implementations, but I don't really see any that are actually used in a network. I am trying to get some footing for implementing this, at least with 2 users to start.
The thing I'm confused about at the moment is what actually gets shared between users? Is it the chain itself? Just new transactions? When a user does Wallet.sendMoney(5, satoshi.publicKey), it would update the local wallet, but then what? I'm guessing send the transaction to others on the network, but then each copy of the blockchain adds/verifies independently. This seems problematic because some of the transactions could get lost (internet outage or whatever), which makes me wonder if the whole blockchain gets sent, yet this seems unwieldy.

The thing I'm confused about at the moment is what actually gets
shared between users?
You meant between nodes not "users". All the nodes should have the same chain and transactions. So you have to implement a pub-sub system to listen for certain events and also publish the transaction and chain. Using redis, you can create a class. I explained on code:
// Note that redis stores strings.
const redis = require("redis");
// create two channels to transfer data
const CHANNELS = {
BLOCKCHAIN: "BLOCKCHAIN",
TRANSACTION: "TRANSACTION",
};
// unlike socket, we do not need to know the address of otehr nodes
// ---------------------------HERE IS BROADCASTING STATION---------------------
// it writes multiple processes to communicate over channels.
class PubSub {
constructor({ blockchain, transactionPool }) {
// it is able to broadcast its chain and replacing the valid chain
this.blockchain = blockchain;
this.transactionPool = transactionPool;
this.publisher = redis.createClient();
this.subscriber = redis.createClient();
this.subscribeToChannels();
// this.subscriber.on("message", (channel, message) => {
// return this.handleMessage(channel, message);
// });
this.subscriber.on("message", (channel, message) =>
this.handleMessage(channel, message)
);
}
// we are listening all channels
subscribeToChannels() {
Object.values(CHANNELS).forEach((channel) => {
this.subscriber.subscribe(channel);
});
}
publish({ channel, message }) {
//we unsubscrive so we dont send message to ourselves
// we subscribe again to receive messages
this.subscriber.unsubscribe(channel, () => {
this.publisher.publish(channel, message, () => {
this.subscriber.subscribe(channel);
});
});
}
// ------THIS IS WHERE BROADCASTING DONE-------------
handleMessage(channel, message) {
const parsedMessage = JSON.parse(message);
switch (channel) {
case CHANNELS.BLOCKCHAIN:
this.blockchain.replaceChain(parsedMessage, true, () => {
// we need to clear local transaction pool becasue we got a new chain
this.transactionPool.clearBlockchainTransactions({
chain: parsedMessage,
});
});
break;
case CHANNELS.TRANSACTION:
console.log("this in pubsusb", this.transactionPool);
this.transactionPool.setTransaction(parsedMessage);
break;
default:
return;
}
}
broadcastChain() {
this.publish({
channel: CHANNELS.BLOCKCHAIN,
message: JSON.stringify(this.blockchain.chain),
});
}
broadcastTransaction(transaction) {
this.publish({
channel: CHANNELS.TRANSACTION,
message: JSON.stringify(transaction),
});
}
}
export default PubSub;

Related

Solace via NodeJS Not Waiting for Success

I'm trying to get Solace (a queuing system) to create a session, then send a message on that session. Instead, it listens to my session creation, receives all the event handlers (I registered all of them), fails to create that session and fails to tell me why. I cannot get this to WAIT for completion. I suspect if it had a few more microseconds, the session would be completed. The promises I have are not being kept. Any awaits that I put in are dutifully ignored.
The Typescript code below is attempting to make a connection to Solace to put a message on a queue. At a high level, it works by getting an instance of the Solace module, then it creates a Session, then with that session, it sends the message. Session creation returns an actual Session and not a promise. That doesn't mean it actually works though. Instead, you have to register an event handler. Because I don't see any of the console.log()s, I believe the createSession event handlers are not being run. Despite registering an event handler for every error in the session handler, Solace neither made the connection, nor said why. As far as I can tell, there's no concept of getting the current state of the session either.
Please note, in previous attempts, I was getting a WaitingForDNS error on the send. It also runs relatively quickly, so I don't think it's doing very much. When I turned on tracing, the most I could tell is that eventually Solace decided to resolve the IP address.
Please see my wishes annotated below:
export class TopicPublisher {
public async connect() {
// Return me a Promise for the Session; either the Session is fully loaded
// loaded, or it's rejected
return new Promise<Session>((resolve, reject) => {
if (this.session !== null) {
this.log("Already connected and ready to publish");
reject();
}
try {
this.session = this.solace.SolclientFactory.createSession({
// solace.SessionProperties
url: this.hosturl,
vpnName: this.vpn,
userName: this.username,
password: this.pass,
connectRetries: 1,
});
} catch (error: any) {
this.log('Error on creating session: ' + error.toString());
reject(error);
}
//The UP_NOTICE dictates whether the session has been established
this.session.on(solace.SessionEventCode.UP_NOTICE, () => {
// *** At this point, return the session as a successfully completing promise ***
this.log("=== Successfully connected and ready to subscribe. ===");
resolve(this.session);
});
//The CONNECT_FAILED_ERROR implies a connection failure
this.session.on(solace.SessionEventCode.CONNECT_FAILED_ERROR, (sessionEvent: { infoStr: string; }) => {
this.log("Connection failed to the message router: " + sessionEvent.infoStr + " - check correct parameter values and connectivity!");
reject(`Check the settings in game-config.ts and try again!`);
});
// Register every event handler in vain attempt at getting Solace to tell me
// why it does not work
let otherErrors = [
solace.SessionEventCode.DOWN_ERROR,
solace.SessionEventCode.REJECTED_MESSAGE_ERROR,
solace.SessionEventCode.SUBSCRIPTION_ERROR,
solace.SessionEventCode.SUBSCRIPTION_OK,
solace.SessionEventCode.VIRTUALROUTER_NAME_CHANGED,
solace.SessionEventCode.REQUEST_ABORTED,
solace.SessionEventCode.REQUEST_TIMEOUT,
solace.SessionEventCode.PROPERTY_UPDATE_OK,
solace.SessionEventCode.PROPERTY_UPDATE_ERROR,
solace.SessionEventCode.CAN_ACCEPT_DATA,
solace.SessionEventCode.RECONNECTING_NOTICE,
solace.SessionEventCode.RECONNECTED_NOTICE,
solace.SessionEventCode.REPUBLISHING_UNACKED_MESSAGES,
solace.SessionEventCode.ACKNOWLEDGED_MESSAGE,
solace.SessionEventCode.UNSUBSCRIBE_TE_TOPIC_OK,
solace.SessionEventCode.UNSUBSCRIBE_TE_TOPIC_ERROR,
solace.SessionEventCode.MESSAGE,
solace.SessionEventCode.GUARANTEED_MESSAGE_PUBLISHER_DOWN
];
for (let errorCodeIndex = 0; errorCodeIndex < otherErrors.length; errorCodeIndex++) {
this.log('Registering error handler code: '+otherErrors[errorCodeIndex]);
this.session.on(otherErrors[errorCodeIndex], (sessionEvent: { infoStr: string; }) => {
this.log("Connection failed with error code : " + otherErrors[errorCodeIndex] + " " + sessionEvent.infoStr);
reject(`Check the config settings`);
});
}
//DISCONNECTED implies the client was disconnected
this.session.on(solace.SessionEventCode.DISCONNECTED, (sessionEvent: any) => {
this.log("Disconnected.");
if (this.session !== null) {
this.session.dispose();
//this.subscribed = false;
this.session = null;
}
});
try {
this.session.connect();
} catch (error: any) {
reject();
}
});
};
public async publish(topicName: string, payload: any) {
// This builds a message payload, it works fine
let solaceMessage = this.getSolaceMessage(topicName, payload);
try {
// *** It does *not* wait for the connection ***
console.log('##This point is reached');
let localSession = await this.connect();
// UP_EVENT ***SHOULD*** have happened, but it does not wait for any events
// or promises to be completed.
console.log('##This point is reached');
console.log('localSession =' + localSession);
localSession.send(solaceMessage);
} catch (error) {
}
};
}
let topicPublisher: TopicPublisher = new TopicPublisher(getInitializedSolaceModule(),
argumentParser.hosturl,
argumentParser.usernamevpn,
argumentParser.username,
argumentParser.vpn,
argumentParser.pass,
argumentParser.topicName);
topicPublisher.publish(argumentParser.topicName, readMessageFromFile(argumentParser.messageFileSpecification)).then(() => {
console.log('##This point is reached');
}, () => {
console.log('##BP10.5 Error handler on publish');
}
).catch(error => {
console.log('publish error' + error);
});
console.log('##This point is reached');
topicPublisher.disconnect();
console.log('##This point is reached');
Solace API documentation is at https://docs.solace.com/API-Developer-Online-Ref-Documentation/nodejs/index.html, but I'm not sure this is a Solace error.
I don't have great exposure to TypeScript - is it possible that the check 'this.session !== null' ends up rejecting the promise, and no session is created. An uninitialized value, if it holds undefined, a !== null check would fail. Maybe your log output sequence can shed light on this.
My apologies, this is a silly point, and not offering any direct help.

How to emit socket to specific socket connection?

In my node app,
socket.on('test', function (req) {
controller.test(socket, req, 'test');
})
This way I store all users socket connections in server...
var userSockets = []; //Used to store all connected users data.
userSockets[user.id] = socket; // Storing whole socket object.
// E.x: userSockets[14] = socket; // Stored like this.
Function to get all socket data
getUserSocket() {
return userSockets;
}
Now I need to emit to the specific socket, I have tried this but I got an error.
let allUserSocketListData = databaseHelper.getUserSocket();
allUserSocketListData[result.data[0].id].emit('response' , data);
// E.x: allUserSocketListData[14].emit('response' , data);
Error:
.emit() is not a function.
Update
I have one function in that I'm storing all user's socket data.
validateUser(user, socket) {
... // My some code
userSockets[user.id] = socket;
}
Namespaces and rooms were build for that specific reason, but when you need something handy without extra code, sending emits directly can do job.
Here's a quick approach:
1: Your connection event should store the socket ID and not the whole object
let socketIds = []
socketServer.on("connection",(socket)=>{
socketIds.push(socket.id)
socket.emit("message", "hey")
})
2: Now if you want to send something on the first client only for example, you should first check if it's already registered and proceed with the emit.
if (socketServer.sockets.connected.hasOwnProperty(socketIds[0])){
socketServer.sockets.connected[socketIds[0]].emit("message", "hey again")
} else {
console.error("Error: Wrong Id")
}

How to listen to the event(commit event) in Hyperledger Fabric?

We set up a fabric server, and put some transaction into it. And we have some applications those will cooperate with the fabric server. Here is a situation.
Application send a transaction with fabric-sdk-java or fabric-sdk-node
The fabric excute the chaincode
The fabric notify the application about the result / The application listen to the event of the transaction (commit transaction, generate blockchain, append the blockchain, update the world state, etc.)
Application notify the custom about the transaction result.
As you know, the excution of the chaincode would cost some time. Especially, the blockchain would be commit after tens of seconds. So I want the peer callback a url or just let the application know the result of the execution. Is is possible?
You can register to even hub and listed for notifications of block/transaction being committed. If you are looking for example please consider to take a look at fabcar from fabric-samples. In particular you might want to take a look on invoke.js.
var options = {
wallet_path: path.join(__dirname, './creds'),
user_id: 'PeerAdmin',
channel_id: 'mychannel',
chaincode_id: 'fabcar',
peer_url: 'grpc://localhost:7051',
event_url: 'grpc://localhost:7053',
orderer_url: 'grpc://localhost:7050'
};
let eh = client.newEventHub();
eh.setPeerAddr(options.event_url);
eh.connect();
let txPromise = new Promise((resolve, reject) => {
let handle = setTimeout(() => {
eh.disconnect();
reject();
}, 30000);
eh.registerTxEvent(transactionID, (tx, code) => {
clearTimeout(handle);
eh.unregisterTxEvent(transactionID);
eh.disconnect();
if (code !== 'VALID') {
console.error(
'The transaction was invalid, code = ' + code);
reject();
} else {
console.log(
'The transaction has been committed on peer ' +
eh._ep._endpoint.addr);
resolve();
}
});
});
eventPromises.push(txPromise);
Similar API exists also in Java and Golang SDKs.
Hyperledger Composer has changed how we work with the Hyperledger Fabric Blockchain. Although I cannot give you all the introductions here I provide you a snippet of code on how (credits to):
To define an event
Emit an event from your transaction
Listen to events from your application
1) Defining an event: here I have an event that consists a doctor, a patient, and a message.
event MedicalEvent {
--> Doctor thedoctor
--> Patient thePatient
o String theMessage
}
transaction sampleTransaction {
--> Doctor thedoctor
--> Patient thePatient
}
2) Emitting an event from a transaction: here we will have the logic of the Chain code.
/**
*#ALL NECCESSARY DECORATIONS GO HERE
/
sampleTransaction(obj) {
var factory = getFactory();
var patient = obj.thepatient;
var doctor = obj.thedoctor;
var message = 'Take your medications PROPERLY';
return getParticipantRegistry('org.acme.WHATEVER.Patient')
.then(function(patientRegistry) {
var basicEvent = factory.newEvent('org.acme.WHATEVER', 'addMeLiveEvent');
basicEvent.theDoctor=doctor;
basicEvent.thePatient=patient;
basicEvent.theMessage = message;
emit(basicEvent);
})
}
3) Listen to events: here I have my Nodejs listening to events.
const BusinessNetworkConnection = require('composer-client').BusinessNetworkConnection;
this.bizNetworkConnection = new BusinessNetworkConnection();
this.cardName ='admin#YOUR-NETWORK';
this.businessNetworkIdentifier = 'YOUR-NETWORK';
this.bizNetworkConnection.connect(this.cardName)
.then((result) => {
//You can do ANYTHING
})
.catch((error) => {
throw error;
});
this.bizNetworkConnection.on('event',(evt)=>{
console.log('Amount Transfered: '+evt.theMessage);
});

kurento-utils, multiple WebRtcPeer's in one client

I have an application where I'm sharing both my desktop and my webcam to my Kurento Server (two different endpoints in the same pipeline), starting a recording endpoint for both and then alerting the client on the other hand that they're both ready to consume.
My issue comes with having two WebRtcPeerRecvonly peers on my client, if one doesn't finish before the other one makes a request to consume I either get videos of the same Desktop endpoint or two videos of the same Webcam endpoint.
webcam peer
initWebcamUser(id){
let options = {
onicecandidate: (candidate) => {
socket.emit('onWebcamIceCandidate',{
candidate : candidate,
socket_id : id,
});
}
};
webRtcWebcamPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, function(error) {
this.generateOffer((error, offerSdp) => {
socket.emit('viewerWebcam',{
sdpOffer : offerSdp,
socket_id : id
});
});
});
}
and my desktop peer.
initDesktop(socket_id){
let options = {
onicecandidate: (candidate) => {
socket.emit('onDesktopIceCandidate',{
candidate : candidate,
socket_id : socket_id,
});
}
}
webRtcDesktopPeer = new kurentoUtils.WebRtcPeer.WebRtcPeerRecvonly(options, function(error) {
this.generateOffer((error, offerSdp) => {
socket.emit('viewerDesktop',{
sdpOffer : offerSdp,
socket_id : socket_id
});
});
});
}
I've come to the conclusion that they're both sharing the same kurentoUtils.WebRtcPeer as if I set a delay of 2 seconds before invoking initDesktop after calling initWebcamUser I get the correct streams 100% of the time.
I guess this boils down to the question of is there anyway to do this concurrently? Or should I set up a promise based system on when the WebcamPeer is complete, if so where would I put this in this process, when iceCandidates are added?
Edit: I feel it's important to note that I am assigning these peers to their respective 'participants' in my webcamViewerResponse / desktopViewerResponse respectively so they wouldn't be referenced from those temp webRtcWebcamPeer/webRtcDesktopPeer variables when I'm having this issue.
Thanks in advance.
If anyone is looking for an answer for this, I found a solution. Not the most elegant but it works 100% of the time.
endpoint.on('OnIceComponentStateChanged', function(event) {
if(event.state==='CONNECTED'){
//resolve your promise to continue on with your next connection here.
}
});

Use redis to build a real time chat with socket.io and NodeJs

I want to built a real time chat system for my project but actually I have some problems with Redis because I want my data stored as better as possible.
My problem:
I'd like to use Socket Io to do real time chatting in a closed group (of two people), but how to store messages?
Redis is a key value store and that means that if i want to store something i need to add an unique key to my data before getting stored.
If the same user posts more than one messages which keys would I use inside redis? I'm thinking about unique ids as unique keys but since I want to be able to fetch this comments when a user log the chat page, but if I do that I need to write another database that relate chat ids to the user that posted that message
Am I forgetting anything? Is there a best method to do this?
Sorry for my bad English.
Redis is more then key-value store.
So you want the following:
chat messages,
two-person discussions,
you did not mention time constraints, so lets assume that you archive messages after a while,
you also don't say if you want separate "threads" between two people, like forums or continuous messages, like facebook. I'm assuming continuous.
For each user, you have to store messages he sends. Let's say APP_NAMESPACE:MESSAGES:<USER_ID>:<MESSAGE_ID>. We add userId here so that we can easily retreive all messages sent by a single user.
And, for each two users, you need to track their conversations. As a key, you can simply use their userids APP_NAMESPACE:CONVERSATIONS:<USER1_ID>-<USER2_ID>. To make sure you always get the same, shared conversation for the two users, you can sort their ids alfabetically, so that users 132 and 145 will both have 132:145 as conversation key
So what to store in "conversations"? Let's use a list: [messageKey, messageKey, messageKey].
Ok, but what is now the messageKey? Combo of userId above and a messageId (so we can get the actual message).
So basically, you need two things:
Store the message and give it an ID
Store a reference to this message to the relevant conversation.
With node and standard redis/hiredis client this would be somehting like (I'll skip the obvious error etc checks, and I'll write ES6. If you cannot read ES6 yet, just paste it to babel):
// assuming the init connects to redis and exports a redisClient
import redisClient from './redis-init';
import uuid from `node-uuid`;
export function storeMessage(userId, toUserId, message) {
return new Promise(function(resolve, reject) {
// give it an id.
let messageId = uuid.v4(); // gets us a random uid.
let messageKey = `${userId}:${messageId}`;
let key = `MY_APP:MESSAGES:${messageKey}`;
client.hmset(key, [
"message", message,
"timestamp", new Date(),
"toUserId", toUserId
], function(err) {
if (err) { return reject(err); }
// Now we stored the message. But we also want to store a reference to the messageKey
let convoKey = `MY_APP:CONVERSATIONS:${userId}-${toUserId}`;
client.lpush(convoKey, messageKey, function(err) {
if (err) { return reject(err); }
return resolve();
});
});
});
}
// We also need to retreive the messages for the users.
export function getConversation(userId, otherUserId, page = 1, limit = 10) {
return new Promise(function(resolve, reject) {
let [userId1, userId2] = [userId, otherUserId].sort();
let convoKey = `MY_APP:CONVERSATIONS:${userId1}-${userId2}`;
// lets sort out paging stuff.
let start = (page - 1) * limit; // we're zero-based here.
let stop = page * limit - 1;
client.lrange(convoKey, start, stop, function(err, messageKeys) {
if (err) { return reject(err); }
// we have message keys, now get all messages.
let keys = messageKeys.map(key => `MY_APP:MESSAGES:${key}`);
let promises = keys.map(key => getMessage(key));
Promise.all(promises)
.then(function(messages) {
// now we have them. We can sort them too
return resolve(messages.sort((m1, m2) => m1.timestamp - m2.timestamp));
})
.catch(reject);
});
});
}
// we also need the getMessage here as a promise. We could also have used some Promisify implementation but hey.
export function getMessage(key) {
return new Promise(function(resolve, reject) {
client.hgetall(key, function(err, message) {
if (err) { return reject(err); }
resolve(message);
});
});
}
Now that's crude and untested, but that's the gist of how you can do this.
Is redis is a constraint in your project?
you can go through this http://autobahn.ws/python/wamp/programming.html

Resources