Skip to content

Commit

Permalink
Merge pull request #37 from UVNishanth/master
Browse files Browse the repository at this point in the history
fetched from upstream and resolved conflicts
  • Loading branch information
taustin authored Oct 4, 2023
2 parents bbcd8f6 + b50c1d6 commit 68c5f8c
Show file tree
Hide file tree
Showing 8 changed files with 1,553 additions and 842 deletions.
24 changes: 24 additions & 0 deletions blockchain.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,15 @@ module.exports = class Blockchain {
return this.instance;
}

/**
* Check if Blockchain instance exists
*
* @returns {Blockchain}
*/
static hasInstance() {
return (this.instance ? true : false);
}

/**
* Creates the new instance of the blockchain configuration, giving the
* clients the amount of starting gold specified in the clients array.
Expand All @@ -160,6 +169,7 @@ module.exports = class Blockchain {
* @param {Class} cfg.blockClass - Implementation of the Block class.
* @param {Class} cfg.transactionClass - Implementation of the Transaction class.
* @param {Array} [cfg.clients] - An array of client/miner configurations.
* @param {String} [cfg.mnemonic] - BIP39 mnemonic which is used to generate client addresses.
* @param {number} [cfg.powLeadingZeroes] - Number of leading zeroes required for a valid proof-of-work.
* @param {number} [cfg.coinbaseAmount] - Amount of gold awarded to a miner for creating a block.
* @param {number} [cfg.defaultTxFee] - Amount of gold awarded to a miner for accepting a transaction,
Expand Down Expand Up @@ -192,6 +202,7 @@ module.exports = class Blockchain {
defaultTxFee = DEFAULT_TX_FEE,
confirmedDepth = CONFIRMED_DEPTH,
clients = [],
mnemonic,
net,
}) {

Expand Down Expand Up @@ -236,22 +247,35 @@ module.exports = class Blockchain {

this.initialBalances = new Map();

// generate random mnemonic if mnemonic not passed
if (mnemonic === undefined){
const { generateMnemonic } = require('bip39');
this.mnemonic = generateMnemonic(256);
}
else{
this.mnemonic = mnemonic;
}

clients.forEach((clientCfg) => {
console.log(`Adding client ${clientCfg.name}`);
let client;
if (clientCfg.mining) {
client = new this.minerClass({
name: clientCfg.name,
password: clientCfg.password ? clientCfg.password : clientCfg.name+'_pswd',
net: this.net,
miningRounds: clientCfg.miningRounds,
});
client.generateAddress(this.mnemonic);
// Miners are stored as both miners and clients.
this.miners.push(client);
} else {
client = new this.clientClass({
name: clientCfg.name,
password: clientCfg.password ? clientCfg.password : clientCfg.name+'_pswd',
net: this.net,
});
client.generateAddress(this.mnemonic);
}

this.clientAddressMap.set(client.address, client);
Expand Down
30 changes: 23 additions & 7 deletions client.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,25 @@ module.exports = class Client extends EventEmitter {
* @constructor
* @param {Object} obj - The properties of the client.
* @param {String} [obj.name] - The client's name, used for debugging messages.
* @param {String} [obj.password] - The client's password, used for generating address.
* @param {Object} obj.net - The network used by the client
* to send messages to all miners and clients.
* @param {Block} [obj.startingBlock] - The starting point of the blockchain for the client.
* @param {Object} [obj.keyPair] - The public private keypair for the client.
*/
constructor({name, net, startingBlock, keyPair} = {}) {
constructor({name, password, net, startingBlock} = {}) {
super();

this.net = net;
this.name = name;

if (keyPair === undefined) {
this.keyPair = utils.generateKeypair();
} else {
this.keyPair = keyPair;
}
this.password = password ? password : this.name+"_pswd";

this.address = utils.calcAddress(this.keyPair.public);

if (Blockchain.hasInstance()){
let bc = Blockchain.getInstance();
this.generateAddress(bc.mnemonic);
}

// Establishes order of transactions. Incremented with each
// new output transaction from this client. This feature
Expand Down Expand Up @@ -355,4 +356,19 @@ module.exports = class Client extends EventEmitter {
block = this.blocks.get(block.prevBlockHash);
}
}

/**
* Generate client address using mnemonic set for the blockchain
*
* @param {String} mnemonic - mnemonic set for the blockchain instance
*/
generateAddress(mnemonic){
if (mnemonic === undefined){
throw new Error(`mnemonic not set`);
}
this.keyPair = utils.generateKeypairFromMnemonic(mnemonic, this.password);
this.address = utils.calcAddress(this.keyPair.public);
console.log(`${this.name}'s address is: ${this.address}`);
}

};
6 changes: 3 additions & 3 deletions driver.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ let bc = Blockchain.createInstance({
{name: 'Minnie', amount: 400, mining: true},
{name: 'Mickey', amount: 300, mining: true},
],
mnemonic: "antenna dwarf settle sleep must wool ocean once banana tiger distance gate great similar chief cheap dinner dolphin picture swing twenty two file nuclear",
net: new FakeNet(),
});

Expand All @@ -28,9 +29,9 @@ let [alice, bob] = bc.getClients('Alice', 'Bob');
console.log("Initial balances:");
alice.showAllBalances();

// The miners will start mining blocks when start is called. After 5 seconds,
// The miners will start mining blocks when start is called. After 8 seconds,
// the code will terminate and show the final balances from Alice's perspective.
bc.start(5000, () => {
bc.start(8000, () => {
console.log("Final balances, from Alice's perspective:");
alice.showAllBalances();
});
Expand All @@ -55,4 +56,3 @@ setTimeout(() => {
donald.initialize();
}, 2000);


7 changes: 4 additions & 3 deletions miner.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ module.exports = class Miner extends Client {
* @constructor
* @param {Object} obj - The properties of the client.
* @param {String} [obj.name] - The miner's name, used for debugging messages.
* * @param {Object} net - The network that the miner will use
* @param {Object} net - The network that the miner will use
* to send messages to all other clients.
* @param {String} [obj.password] - The client's password, used for generating address.
* @param {Block} [startingBlock] - The most recently ALREADY ACCEPTED block.
* @param {Object} [obj.keyPair] - The public private keypair for the client.
* @param {Number} [miningRounds] - The number of rounds a miner mines before checking
* for messages. (In single-threaded mode with FakeNet, this parameter can
* simulate miners with more or less mining power.)
*/
constructor({name, net, startingBlock, keyPair, miningRounds=Blockchain.NUM_ROUNDS_MINING} = {}) {
super({name, net, startingBlock, keyPair});
constructor({name, password, net, startingBlock, keyPair, miningRounds=Blockchain.NUM_ROUNDS_MINING} = {}) {
super({name, password, net, startingBlock, keyPair});
this.miningRounds=miningRounds;

// Set of transactions to be added to the next block.
Expand Down
71 changes: 71 additions & 0 deletions mnemonic-driver.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"use strict";

let Blockchain = require('./blockchain.js');

// Used to create a client outside of the blockchain constructor.
let Client = require('./client.js');


// Used to create a miner outside of the blockchain constructor.
let Miner = require('./miner.js');

let FakeNet = require('./fake-net.js');

console.log("Starting simulation. This may take a moment...");

// Creating genesis block
let bc = Blockchain.createInstance({
clients: [
{name: 'Alice', amount: 233, password: 'alice_pswd'},
{name: 'Bob', amount: 99, password: 'bob_pswd'},
{name: 'Charlie', amount: 67, password: 'charlie_pswd'},
{name: 'Minnie', amount: 400, mining: true},
{name: 'Mickey', amount: 300, mining: true},
],
mnemonic: "antenna dwarf settle sleep must wool ocean once banana tiger distance gate great similar chief cheap dinner dolphin picture swing twenty two file nuclear",
net: new FakeNet(),
});

// Late client - to demonstrate that clients can be initialized after blockchain initialization
let trudy = new Client({name: 'Trudy', startingBlock: bc.genesis});
bc.register(trudy);

// Get Alice and Bob
let [alice, bob] = bc.getClients('Alice', 'Bob');

// Showing the initial balances from Alice's perspective, for no particular reason.
console.log("Initial balances:");
alice.showAllBalances();

// The miners will start mining blocks when start is called. After 8 seconds,
// the code will terminate and show the final balances from Alice's perspective.
bc.start(8000, () => {
console.log("Final balances, from Alice's perspective:");
alice.showAllBalances();
});

// Alice transfers some money to Bob.
console.log(`Alice is transferring 40 gold to ${bob.address}`);
alice.postTransaction([{ amount: 40, address: bob.address }]);

// Alice transfers some money to Bob.
console.log(`Alice is transferring 20 gold to ${trudy.address}`);
alice.postTransaction([{ amount: 20, address: trudy.address }]);


setTimeout(() => {
// Late miner - Donald has more mining power, represented by the miningRounds.
// (Mickey and Minnie have the default of 2000 rounds).
let donald = new Miner({
name: "Donald",
startingBlock: bc.genesis,
miningRounds: 3000,
});

console.log();
console.log("***Starting a late-to-the-party miner***");
console.log();
bc.register(donald);
donald.initialize();
}, 2000);

Loading

0 comments on commit 68c5f8c

Please sign in to comment.