Repository: seanseany/blockchain
Branch: master
Commit: e03e2bbea668
Files: 11
Total size: 14.1 KB
Directory structure:
gitextract_mjm9mmw7/
├── .gitignore
├── Block.js
├── Blockchain.js
├── LICENSE.ISC.txt
├── Messages.js
├── P2p.js
├── README.md
├── cli.js
├── index.js
├── message-type.js
└── package.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
node_modules
.DS_Store
================================================
FILE: Block.js
================================================
class Block {
constructor (index, previousHash, timestamp, data, hash, nonce) {
this.index = index;
this.previousHash = previousHash;
this.timestamp = timestamp;
this.data = data;
this.hash = hash;
this.nonce = nonce;
}
static get genesis() {
return new Block(
0,
"0",
1508270000000,
"Welcome to Blockchain Demo 2.0!",
"000dc75a315c77a1f9c98fb6247d03dd18ac52632d7dc6a9920261d8109b37cf",
604
);
}
}
module.exports = Block;
================================================
FILE: Blockchain.js
================================================
const Block = require("./Block.js");
const crypto = require("crypto");
class Blockchain {
constructor() {
this.blockchain = [Block.genesis];
this.difficulty = 3;
}
get() {
return this.blockchain;
}
get latestBlock() {
return this.blockchain[this.blockchain.length - 1];
}
isValidHashDifficulty(hash) {
for (var i = 0; i < hash.length; i++) {
if (hash[i] !== "0") {
break;
}
}
return i >= this.difficulty;
}
calculateHashForBlock(block) {
const { index, previousHash, timestamp, data, nonce } = block;
return this.calculateHash(
index,
previousHash,
timestamp,
data,
nonce
);
}
calculateHash(index, previousHash, timestamp, data, nonce) {
return crypto
.createHash("sha256")
.update(index + previousHash + timestamp + data + nonce)
.digest("hex");
}
mine(data) {
const newBlock = this.generateNextBlock(data);
try {
this.addBlock(newBlock);
} catch(err) {
throw err;
}
}
generateNextBlock(data) {
const nextIndex = this.latestBlock.index + 1;
const previousHash = this.latestBlock.hash;
let timestamp = new Date().getTime();
let nonce = 0;
let nextHash = this.calculateHash(
nextIndex,
previousHash,
timestamp,
data,
nonce
);
while (!this.isValidHashDifficulty(nextHash)) {
nonce = nonce + 1;
timestamp = new Date().getTime();
nextHash = this.calculateHash(
nextIndex,
previousHash,
timestamp,
data,
nonce
);
}
const nextBlock = new Block(
nextIndex,
previousHash,
timestamp,
data,
nextHash,
nonce
);
return nextBlock;
}
addBlock(newBlock) {
if (this.isValidNextBlock(newBlock, this.latestBlock)) {
this.blockchain.push(newBlock);
} else {
throw "Error: Invalid block";
}
}
isValidNextBlock(nextBlock, previousBlock) {
const nextBlockHash = this.calculateHashForBlock(nextBlock);
if (previousBlock.index + 1 !== nextBlock.index) {
return false;
} else if (previousBlock.hash !== nextBlock.previousHash) {
return false;
} else if (nextBlockHash !== nextBlock.hash) {
return false;
} else if (!this.isValidHashDifficulty(nextBlockHash)) {
return false;
} else {
return true;
}
}
isValidChain(chain) {
if (JSON.stringify(chain[0]) !== JSON.stringify(Block.genesis)) {
return false;
}
const tempChain = [chain[0]];
for (let i = 1; i < chain.length; i = i + 1) {
if (this.isValidNextBlock(chain[i], tempChain[i - 1])) {
tempChain.push(chain[i]);
} else {
return false;
}
}
return true;
}
isChainLonger(chain) {
return chain.length > this.blockchain.length;
}
replaceChain(newChain) {
if (this.isValidChain(newChain) && this.isChainLonger(newChain)) {
this.blockchain = JSON.parse(JSON.stringify(newChain));
} else {
throw "Error: invalid chain";
}
}
}
module.exports = Blockchain;
================================================
FILE: LICENSE.ISC.txt
================================================
ISC License
Copyright (c) 2017, Sean Han
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
================================================
FILE: Messages.js
================================================
const messageType = require("./message-type.js");
const {
REQUEST_LATEST_BLOCK,
RECEIVE_LATEST_BLOCK,
REQUEST_BLOCKCHAIN,
RECEIVE_BLOCKCHAIN,
REQUEST_TRANSACTIONS,
RECEIVE_TRANSACTIONS
} = messageType;
class Messages {
static getLatestBlock() {
return {
type: REQUEST_LATEST_BLOCK
};
}
static sendLatestBlock(block) {
return {
type: RECEIVE_LATEST_BLOCK,
data: block
};
}
static getBlockchain() {
return {
type: REQUEST_BLOCKCHAIN
};
}
static sendBlockchain(blockchain) {
return {
type: RECEIVE_BLOCKCHAIN,
data: blockchain
};
}
}
module.exports = Messages;
================================================
FILE: P2p.js
================================================
const wrtc = require("wrtc");
const Exchange = require("peer-exchange");
const p2p = new Exchange("Blockchain Demo 2.0", { wrtc: wrtc });
const net = require("net");
const messageType = require("./message-type.js");
const {
REQUEST_LATEST_BLOCK,
RECEIVE_LATEST_BLOCK,
REQUEST_BLOCKCHAIN,
RECEIVE_BLOCKCHAIN,
REQUEST_TRANSACTIONS,
RECEIVE_TRANSACTIONS
} = messageType;
const Messages = require("./Messages.js");
class PeerToPeer {
constructor(blockchain) {
this.peers = [];
this.blockchain = blockchain;
}
startServer(port) {
const server = net
.createServer(socket =>
p2p.accept(socket, (err, conn) => {
if (err) {
throw err;
} else {
this.initConnection.call(this, conn);
}
})
)
.listen(port);
}
discoverPeers() {
p2p.getNewPeer((err, conn) => {
if (err) {
throw err;
} else {
this.initConnection.call(this, conn);
}
});
}
connectToPeer(host, port) {
const socket = net.connect(port, host, () =>
p2p.connect(socket, (err, conn) => {
if (err) {
throw err;
} else {
this.initConnection.call(this, conn);
}
})
);
}
closeConnection() {
p2p.close(err => {
throw err;
});
}
broadcastLatest() {
this.broadcast(Messages.sendLatestBlock(this.blockchain.latestBlock));
}
broadcast(message) {
this.peers.forEach(peer => this.write(peer, message));
}
write(peer, message) {
peer.write(JSON.stringify(message));
}
initConnection(connection) {
this.peers.push(connection);
this.initMessageHandler(connection);
this.initErrorHandler(connection);
this.write(connection, Messages.getLatestBlock());
}
initMessageHandler(connection) {
connection.on("data", data => {
const message = JSON.parse(data.toString("utf8"));
this.handleMessage(connection, message);
});
}
initErrorHandler(connection) {
connection.on("error", err => {
throw err;
});
}
handleMessage(peer, message) {
switch (message.type) {
case REQUEST_LATEST_BLOCK:
this.write(peer, Messages.sendLatestBlock(this.blockchain.latestBlock));
break;
case REQUEST_BLOCKCHAIN:
this.write(peer, Messages.sendBlockchain(this.blockchain.get()));
break;
case RECEIVE_LATEST_BLOCK:
this.handleReceivedLatestBlock(message, peer);
break;
case RECEIVE_BLOCKCHAIN:
this.handleReceivedBlockchain(message);
break;
default:
throw "Received invalid message.";
}
}
handleReceivedLatestBlock(message, peer) {
const receivedBlock = message.data;
const latestBlock = this.blockchain.latestBlock;
if (latestBlock.hash === receivedBlock.previousHash) {
try {
this.blockchain.addBlock(receivedBlock);
} catch(err) {
throw err;
}
} else if (receivedBlock.index > latestBlock.index) {
this.write(peer, Messages.getBlockchain());
} else {
// Do nothing.
}
}
handleReceivedBlockchain(message) {
const receivedChain = message.data;
try {
this.blockchain.replaceChain(receivedChain);
} catch(err) {
throw err;
}
}
}
module.exports = PeerToPeer;
================================================
FILE: README.md
================================================
<h1 align="center">
<br>
<a href="https://blockchaindemo.io" rel="noopener noreferrer" target="_blank"><img src="https://raw.githubusercontent.com/seanseany/blockchain/master/logo.png" width="200"></a>
<br>
<a href="https://blockchaindemo.io" rel="noopener noreferrer" target="_blank">Blockchaindemo.io</a>
<br>
</h1>
<h4 align="center">Code for learning the blockchain data structure</h4>
<br>
## 📦 Installation
To install this application, you'll need
[Node.js](https://nodejs.org/en/download/) 7+ (which comes with
[npm](http://npmjs.com)) installed on your computer. From your command line:
#### Source
You'll need [Git](https://git-scm.com) to run the project from source. From your
command line:
```bash
# Clone this repository
$ git clone https://github.com/seanseany/blockchain
# Go into the repository
$ cd blockchain
# Install dependencies
$ npm install
# Run the app
$ npm start
```
## ℹ️ FAQ
#### When or why I would use this?
You should use this if you want to build a bitcoin wallet, payment processor, or
bitcoin merchant portal in javascript. You might also be interested in why
decentralized networks or p2p applications are useful, or what advantages they
have; this project seems like a good way to learn about that.
#### What is the block chain actually for?
The blockchain is for authorizing payments of a cryptocurrency between two peers
without the need for a centralized 3rd party approving of the transaction. There
are other uses of the blockchain which are more in line with the second point,
digital signatures, but they are secondary to the main purpose of peer to peer
transfer of value. Bitcoin is blockchain's killer app.
#### Why the hell should I care about the blockchain?
Blockchain facilitates trade over a network. Imagine a metal as scarce as gold
with a magical property of "can be transported over a communications channel".
This has implications with respect to individual rights, the world economy, and
the way we monetize and transfer value at a level higher than bartering directly
for goods.
Lately people are distancing themselves from the proof-of-work concept and are
using blockchain to describe only the mechanism of signing a transaction as
verification of sending an amount. Change "sending an amount" to almost anything
else - authorizing a change in a ruleset, casting a vote for a politician,
verifying a point of IoT data is authentic. Now add in the concept of a
peer-to-peer network to this and you've eliminated a middleman that once
existed, thereby improving the efficiency and reducing cost. In these cases,
"blockchain" refers to the structuring of a program or database in such a way
that it has no central point of failure while still providing all of the
features expected. For example, augur and gnosis are decentralized prediction
markets. Ethereum has implemented smart contracts which enable decentralized
release of funds based on a gambling outcome.
================================================
FILE: cli.js
================================================
const P2p = require("./P2p.js");
const Blockchain = require("./Blockchain.js");
const blockchain = new Blockchain();
const p2p = new P2p(blockchain);
function cli(vorpal) {
vorpal
.use(welcome)
.use(connectCommand)
.use(discoverCommand)
.use(blockchainCommand)
.use(peersCommand)
.use(mineCommand)
.use(openCommand)
.delimiter('blockchain →')
.show()
}
module.exports = cli;
// COMMANDS
function welcome(vorpal) {
vorpal.log("Welcome to Blockchain CLI!");
vorpal.exec("help");
}
function connectCommand(vorpal) {
vorpal
.command('connect <host> <port>', "Connect to a new peer. Eg: connect localhost 2727")
.alias('c')
.action(function(args, callback) {
if(args.host && args.port) {
try {
p2p.connectToPeer(args.host, args.port);
} catch(err) {
this.log(err);
}
}
callback();
})
}
function discoverCommand(vorpal) {
vorpal
.command('discover', 'Discover new peers from your connected peers.')
.alias('d')
.action(function(args, callback) {
try {
p2p.discoverPeers();
} catch(err) {
this.log(err);
}
callback();
})
}
function blockchainCommand(vorpal) {
vorpal
.command('blockchain', 'See the current state of the blockchain.')
.alias('bc')
.action(function(args, callback) {
this.log(blockchain)
callback();
})
}
function peersCommand(vorpal) {
vorpal
.command('peers', 'Get the list of connected peers.')
.alias('p')
.action(function(args, callback) {
p2p.peers.forEach(peer => {
this.log(`${peer.pxpPeer.socket._host} \n`)
}, this)
callback();
})
}
function mineCommand(vorpal) {
vorpal
.command('mine <data>', 'Mine a new block. Eg: mine hello!')
.alias('m')
.action(function(args, callback) {
if (args.data) {
blockchain.mine(args.data);
p2p.broadcastLatest();
}
callback();
})
}
function openCommand(vorpal) {
vorpal
.command('open <port>', 'Open port to accept incoming connections. Eg: open 2727')
.alias('o')
.action(function(args, callback) {
if (args.port) {
if(typeof args.port === 'number') {
p2p.startServer(args.port);
this.log(`Listening to peers on ${args.port}`);
} else {
this.log(`Invalid port!`);
}
}
callback();
})
}
================================================
FILE: index.js
================================================
#!/usr/bin/env node
const vorpal = require('vorpal')();
vorpal.use(require('./cli.js'));
================================================
FILE: message-type.js
================================================
const messageType = {
REQUEST_LATEST_BLOCK: 0,
RECEIVE_LATEST_BLOCK: 1,
REQUEST_BLOCKCHAIN: 2,
RECEIVE_BLOCKCHAIN: 3,
};
module.exports = messageType;
================================================
FILE: package.json
================================================
{
"name": "blockchain-cli",
"version": "2.0.0",
"description": "Blockchain command-line interface",
"main": "index.js",
"engines": {
"node": "7.0.0",
"npm": "3.10.8"
},
"scripts": {
"start": "node ./index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"peer-exchange": "^2.2.0",
"vorpal": "^1.12.0",
"wrtc": "0.0.63"
}
}
gitextract_mjm9mmw7/ ├── .gitignore ├── Block.js ├── Blockchain.js ├── LICENSE.ISC.txt ├── Messages.js ├── P2p.js ├── README.md ├── cli.js ├── index.js ├── message-type.js └── package.json
SYMBOL INDEX (45 symbols across 5 files)
FILE: Block.js
class Block (line 1) | class Block {
method constructor (line 2) | constructor (index, previousHash, timestamp, data, hash, nonce) {
method genesis (line 11) | static get genesis() {
FILE: Blockchain.js
class Blockchain (line 4) | class Blockchain {
method constructor (line 5) | constructor() {
method get (line 10) | get() {
method latestBlock (line 14) | get latestBlock() {
method isValidHashDifficulty (line 18) | isValidHashDifficulty(hash) {
method calculateHashForBlock (line 27) | calculateHashForBlock(block) {
method calculateHash (line 38) | calculateHash(index, previousHash, timestamp, data, nonce) {
method mine (line 45) | mine(data) {
method generateNextBlock (line 54) | generateNextBlock(data) {
method addBlock (line 91) | addBlock(newBlock) {
method isValidNextBlock (line 99) | isValidNextBlock(nextBlock, previousBlock) {
method isValidChain (line 115) | isValidChain(chain) {
method isChainLonger (line 131) | isChainLonger(chain) {
method replaceChain (line 135) | replaceChain(newChain) {
FILE: Messages.js
class Messages (line 11) | class Messages {
method getLatestBlock (line 12) | static getLatestBlock() {
method sendLatestBlock (line 18) | static sendLatestBlock(block) {
method getBlockchain (line 25) | static getBlockchain() {
method sendBlockchain (line 31) | static sendBlockchain(blockchain) {
FILE: P2p.js
class PeerToPeer (line 16) | class PeerToPeer {
method constructor (line 17) | constructor(blockchain) {
method startServer (line 22) | startServer(port) {
method discoverPeers (line 36) | discoverPeers() {
method connectToPeer (line 46) | connectToPeer(host, port) {
method closeConnection (line 58) | closeConnection() {
method broadcastLatest (line 64) | broadcastLatest() {
method broadcast (line 68) | broadcast(message) {
method write (line 72) | write(peer, message) {
method initConnection (line 76) | initConnection(connection) {
method initMessageHandler (line 83) | initMessageHandler(connection) {
method initErrorHandler (line 90) | initErrorHandler(connection) {
method handleMessage (line 96) | handleMessage(peer, message) {
method handleReceivedLatestBlock (line 115) | handleReceivedLatestBlock(message, peer) {
method handleReceivedBlockchain (line 132) | handleReceivedBlockchain(message) {
FILE: cli.js
function cli (line 7) | function cli(vorpal) {
function welcome (line 23) | function welcome(vorpal) {
function connectCommand (line 28) | function connectCommand(vorpal) {
function discoverCommand (line 44) | function discoverCommand(vorpal) {
function blockchainCommand (line 58) | function blockchainCommand(vorpal) {
function peersCommand (line 68) | function peersCommand(vorpal) {
function mineCommand (line 80) | function mineCommand(vorpal) {
function openCommand (line 93) | function openCommand(vorpal) {
Condensed preview — 11 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (16K chars).
[
{
"path": ".gitignore",
"chars": 22,
"preview": "node_modules\n.DS_Store"
},
{
"path": "Block.js",
"chars": 499,
"preview": "class Block {\n constructor (index, previousHash, timestamp, data, hash, nonce) {\n this.index = index;\n this.previ"
},
{
"path": "Blockchain.js",
"chars": 3134,
"preview": "const Block = require(\"./Block.js\");\nconst crypto = require(\"crypto\");\n\nclass Blockchain {\n constructor() {\n this.bl"
},
{
"path": "LICENSE.ISC.txt",
"chars": 740,
"preview": "ISC License\n\nCopyright (c) 2017, Sean Han\n\nPermission to use, copy, modify, and/or distribute this software for any\npurp"
},
{
"path": "Messages.js",
"chars": 658,
"preview": "const messageType = require(\"./message-type.js\");\nconst {\n REQUEST_LATEST_BLOCK,\n RECEIVE_LATEST_BLOCK,\n REQUEST_BLOC"
},
{
"path": "P2p.js",
"chars": 3336,
"preview": "const wrtc = require(\"wrtc\");\nconst Exchange = require(\"peer-exchange\");\nconst p2p = new Exchange(\"Blockchain Demo 2.0\","
},
{
"path": "README.md",
"chars": 2953,
"preview": "<h1 align=\"center\">\n <br>\n <a href=\"https://blockchaindemo.io\" rel=\"noopener noreferrer\" target=\"_blank\"><img src=\"htt"
},
{
"path": "cli.js",
"chars": 2382,
"preview": "\nconst P2p = require(\"./P2p.js\");\nconst Blockchain = require(\"./Blockchain.js\");\nconst blockchain = new Blockchain();\nco"
},
{
"path": "index.js",
"chars": 88,
"preview": "#!/usr/bin/env node\nconst vorpal = require('vorpal')();\nvorpal.use(require('./cli.js'));"
},
{
"path": "message-type.js",
"chars": 159,
"preview": "const messageType = {\n REQUEST_LATEST_BLOCK: 0,\n RECEIVE_LATEST_BLOCK: 1,\n REQUEST_BLOCKCHAIN: 2,\n RECEIVE_BLOCKCHAI"
},
{
"path": "package.json",
"chars": 438,
"preview": "{\n \"name\": \"blockchain-cli\",\n \"version\": \"2.0.0\",\n \"description\": \"Blockchain command-line interface\",\n \"main\": \"ind"
}
]
About this extraction
This page contains the full source code of the seanseany/blockchain GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 11 files (14.1 KB), approximately 3.8k tokens, and a symbol index with 45 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.