I started delving into blockchain development and implemented one in Node.JS. I managed to write the data into a file and read it from there, but the hosting environment does not allow this, and so I would like to implement this using MongoDB. I did it to some extent, but the problem is that the data is somehow not written to the database after running the script and navigating to the hosted page. No error messages or success messages come back, everything looks normal on the console. If anyone could help, I would greatly appreciate it. I am attaching my code and console output.
My code:
class Block {
constructor(index, transactions, timestamp, previousHash, nonce = 0) {
this.index = index;
this.transactions = transactions;
this.timestamp = timestamp;
this.previousHash = previousHash;
this.nonce = nonce;
}
computeHash() {
const blockString = JSON.stringify(this, Object.keys(this).sort());
return crypto.createHash('sha256').update(blockString).digest('hex');
}
}
class Blockchain {
constructor() {
/*const chainData = await readChain();
if (chainData === '') {
this.chain = [this.createGenesisBlock()];
fs.writeFileSync('blockchain.json', JSON.stringify(this.chain));
await writeChain(JSON.stringify(this.chain));
} else {
this.chain = JSON.parse(chainData);
}
this.chain = [this.createGenesisBlock()];
this.difficulty = 2;*/
}
async initialize() {
const chainData = await this.readChain();
console.log("Chain data: ",chainData);
if (!chainData) {
this.chain = [this.createGenesisBlock()];
//fs.writeFileSync('blockchain.json', JSON.stringify(this.chain));
console.log(JSON.stringify(this.chain));
await this.writeChain(JSON.stringify(this.chain));
} else {
this.chain = JSON.parse(chainData);
}
this.chain = [this.createGenesisBlock()];
this.difficulty = 2;
}
static async create() {
const o = new Blockchain();
await o.initialize();
return o;
}
async readChain(){
client.connect(err => {
const collection = client.db(DB).collection(COLL);
collection.find({}).toArray((err, docs) => {
if (err) {
console.log(err);
client.close();
} else {
console.log('Found documents:', docs);
client.close();
return docs;
}
});
});
}
async writeChain(data){
const newValues = { $set:{ chain: data} };
client.connect(err => {
const collection = client.db(DB).collection(COLL);
collection.updateOne({ }, newValues, (err, result) => {
if (err) {
console.log(err);
client.close();
} else {
console.log('Document modified:', result.result);
client.close();
}
});
});
}
createGenesisBlock() {
return new Block(0, [{ fromAddress: 'root', toAddress: 'petertill', amount: 100}], Date.now(), '0');
}
getLatestBlock() {
return this.chain[this.chain.length - 1];
}
async addBlock(newBlock, proof) {
const previousHash = this.getLatestBlock().computeHash();
if (previousHash !== newBlock.previousHash) {
return false;
}
if (!this.isValidProof(newBlock, proof)) {
return false;
}
this.chain.push(newBlock);
//fs.writeFileSync('blockchain.json', JSON.stringify(this.chain));
await this.writeChain(JSON.stringify(this.chain));
return true;
}
isValidProof(block, blockHash) {
return blockHash.startsWith('0'.repeat(this.difficulty)) && blockHash === block.computeHash();
}
proofOfWork(block) {
block.nonce = 0;
let computedHash = block.computeHash();
while (!computedHash.startsWith('0'.repeat(this.difficulty))) {
block.nonce++;
computedHash = block.computeHash();
}
return computedHash;
}
async addTransaction(transaction) {
const { fromAddress, toAddress, amount } = transaction;
if (this.getBalance(fromAddress) < amount) {
return { status: false, message: 'Insufficient balance' };
}
/*ToDo: if the latest block's transactions are
less than something, add transactions to it. Otherwise,
create new block. I may not need very high number of
transactions each block*/
//Adding only two transactions may not be optimal in real blockchain
const newBlock = new Block(this.chain.length+1, [transaction], Date.now(), this.getLatestBlock().computeHash());
//console.log(newBlock);
this.addBlock(newBlock, this.proofOfWork(newBlock));
//this.getLatestBlock().transactions.push(transaction);
return { status: true, message: 'Transaction added successfully' };
}
async getBalance(address) {
let balance = 0;
for (const block of this.chain) {
for (const transaction of block.transactions) {
if (transaction.fromAddress === address) {
balance -= transaction.amount;
} else if (transaction.toAddress === address) {
balance += transaction.amount;
}
}
}
return balance;
}
async getBlockchain() {
//ToDo: Remove JSON.stringify() if I don't want to see transactions
return JSON.stringify(this.chain.map(block => ({ ...block, transactions: [...block.transactions] })) );
}
}
/*const myCoin = new Blockchain();
myCoin.addTransaction({ fromAddress: 'petertill', toAddress: 'John', amount: 10 });
const { status, message } = myCoin.addTransaction({ fromAddress: 'John', toAddress: 'Bob', amount: 10 });
if (status) {
console.log(message);
} else {
console.log(`Transaction failed. Message: ${message}`);
}
myCoin.addTransaction({ fromAddress: 'Bob', toAddress: 'petertill', amount: 5});
/* Bányászat*//*
const latestBlock = myCoin.getLatestBlock();
console.log(latestBlock.computeHash())
const newBlock = new Block(latestBlock.index + 1, latestBlock.transactions, Date.now(), latestBlock.computeHash());
const proof = myCoin.proofOfWork(newBlock);
myCoin.addBlock(newBlock, proof);*/
/*
console.log(`Peter's balance: ${myCoin.getBalance('Peter')}`);
console.log(`John's balance: ${myCoin.getBalance('John')}`);
console.log(`Bob's balance: ${myCoin.getBalance('Bob')}`);
console.log(myCoin.getBlockchain());
*/
app.get('/auth/github', passport.authenticate('github'));
app.get('/auth/github/callback', passport.authenticate('github', {
successRedirect: '/success',
failureRedirect: '/error'
}));
app.get('/success', async (req, res) => {
// Check if the user is authenticated
/*if (!req.user) {
return res.redirect('/error');
}*/
//const Coin = new Blockchain();
const Coin = await Blockchain.create();
const { status, message } = await Coin.addTransaction({ fromAddress: 'petertill', toAddress: 'John', amount: 10 });
if (status) {
console.log(message);
} else {
console.log(`Transaction failed. Message: ${message}`);
}
console.log(`Peter's balance: ${await Coin.getBalance('petertill')}`);
console.log(`John's balance: ${await Coin.getBalance('John')}`);
console.log(`Bob's balance: ${await Coin.getBalance('Bob')}`);
//res.render(__dirname + "/home.html", {name:req.user.username, balance:await Coin.getBalance(req.user.username), pfp:req.user.photos[0].value});
//res.sendFile(__dirname + "/index.html");
res.send(`balance: ${await Coin.getBalance('petertill')}`);
// Render the success page with the user's credentials
//res.send(`Welcome ${req.user.displayName}! Your Github username is ${req.user.username}.`);
});
Console output:
Hint: hit control+c anytime to enter REPL.
Example app listening on port 3000
Chain data: undefined
[{"index":0,"transactions":[{"fromAddress":"root","toAddress":"petertill","amount":100}],"timestamp":1681403116454,"previousHash":"0","nonce":0}]
Transaction added successfully
Peter's balance: 90
John's balance: 10
Bob's balance: 0
I’ve tried abbreviating the async functions and writing out the variables, but I can’t figure out what the problem might be.