From 840cc0929939ccdeb39b56efcbd0af82432a9021 Mon Sep 17 00:00:00 2001 From: yingweiwang Date: Thu, 26 Jul 2018 22:11:38 -0400 Subject: [PATCH 01/36] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b1664b6..c84eed5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -# Naivecoin +# Dewcoin -The repository for the naivecoin tutorial: https://lhartikk.github.io/ +naivecoin dew computing version. a proof of concept for blockchain applications that follow dew computing principles. http://www.dewcomputing.org/ + +(in progress) ``` npm install From d81bcbefd2058a04d827adeaeed24376a34a04ef Mon Sep 17 00:00:00 2001 From: ywang Date: Thu, 26 Jul 2018 22:42:02 -0400 Subject: [PATCH 02/36] basic introduction --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b1664b6..839b976 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,10 @@ -# Naivecoin +# Dewcoin -The repository for the naivecoin tutorial: https://lhartikk.github.io/ +naivecoin dew computing version. a proof of concept for blockchain applications that follow dew computing principles. http://www.dewcomputing.org/ +(in progress) + +Basic principles of naivecoin can be found in: A tutorial for building a cryptocurrency https://lhartikk.github.io/ ``` npm install npm start From 038b46d011159d37b2c8672a3175c354f236b483 Mon Sep 17 00:00:00 2001 From: ywang Date: Sat, 28 Jul 2018 16:03:33 -0400 Subject: [PATCH 03/36] File structure change, redefine transactions and accounts --- cloud/README.md | 55 + {node => cloud/node}/wallet/.gitignore | 0 package-lock.json => cloud/package-lock.json | 0 package.json => cloud/package.json | 0 cloud/src/blockchain.js | 261 +++++ cloud/src/blockchain.js.map | 1 + {src => cloud/src}/blockchain.ts | 0 cloud/src/main.js | 122 ++ cloud/src/main.js.map | 1 + cloud/src/main.ts | 141 +++ cloud/src/p2p.js | 175 +++ cloud/src/p2p.js.map | 1 + {src => cloud/src}/p2p.ts | 0 cloud/src/transaction.js | 298 +++++ cloud/src/transaction.js.map | 1 + {src => cloud/src}/transaction.ts | 0 cloud/src/transactionPool.js | 64 ++ cloud/src/transactionPool.js.map | 1 + {src => cloud/src}/transactionPool.ts | 0 cloud/src/util.js | 22 + cloud/src/util.js.map | 1 + {src => cloud/src}/util.ts | 0 cloud/src/wallet.js | 120 ++ cloud/src/wallet.js.map | 1 + {src => cloud/src}/wallet.ts | 0 tsconfig.json => cloud/tsconfig.json | 0 tslint.json => cloud/tslint.json | 0 dew/README.md | 55 + dew/node/wallet/.gitignore | 2 + dew/package-lock.json | 1077 ++++++++++++++++++ dew/package.json | 34 + dew/src/blockchain.js | 261 +++++ dew/src/blockchain.js.map | 1 + dew/src/blockchain.ts | 299 +++++ dew/src/main.js | 122 ++ dew/src/main.js.map | 1 + {src => dew/src}/main.ts | 0 dew/src/p2p.js | 175 +++ dew/src/p2p.js.map | 1 + dew/src/p2p.ts | 191 ++++ dew/src/transaction.js | 298 +++++ dew/src/transaction.js.map | 1 + dew/src/transaction.ts | 429 +++++++ dew/src/transactionPool.js | 64 ++ dew/src/transactionPool.js.map | 1 + dew/src/transactionPool.ts | 71 ++ dew/src/util.js | 22 + dew/src/util.js.map | 1 + dew/src/util.ts | 19 + dew/src/wallet.js | 120 ++ dew/src/wallet.js.map | 1 + dew/src/wallet.ts | 136 +++ dew/tsconfig.json | 19 + dew/tslint.json | 26 + 54 files changed, 4692 insertions(+) create mode 100644 cloud/README.md rename {node => cloud/node}/wallet/.gitignore (100%) rename package-lock.json => cloud/package-lock.json (100%) rename package.json => cloud/package.json (100%) create mode 100644 cloud/src/blockchain.js create mode 100644 cloud/src/blockchain.js.map rename {src => cloud/src}/blockchain.ts (100%) create mode 100644 cloud/src/main.js create mode 100644 cloud/src/main.js.map create mode 100644 cloud/src/main.ts create mode 100644 cloud/src/p2p.js create mode 100644 cloud/src/p2p.js.map rename {src => cloud/src}/p2p.ts (100%) create mode 100644 cloud/src/transaction.js create mode 100644 cloud/src/transaction.js.map rename {src => cloud/src}/transaction.ts (100%) create mode 100644 cloud/src/transactionPool.js create mode 100644 cloud/src/transactionPool.js.map rename {src => cloud/src}/transactionPool.ts (100%) create mode 100644 cloud/src/util.js create mode 100644 cloud/src/util.js.map rename {src => cloud/src}/util.ts (100%) create mode 100644 cloud/src/wallet.js create mode 100644 cloud/src/wallet.js.map rename {src => cloud/src}/wallet.ts (100%) rename tsconfig.json => cloud/tsconfig.json (100%) rename tslint.json => cloud/tslint.json (100%) create mode 100644 dew/README.md create mode 100644 dew/node/wallet/.gitignore create mode 100644 dew/package-lock.json create mode 100644 dew/package.json create mode 100644 dew/src/blockchain.js create mode 100644 dew/src/blockchain.js.map create mode 100644 dew/src/blockchain.ts create mode 100644 dew/src/main.js create mode 100644 dew/src/main.js.map rename {src => dew/src}/main.ts (100%) create mode 100644 dew/src/p2p.js create mode 100644 dew/src/p2p.js.map create mode 100644 dew/src/p2p.ts create mode 100644 dew/src/transaction.js create mode 100644 dew/src/transaction.js.map create mode 100644 dew/src/transaction.ts create mode 100644 dew/src/transactionPool.js create mode 100644 dew/src/transactionPool.js.map create mode 100644 dew/src/transactionPool.ts create mode 100644 dew/src/util.js create mode 100644 dew/src/util.js.map create mode 100644 dew/src/util.ts create mode 100644 dew/src/wallet.js create mode 100644 dew/src/wallet.js.map create mode 100644 dew/src/wallet.ts create mode 100644 dew/tsconfig.json create mode 100644 dew/tslint.json diff --git a/cloud/README.md b/cloud/README.md new file mode 100644 index 0000000..839b976 --- /dev/null +++ b/cloud/README.md @@ -0,0 +1,55 @@ +# Dewcoin + +naivecoin dew computing version. a proof of concept for blockchain applications that follow dew computing principles. http://www.dewcomputing.org/ + +(in progress) + +Basic principles of naivecoin can be found in: A tutorial for building a cryptocurrency https://lhartikk.github.io/ +``` +npm install +npm start +``` + +##### Get blockchain +``` +curl http://localhost:3001/blocks +``` + +##### Mine a block +``` +curl -X POST http://localhost:3001/mineBlock +``` + +##### Send transaction +``` +curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction +``` + +##### Query transaction pool +``` +curl http://localhost:3001/transactionPool +``` + +##### Mine transaction +``` +curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction +``` + +##### Get balance +``` +curl http://localhost:3001/balance +``` + +#### Query information about a specific address +``` +curl http://localhost:3001/address/04f72a4541275aeb4344a8b049bfe2734b49fe25c08d56918f033507b96a61f9e3c330c4fcd46d0854a712dc878b9c280abe90c788c47497e06df78b25bf60ae64 +``` + +##### Add peer +``` +curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addPeer +``` +#### Query connected peers +``` +curl http://localhost:3001/peers +``` diff --git a/node/wallet/.gitignore b/cloud/node/wallet/.gitignore similarity index 100% rename from node/wallet/.gitignore rename to cloud/node/wallet/.gitignore diff --git a/package-lock.json b/cloud/package-lock.json similarity index 100% rename from package-lock.json rename to cloud/package-lock.json diff --git a/package.json b/cloud/package.json similarity index 100% rename from package.json rename to cloud/package.json diff --git a/cloud/src/blockchain.js b/cloud/src/blockchain.js new file mode 100644 index 0000000..1b51687 --- /dev/null +++ b/cloud/src/blockchain.js @@ -0,0 +1,261 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const CryptoJS = require("crypto-js"); +const _ = require("lodash"); +const p2p_1 = require("./p2p"); +const transaction_1 = require("./transaction"); +const transactionPool_1 = require("./transactionPool"); +const util_1 = require("./util"); +const wallet_1 = require("./wallet"); +class Block { + constructor(index, hash, previousHash, timestamp, data, difficulty, nonce) { + this.index = index; + this.previousHash = previousHash; + this.timestamp = timestamp; + this.data = data; + this.hash = hash; + this.difficulty = difficulty; + this.nonce = nonce; + } +} +exports.Block = Block; +const genesisTransaction = { + 'txIns': [{ 'signature': '', 'txOutId': '', 'txOutIndex': 0 }], + 'txOuts': [{ + 'address': '04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a', + 'amount': 50 + }], + 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3' +}; +const genesisBlock = new Block(0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1465154705, [genesisTransaction], 0, 0); +let blockchain = [genesisBlock]; +// the unspent txOut of genesis block is set to unspentTxOuts on startup +let unspentTxOuts = transaction_1.processTransactions(blockchain[0].data, [], 0); +const getBlockchain = () => blockchain; +exports.getBlockchain = getBlockchain; +const getUnspentTxOuts = () => _.cloneDeep(unspentTxOuts); +exports.getUnspentTxOuts = getUnspentTxOuts; +// and txPool should be only updated at the same time +const setUnspentTxOuts = (newUnspentTxOut) => { + console.log('replacing unspentTxouts with: %s', newUnspentTxOut); + unspentTxOuts = newUnspentTxOut; +}; +const getLatestBlock = () => blockchain[blockchain.length - 1]; +exports.getLatestBlock = getLatestBlock; +// in seconds +const BLOCK_GENERATION_INTERVAL = 10; +// in blocks +const DIFFICULTY_ADJUSTMENT_INTERVAL = 10; +const getDifficulty = (aBlockchain) => { + const latestBlock = aBlockchain[blockchain.length - 1]; + if (latestBlock.index % DIFFICULTY_ADJUSTMENT_INTERVAL === 0 && latestBlock.index !== 0) { + return getAdjustedDifficulty(latestBlock, aBlockchain); + } + else { + return latestBlock.difficulty; + } +}; +const getAdjustedDifficulty = (latestBlock, aBlockchain) => { + const prevAdjustmentBlock = aBlockchain[blockchain.length - DIFFICULTY_ADJUSTMENT_INTERVAL]; + const timeExpected = BLOCK_GENERATION_INTERVAL * DIFFICULTY_ADJUSTMENT_INTERVAL; + const timeTaken = latestBlock.timestamp - prevAdjustmentBlock.timestamp; + if (timeTaken < timeExpected / 2) { + return prevAdjustmentBlock.difficulty + 1; + } + else if (timeTaken > timeExpected * 2) { + return prevAdjustmentBlock.difficulty - 1; + } + else { + return prevAdjustmentBlock.difficulty; + } +}; +const getCurrentTimestamp = () => Math.round(new Date().getTime() / 1000); +const generateRawNextBlock = (blockData) => { + const previousBlock = getLatestBlock(); + const difficulty = getDifficulty(getBlockchain()); + const nextIndex = previousBlock.index + 1; + const nextTimestamp = getCurrentTimestamp(); + const newBlock = findBlock(nextIndex, previousBlock.hash, nextTimestamp, blockData, difficulty); + if (addBlockToChain(newBlock)) { + p2p_1.broadcastLatest(); + return newBlock; + } + else { + return null; + } +}; +exports.generateRawNextBlock = generateRawNextBlock; +// gets the unspent transaction outputs owned by the wallet +const getMyUnspentTransactionOutputs = () => { + return wallet_1.findUnspentTxOuts(wallet_1.getPublicFromWallet(), getUnspentTxOuts()); +}; +exports.getMyUnspentTransactionOutputs = getMyUnspentTransactionOutputs; +const generateNextBlock = () => { + const coinbaseTx = transaction_1.getCoinbaseTransaction(wallet_1.getPublicFromWallet(), getLatestBlock().index + 1); + const blockData = [coinbaseTx].concat(transactionPool_1.getTransactionPool()); + return generateRawNextBlock(blockData); +}; +exports.generateNextBlock = generateNextBlock; +const generatenextBlockWithTransaction = (receiverAddress, amount) => { + if (!transaction_1.isValidAddress(receiverAddress)) { + throw Error('invalid address'); + } + if (typeof amount !== 'number') { + throw Error('invalid amount'); + } + const coinbaseTx = transaction_1.getCoinbaseTransaction(wallet_1.getPublicFromWallet(), getLatestBlock().index + 1); + const tx = wallet_1.createTransaction(receiverAddress, amount, wallet_1.getPrivateFromWallet(), getUnspentTxOuts(), transactionPool_1.getTransactionPool()); + const blockData = [coinbaseTx, tx]; + return generateRawNextBlock(blockData); +}; +exports.generatenextBlockWithTransaction = generatenextBlockWithTransaction; +const findBlock = (index, previousHash, timestamp, data, difficulty) => { + let nonce = 0; + while (true) { + const hash = calculateHash(index, previousHash, timestamp, data, difficulty, nonce); + if (hashMatchesDifficulty(hash, difficulty)) { + return new Block(index, hash, previousHash, timestamp, data, difficulty, nonce); + } + nonce++; + } +}; +const getAccountBalance = () => { + return wallet_1.getBalance(wallet_1.getPublicFromWallet(), getUnspentTxOuts()); +}; +exports.getAccountBalance = getAccountBalance; +const sendTransaction = (address, amount) => { + const tx = wallet_1.createTransaction(address, amount, wallet_1.getPrivateFromWallet(), getUnspentTxOuts(), transactionPool_1.getTransactionPool()); + transactionPool_1.addToTransactionPool(tx, getUnspentTxOuts()); + p2p_1.broadCastTransactionPool(); + return tx; +}; +exports.sendTransaction = sendTransaction; +const calculateHashForBlock = (block) => calculateHash(block.index, block.previousHash, block.timestamp, block.data, block.difficulty, block.nonce); +const calculateHash = (index, previousHash, timestamp, data, difficulty, nonce) => CryptoJS.SHA256(index + previousHash + timestamp + data + difficulty + nonce).toString(); +const isValidBlockStructure = (block) => { + return typeof block.index === 'number' + && typeof block.hash === 'string' + && typeof block.previousHash === 'string' + && typeof block.timestamp === 'number' + && typeof block.data === 'object'; +}; +exports.isValidBlockStructure = isValidBlockStructure; +const isValidNewBlock = (newBlock, previousBlock) => { + if (!isValidBlockStructure(newBlock)) { + console.log('invalid block structure: %s', JSON.stringify(newBlock)); + return false; + } + if (previousBlock.index + 1 !== newBlock.index) { + console.log('invalid index'); + return false; + } + else if (previousBlock.hash !== newBlock.previousHash) { + console.log('invalid previoushash'); + return false; + } + else if (!isValidTimestamp(newBlock, previousBlock)) { + console.log('invalid timestamp'); + return false; + } + else if (!hasValidHash(newBlock)) { + return false; + } + return true; +}; +const getAccumulatedDifficulty = (aBlockchain) => { + return aBlockchain + .map((block) => block.difficulty) + .map((difficulty) => Math.pow(2, difficulty)) + .reduce((a, b) => a + b); +}; +const isValidTimestamp = (newBlock, previousBlock) => { + return (previousBlock.timestamp - 60 < newBlock.timestamp) + && newBlock.timestamp - 60 < getCurrentTimestamp(); +}; +const hasValidHash = (block) => { + if (!hashMatchesBlockContent(block)) { + console.log('invalid hash, got:' + block.hash); + return false; + } + if (!hashMatchesDifficulty(block.hash, block.difficulty)) { + console.log('block difficulty not satisfied. Expected: ' + block.difficulty + 'got: ' + block.hash); + } + return true; +}; +const hashMatchesBlockContent = (block) => { + const blockHash = calculateHashForBlock(block); + return blockHash === block.hash; +}; +const hashMatchesDifficulty = (hash, difficulty) => { + const hashInBinary = util_1.hexToBinary(hash); + const requiredPrefix = '0'.repeat(difficulty); + return hashInBinary.startsWith(requiredPrefix); +}; +/* + Checks if the given blockchain is valid. Return the unspent txOuts if the chain is valid + */ +const isValidChain = (blockchainToValidate) => { + console.log('isValidChain:'); + console.log(JSON.stringify(blockchainToValidate)); + const isValidGenesis = (block) => { + return JSON.stringify(block) === JSON.stringify(genesisBlock); + }; + if (!isValidGenesis(blockchainToValidate[0])) { + return null; + } + /* + Validate each block in the chain. The block is valid if the block structure is valid + and the transaction are valid + */ + let aUnspentTxOuts = []; + for (let i = 0; i < blockchainToValidate.length; i++) { + const currentBlock = blockchainToValidate[i]; + if (i !== 0 && !isValidNewBlock(blockchainToValidate[i], blockchainToValidate[i - 1])) { + return null; + } + aUnspentTxOuts = transaction_1.processTransactions(currentBlock.data, aUnspentTxOuts, currentBlock.index); + if (aUnspentTxOuts === null) { + console.log('invalid transactions in blockchain'); + return null; + } + } + return aUnspentTxOuts; +}; +const addBlockToChain = (newBlock) => { + if (isValidNewBlock(newBlock, getLatestBlock())) { + const retVal = transaction_1.processTransactions(newBlock.data, getUnspentTxOuts(), newBlock.index); + if (retVal === null) { + console.log('block is not valid in terms of transactions'); + return false; + } + else { + blockchain.push(newBlock); + setUnspentTxOuts(retVal); + transactionPool_1.updateTransactionPool(unspentTxOuts); + return true; + } + } + return false; +}; +exports.addBlockToChain = addBlockToChain; +const replaceChain = (newBlocks) => { + const aUnspentTxOuts = isValidChain(newBlocks); + const validChain = aUnspentTxOuts !== null; + if (validChain && + getAccumulatedDifficulty(newBlocks) > getAccumulatedDifficulty(getBlockchain())) { + console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); + blockchain = newBlocks; + setUnspentTxOuts(aUnspentTxOuts); + transactionPool_1.updateTransactionPool(unspentTxOuts); + p2p_1.broadcastLatest(); + } + else { + console.log('Received blockchain invalid'); + } +}; +exports.replaceChain = replaceChain; +const handleReceivedTransaction = (transaction) => { + transactionPool_1.addToTransactionPool(transaction, getUnspentTxOuts()); +}; +exports.handleReceivedTransaction = handleReceivedTransaction; +//# sourceMappingURL=blockchain.js.map \ No newline at end of file diff --git a/cloud/src/blockchain.js.map b/cloud/src/blockchain.js.map new file mode 100644 index 0000000..94bd3e2 --- /dev/null +++ b/cloud/src/blockchain.js.map @@ -0,0 +1 @@ +{"version":3,"file":"blockchain.js","sourceRoot":"","sources":["blockchain.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/blockchain.ts b/cloud/src/blockchain.ts similarity index 100% rename from src/blockchain.ts rename to cloud/src/blockchain.ts diff --git a/cloud/src/main.js b/cloud/src/main.js new file mode 100644 index 0000000..ed3bdfb --- /dev/null +++ b/cloud/src/main.js @@ -0,0 +1,122 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const bodyParser = require("body-parser"); +const express = require("express"); +const _ = require("lodash"); +const blockchain_1 = require("./blockchain"); +const p2p_1 = require("./p2p"); +const transactionPool_1 = require("./transactionPool"); +const wallet_1 = require("./wallet"); +const httpPort = parseInt(process.env.HTTP_PORT) || 4001; +const p2pPort = parseInt(process.env.P2P_PORT) || 7001; +const initHttpServer = (myHttpPort) => { + const app = express(); + app.use(bodyParser.json()); + app.use((err, req, res, next) => { + if (err) { + res.status(400).send(err.message); + } + }); + app.get('/blocks', (req, res) => { + res.send(blockchain_1.getBlockchain()); + }); + app.get('/block/:hash', (req, res) => { + const block = _.find(blockchain_1.getBlockchain(), { 'hash': req.params.hash }); + res.send(block); + }); + app.get('/transaction/:id', (req, res) => { + const tx = _(blockchain_1.getBlockchain()) + .map((blocks) => blocks.data) + .flatten() + .find({ 'id': req.params.id }); + res.send(tx); + }); + app.get('/address/:address', (req, res) => { + const unspentTxOuts = _.filter(blockchain_1.getUnspentTxOuts(), (uTxO) => uTxO.address === req.params.address); + res.send({ 'unspentTxOuts': unspentTxOuts }); + }); + app.get('/unspentTransactionOutputs', (req, res) => { + res.send(blockchain_1.getUnspentTxOuts()); + }); + app.get('/myUnspentTransactionOutputs', (req, res) => { + res.send(blockchain_1.getMyUnspentTransactionOutputs()); + }); + app.post('/mineRawBlock', (req, res) => { + if (req.body.data == null) { + res.send('data parameter is missing'); + return; + } + const newBlock = blockchain_1.generateRawNextBlock(req.body.data); + if (newBlock === null) { + res.status(400).send('could not generate block'); + } + else { + res.send(newBlock); + } + }); + app.post('/mineBlock', (req, res) => { + const newBlock = blockchain_1.generateNextBlock(); + if (newBlock === null) { + res.status(400).send('could not generate block'); + } + else { + res.send(newBlock); + } + }); + app.get('/balance', (req, res) => { + const balance = blockchain_1.getAccountBalance(); + res.send({ 'balance': balance }); + }); + app.get('/address', (req, res) => { + const address = wallet_1.getPublicFromWallet(); + res.send({ 'address': address }); + }); + app.post('/mineTransaction', (req, res) => { + const address = req.body.address; + const amount = req.body.amount; + try { + const resp = blockchain_1.generatenextBlockWithTransaction(address, amount); + res.send(resp); + } + catch (e) { + console.log(e.message); + res.status(400).send(e.message); + } + }); + app.post('/sendTransaction', (req, res) => { + try { + const address = req.body.address; + const amount = req.body.amount; + if (address === undefined || amount === undefined) { + throw Error('invalid address or amount'); + } + const resp = blockchain_1.sendTransaction(address, amount); + res.send(resp); + } + catch (e) { + console.log(e.message); + res.status(400).send(e.message); + } + }); + app.get('/transactionPool', (req, res) => { + res.send(transactionPool_1.getTransactionPool()); + }); + app.get('/peers', (req, res) => { + res.send(p2p_1.getSockets().map((s) => s._socket.remoteAddress + ':' + s._socket.remotePort)); + }); + app.post('/addPeer', (req, res) => { + p2p_1.connectToPeers(req.body.peer); + res.send(); + }); + app.post('/stop', (req, res) => { + res.send({ 'msg': 'stopping server' }); + process.exit(); + }); + app.listen(myHttpPort, () => { + console.log('Listening http on port: ' + myHttpPort); + }); +}; +initHttpServer(httpPort); +p2p_1.initP2PServer(p2pPort); +wallet_1.initWallet(); +//# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/cloud/src/main.js.map b/cloud/src/main.js.map new file mode 100644 index 0000000..b723beb --- /dev/null +++ b/cloud/src/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":";;AAAA,0CAA2C;AAC3C,mCAAmC;AACnC,4BAA4B;AAC5B,6CAGsB;AACtB,+BAAgE;AAEhE,uDAAqD;AACrD,qCAAyD;AAEzD,MAAM,QAAQ,GAAW,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AACjE,MAAM,OAAO,GAAW,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;AAE/D,MAAM,cAAc,GAAG,CAAC,UAAkB;IACtC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;IAE3B,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI;QACxB,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG;QACxB,GAAG,CAAC,IAAI,CAAC,0BAAa,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG;QAC7B,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,0BAAa,EAAE,EAAE,EAAC,MAAM,EAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAC,CAAC,CAAC;QAClE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG;QACjC,MAAM,EAAE,GAAG,CAAC,CAAC,0BAAa,EAAE,CAAC;aACxB,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC;aAC5B,OAAO,EAAE;aACT,IAAI,CAAC,EAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAC,CAAC,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,GAAG;QAClC,MAAM,aAAa,GACf,CAAC,CAAC,MAAM,CAAC,6BAAgB,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,KAAK,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChF,GAAG,CAAC,IAAI,CAAC,EAAC,eAAe,EAAE,aAAa,EAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,4BAA4B,EAAE,CAAC,GAAG,EAAE,GAAG;QAC3C,GAAG,CAAC,IAAI,CAAC,6BAAgB,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,8BAA8B,EAAE,CAAC,GAAG,EAAE,GAAG;QAC7C,GAAG,CAAC,IAAI,CAAC,2CAA8B,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG;QAC/B,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YACtC,MAAM,CAAC;QACX,CAAC;QACD,MAAM,QAAQ,GAAU,iCAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,EAAE,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC;YACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACrD,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,GAAG;QAC5B,MAAM,QAAQ,GAAU,8BAAiB,EAAE,CAAC;QAC5C,EAAE,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC;YACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACrD,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG;QACzB,MAAM,OAAO,GAAW,8BAAiB,EAAE,CAAC;QAC5C,GAAG,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,OAAO,EAAC,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG;QACzB,MAAM,OAAO,GAAW,4BAAmB,EAAE,CAAC;QAC9C,GAAG,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,OAAO,EAAC,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG;QAClC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;QACjC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;QAC/B,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,6CAAgC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC/D,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;QAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACT,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACvB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG;QAClC,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;YACjC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;YAE/B,EAAE,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC;gBAChD,MAAM,KAAK,CAAC,2BAA2B,CAAC,CAAC;YAC7C,CAAC;YACD,MAAM,IAAI,GAAG,4BAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC9C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;QAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACT,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACvB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG;QACjC,GAAG,CAAC,IAAI,CAAC,oCAAkB,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG;QACvB,GAAG,CAAC,IAAI,CAAC,gBAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAM,KAAK,CAAC,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG;QAC1B,oBAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,GAAG,CAAC,IAAI,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG;QACvB,GAAG,CAAC,IAAI,CAAC,EAAC,KAAK,EAAG,iBAAiB,EAAC,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE;QACnB,OAAO,CAAC,GAAG,CAAC,0BAA0B,GAAG,UAAU,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,cAAc,CAAC,QAAQ,CAAC,CAAC;AACzB,mBAAa,CAAC,OAAO,CAAC,CAAC;AACvB,mBAAU,EAAE,CAAC"} \ No newline at end of file diff --git a/cloud/src/main.ts b/cloud/src/main.ts new file mode 100644 index 0000000..75f5ae7 --- /dev/null +++ b/cloud/src/main.ts @@ -0,0 +1,141 @@ +import * as bodyParser from 'body-parser'; +import * as express from 'express'; +import * as _ from 'lodash'; +import { + Block, generateNextBlock, generatenextBlockWithTransaction, generateRawNextBlock, getAccountBalance, + getBlockchain, getMyUnspentTransactionOutputs, getUnspentTxOuts, sendTransaction +} from './blockchain'; +import {connectToPeers, getSockets, initP2PServer} from './p2p'; +import {UnspentTxOut} from './transaction'; +import {getTransactionPool} from './transactionPool'; +import {getPublicFromWallet, initWallet} from './wallet'; + +const httpPort: number = parseInt(process.env.HTTP_PORT) || 4001; +const p2pPort: number = parseInt(process.env.P2P_PORT) || 7001; + +const initHttpServer = (myHttpPort: number) => { + const app = express(); + app.use(bodyParser.json()); + + app.use((err, req, res, next) => { + if (err) { + res.status(400).send(err.message); + } + }); + + app.get('/blocks', (req, res) => { + res.send(getBlockchain()); + }); + + app.get('/block/:hash', (req, res) => { + const block = _.find(getBlockchain(), {'hash' : req.params.hash}); + res.send(block); + }); + + app.get('/transaction/:id', (req, res) => { + const tx = _(getBlockchain()) + .map((blocks) => blocks.data) + .flatten() + .find({'id': req.params.id}); + res.send(tx); + }); + + app.get('/address/:address', (req, res) => { + const unspentTxOuts: UnspentTxOut[] = + _.filter(getUnspentTxOuts(), (uTxO) => uTxO.address === req.params.address); + res.send({'unspentTxOuts': unspentTxOuts}); + }); + + app.get('/unspentTransactionOutputs', (req, res) => { + res.send(getUnspentTxOuts()); + }); + + app.get('/myUnspentTransactionOutputs', (req, res) => { + res.send(getMyUnspentTransactionOutputs()); + }); + + app.post('/mineRawBlock', (req, res) => { + if (req.body.data == null) { + res.send('data parameter is missing'); + return; + } + const newBlock: Block = generateRawNextBlock(req.body.data); + if (newBlock === null) { + res.status(400).send('could not generate block'); + } else { + res.send(newBlock); + } + }); + + app.post('/mineBlock', (req, res) => { + const newBlock: Block = generateNextBlock(); + if (newBlock === null) { + res.status(400).send('could not generate block'); + } else { + res.send(newBlock); + } + }); + + app.get('/balance', (req, res) => { + const balance: number = getAccountBalance(); + res.send({'balance': balance}); + }); + + app.get('/address', (req, res) => { + const address: string = getPublicFromWallet(); + res.send({'address': address}); + }); + + app.post('/mineTransaction', (req, res) => { + const address = req.body.address; + const amount = req.body.amount; + try { + const resp = generatenextBlockWithTransaction(address, amount); + res.send(resp); + } catch (e) { + console.log(e.message); + res.status(400).send(e.message); + } + }); + + app.post('/sendTransaction', (req, res) => { + try { + const address = req.body.address; + const amount = req.body.amount; + + if (address === undefined || amount === undefined) { + throw Error('invalid address or amount'); + } + const resp = sendTransaction(address, amount); + res.send(resp); + } catch (e) { + console.log(e.message); + res.status(400).send(e.message); + } + }); + + app.get('/transactionPool', (req, res) => { + res.send(getTransactionPool()); + }); + + app.get('/peers', (req, res) => { + res.send(getSockets().map((s: any) => s._socket.remoteAddress + ':' + s._socket.remotePort)); + }); + app.post('/addPeer', (req, res) => { + connectToPeers(req.body.peer); + res.send(); + }); + + app.post('/stop', (req, res) => { + res.send({'msg' : 'stopping server'}); + process.exit(); + }); + + app.listen(myHttpPort, () => { + console.log('Listening http on port: ' + myHttpPort); + }); +}; + +initHttpServer(httpPort); +initP2PServer(p2pPort); +initWallet(); diff --git a/cloud/src/p2p.js b/cloud/src/p2p.js new file mode 100644 index 0000000..db14e7e --- /dev/null +++ b/cloud/src/p2p.js @@ -0,0 +1,175 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const WebSocket = require("ws"); +const blockchain_1 = require("./blockchain"); +const transactionPool_1 = require("./transactionPool"); +const sockets = []; +var MessageType; +(function (MessageType) { + MessageType[MessageType["QUERY_LATEST"] = 0] = "QUERY_LATEST"; + MessageType[MessageType["QUERY_ALL"] = 1] = "QUERY_ALL"; + MessageType[MessageType["RESPONSE_BLOCKCHAIN"] = 2] = "RESPONSE_BLOCKCHAIN"; + MessageType[MessageType["QUERY_TRANSACTION_POOL"] = 3] = "QUERY_TRANSACTION_POOL"; + MessageType[MessageType["RESPONSE_TRANSACTION_POOL"] = 4] = "RESPONSE_TRANSACTION_POOL"; +})(MessageType || (MessageType = {})); +class Message { +} +const initP2PServer = (p2pPort) => { + const server = new WebSocket.Server({ port: p2pPort }); + server.on('connection', (ws) => { + initConnection(ws); + }); + console.log('listening websocket p2p port on: ' + p2pPort); +}; +exports.initP2PServer = initP2PServer; +const getSockets = () => sockets; +exports.getSockets = getSockets; +const initConnection = (ws) => { + sockets.push(ws); + initMessageHandler(ws); + initErrorHandler(ws); + write(ws, queryChainLengthMsg()); + // query transactions pool only some time after chain query + setTimeout(() => { + broadcast(queryTransactionPoolMsg()); + }, 500); +}; +const JSONToObject = (data) => { + try { + return JSON.parse(data); + } + catch (e) { + console.log(e); + return null; + } +}; +const initMessageHandler = (ws) => { + ws.on('message', (data) => { + try { + const message = JSONToObject(data); + if (message === null) { + console.log('could not parse received JSON message: ' + data); + return; + } + console.log('Received message: %s', JSON.stringify(message)); + switch (message.type) { + case MessageType.QUERY_LATEST: + write(ws, responseLatestMsg()); + break; + case MessageType.QUERY_ALL: + write(ws, responseChainMsg()); + break; + case MessageType.RESPONSE_BLOCKCHAIN: + const receivedBlocks = JSONToObject(message.data); + if (receivedBlocks === null) { + console.log('invalid blocks received: %s', JSON.stringify(message.data)); + break; + } + handleBlockchainResponse(receivedBlocks); + break; + case MessageType.QUERY_TRANSACTION_POOL: + write(ws, responseTransactionPoolMsg()); + break; + case MessageType.RESPONSE_TRANSACTION_POOL: + const receivedTransactions = JSONToObject(message.data); + if (receivedTransactions === null) { + console.log('invalid transaction received: %s', JSON.stringify(message.data)); + break; + } + receivedTransactions.forEach((transaction) => { + try { + blockchain_1.handleReceivedTransaction(transaction); + // if no error is thrown, transaction was indeed added to the pool + // let's broadcast transaction pool + broadCastTransactionPool(); + } + catch (e) { + console.log(e.message); + } + }); + break; + } + } + catch (e) { + console.log(e); + } + }); +}; +const write = (ws, message) => ws.send(JSON.stringify(message)); +const broadcast = (message) => sockets.forEach((socket) => write(socket, message)); +const queryChainLengthMsg = () => ({ 'type': MessageType.QUERY_LATEST, 'data': null }); +const queryAllMsg = () => ({ 'type': MessageType.QUERY_ALL, 'data': null }); +const responseChainMsg = () => ({ + 'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify(blockchain_1.getBlockchain()) +}); +const responseLatestMsg = () => ({ + 'type': MessageType.RESPONSE_BLOCKCHAIN, + 'data': JSON.stringify([blockchain_1.getLatestBlock()]) +}); +const queryTransactionPoolMsg = () => ({ + 'type': MessageType.QUERY_TRANSACTION_POOL, + 'data': null +}); +const responseTransactionPoolMsg = () => ({ + 'type': MessageType.RESPONSE_TRANSACTION_POOL, + 'data': JSON.stringify(transactionPool_1.getTransactionPool()) +}); +const initErrorHandler = (ws) => { + const closeConnection = (myWs) => { + console.log('connection failed to peer: ' + myWs.url); + sockets.splice(sockets.indexOf(myWs), 1); + }; + ws.on('close', () => closeConnection(ws)); + ws.on('error', () => closeConnection(ws)); +}; +const handleBlockchainResponse = (receivedBlocks) => { + if (receivedBlocks.length === 0) { + console.log('received block chain size of 0'); + return; + } + const latestBlockReceived = receivedBlocks[receivedBlocks.length - 1]; + if (!blockchain_1.isValidBlockStructure(latestBlockReceived)) { + console.log('block structuture not valid'); + return; + } + const latestBlockHeld = blockchain_1.getLatestBlock(); + if (latestBlockReceived.index > latestBlockHeld.index) { + console.log('blockchain possibly behind. We got: ' + + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index); + if (latestBlockHeld.hash === latestBlockReceived.previousHash) { + if (blockchain_1.addBlockToChain(latestBlockReceived)) { + broadcast(responseLatestMsg()); + } + } + else if (receivedBlocks.length === 1) { + console.log('We have to query the chain from our peer'); + broadcast(queryAllMsg()); + } + else { + console.log('Received blockchain is longer than current blockchain'); + blockchain_1.replaceChain(receivedBlocks); + } + } + else { + console.log('received blockchain is not longer than received blockchain. Do nothing'); + } +}; +const broadcastLatest = () => { + broadcast(responseLatestMsg()); +}; +exports.broadcastLatest = broadcastLatest; +const connectToPeers = (newPeer) => { + const ws = new WebSocket(newPeer); + ws.on('open', () => { + initConnection(ws); + }); + ws.on('error', () => { + console.log('connection failed'); + }); +}; +exports.connectToPeers = connectToPeers; +const broadCastTransactionPool = () => { + broadcast(responseTransactionPoolMsg()); +}; +exports.broadCastTransactionPool = broadCastTransactionPool; +//# sourceMappingURL=p2p.js.map \ No newline at end of file diff --git a/cloud/src/p2p.js.map b/cloud/src/p2p.js.map new file mode 100644 index 0000000..c86c349 --- /dev/null +++ b/cloud/src/p2p.js.map @@ -0,0 +1 @@ +{"version":3,"file":"p2p.js","sourceRoot":"","sources":["p2p.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/p2p.ts b/cloud/src/p2p.ts similarity index 100% rename from src/p2p.ts rename to cloud/src/p2p.ts diff --git a/cloud/src/transaction.js b/cloud/src/transaction.js new file mode 100644 index 0000000..bb1a059 --- /dev/null +++ b/cloud/src/transaction.js @@ -0,0 +1,298 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const CryptoJS = require("crypto-js"); +const ecdsa = require("elliptic"); +const _ = require("lodash"); +const ec = new ecdsa.ec('secp256k1'); +const COINBASE_AMOUNT = 50; +class UnspentTxOut { + constructor(txOutId, txOutIndex, address, amount) { + this.txOutId = txOutId; + this.txOutIndex = txOutIndex; + this.address = address; + this.amount = amount; + } +} +exports.UnspentTxOut = UnspentTxOut; +class TxIn { +} +exports.TxIn = TxIn; +class TxOut { + constructor(address, amount) { + this.address = address; + this.amount = amount; + } +} +exports.TxOut = TxOut; +class Transaction { +} +exports.Transaction = Transaction; +const getTransactionId = (transaction) => { + const txInContent = transaction.txIns + .map((txIn) => txIn.txOutId + txIn.txOutIndex) + .reduce((a, b) => a + b, ''); + const txOutContent = transaction.txOuts + .map((txOut) => txOut.address + txOut.amount) + .reduce((a, b) => a + b, ''); + return CryptoJS.SHA256(txInContent + txOutContent).toString(); +}; +exports.getTransactionId = getTransactionId; +const validateTransaction = (transaction, aUnspentTxOuts) => { + if (!isValidTransactionStructure(transaction)) { + return false; + } + if (getTransactionId(transaction) !== transaction.id) { + console.log('invalid tx id: ' + transaction.id); + return false; + } + const hasValidTxIns = transaction.txIns + .map((txIn) => validateTxIn(txIn, transaction, aUnspentTxOuts)) + .reduce((a, b) => a && b, true); + if (!hasValidTxIns) { + console.log('some of the txIns are invalid in tx: ' + transaction.id); + return false; + } + const totalTxInValues = transaction.txIns + .map((txIn) => getTxInAmount(txIn, aUnspentTxOuts)) + .reduce((a, b) => (a + b), 0); + const totalTxOutValues = transaction.txOuts + .map((txOut) => txOut.amount) + .reduce((a, b) => (a + b), 0); + if (totalTxOutValues !== totalTxInValues) { + console.log('totalTxOutValues !== totalTxInValues in tx: ' + transaction.id); + return false; + } + return true; +}; +exports.validateTransaction = validateTransaction; +const validateBlockTransactions = (aTransactions, aUnspentTxOuts, blockIndex) => { + const coinbaseTx = aTransactions[0]; + if (!validateCoinbaseTx(coinbaseTx, blockIndex)) { + console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); + return false; + } + // check for duplicate txIns. Each txIn can be included only once + const txIns = _(aTransactions) + .map((tx) => tx.txIns) + .flatten() + .value(); + if (hasDuplicates(txIns)) { + return false; + } + // all but coinbase transactions + const normalTransactions = aTransactions.slice(1); + return normalTransactions.map((tx) => validateTransaction(tx, aUnspentTxOuts)) + .reduce((a, b) => (a && b), true); +}; +const hasDuplicates = (txIns) => { + const groups = _.countBy(txIns, (txIn) => txIn.txOutId + txIn.txOutIndex); + return _(groups) + .map((value, key) => { + if (value > 1) { + console.log('duplicate txIn: ' + key); + return true; + } + else { + return false; + } + }) + .includes(true); +}; +exports.hasDuplicates = hasDuplicates; +const validateCoinbaseTx = (transaction, blockIndex) => { + if (transaction == null) { + console.log('the first transaction in the block must be coinbase transaction'); + return false; + } + if (getTransactionId(transaction) !== transaction.id) { + console.log('invalid coinbase tx id: ' + transaction.id); + return false; + } + if (transaction.txIns.length !== 1) { + console.log('one txIn must be specified in the coinbase transaction'); + return; + } + if (transaction.txIns[0].txOutIndex !== blockIndex) { + console.log('the txIn signature in coinbase tx must be the block height'); + return false; + } + if (transaction.txOuts.length !== 1) { + console.log('invalid number of txOuts in coinbase transaction'); + return false; + } + if (transaction.txOuts[0].amount !== COINBASE_AMOUNT) { + console.log('invalid coinbase amount in coinbase transaction'); + return false; + } + return true; +}; +const validateTxIn = (txIn, transaction, aUnspentTxOuts) => { + const referencedUTxOut = aUnspentTxOuts.find((uTxO) => uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex); + if (referencedUTxOut == null) { + console.log('referenced txOut not found: ' + JSON.stringify(txIn)); + return false; + } + const address = referencedUTxOut.address; + const key = ec.keyFromPublic(address, 'hex'); + const validSignature = key.verify(transaction.id, txIn.signature); + if (!validSignature) { + console.log('invalid txIn signature: %s txId: %s address: %s', txIn.signature, transaction.id, referencedUTxOut.address); + return false; + } + return true; +}; +const getTxInAmount = (txIn, aUnspentTxOuts) => { + return findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts).amount; +}; +const findUnspentTxOut = (transactionId, index, aUnspentTxOuts) => { + return aUnspentTxOuts.find((uTxO) => uTxO.txOutId === transactionId && uTxO.txOutIndex === index); +}; +const getCoinbaseTransaction = (address, blockIndex) => { + const t = new Transaction(); + const txIn = new TxIn(); + txIn.signature = ''; + txIn.txOutId = ''; + txIn.txOutIndex = blockIndex; + t.txIns = [txIn]; + t.txOuts = [new TxOut(address, COINBASE_AMOUNT)]; + t.id = getTransactionId(t); + return t; +}; +exports.getCoinbaseTransaction = getCoinbaseTransaction; +const signTxIn = (transaction, txInIndex, privateKey, aUnspentTxOuts) => { + const txIn = transaction.txIns[txInIndex]; + const dataToSign = transaction.id; + const referencedUnspentTxOut = findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts); + if (referencedUnspentTxOut == null) { + console.log('could not find referenced txOut'); + throw Error(); + } + const referencedAddress = referencedUnspentTxOut.address; + if (getPublicKey(privateKey) !== referencedAddress) { + console.log('trying to sign an input with private' + + ' key that does not match the address that is referenced in txIn'); + throw Error(); + } + const key = ec.keyFromPrivate(privateKey, 'hex'); + const signature = toHexString(key.sign(dataToSign).toDER()); + return signature; +}; +exports.signTxIn = signTxIn; +const updateUnspentTxOuts = (aTransactions, aUnspentTxOuts) => { + const newUnspentTxOuts = aTransactions + .map((t) => { + return t.txOuts.map((txOut, index) => new UnspentTxOut(t.id, index, txOut.address, txOut.amount)); + }) + .reduce((a, b) => a.concat(b), []); + const consumedTxOuts = aTransactions + .map((t) => t.txIns) + .reduce((a, b) => a.concat(b), []) + .map((txIn) => new UnspentTxOut(txIn.txOutId, txIn.txOutIndex, '', 0)); + const resultingUnspentTxOuts = aUnspentTxOuts + .filter(((uTxO) => !findUnspentTxOut(uTxO.txOutId, uTxO.txOutIndex, consumedTxOuts))) + .concat(newUnspentTxOuts); + return resultingUnspentTxOuts; +}; +const processTransactions = (aTransactions, aUnspentTxOuts, blockIndex) => { + if (!validateBlockTransactions(aTransactions, aUnspentTxOuts, blockIndex)) { + console.log('invalid block transactions'); + return null; + } + return updateUnspentTxOuts(aTransactions, aUnspentTxOuts); +}; +exports.processTransactions = processTransactions; +const toHexString = (byteArray) => { + return Array.from(byteArray, (byte) => { + return ('0' + (byte & 0xFF).toString(16)).slice(-2); + }).join(''); +}; +const getPublicKey = (aPrivateKey) => { + return ec.keyFromPrivate(aPrivateKey, 'hex').getPublic().encode('hex'); +}; +exports.getPublicKey = getPublicKey; +const isValidTxInStructure = (txIn) => { + if (txIn == null) { + console.log('txIn is null'); + return false; + } + else if (typeof txIn.signature !== 'string') { + console.log('invalid signature type in txIn'); + return false; + } + else if (typeof txIn.txOutId !== 'string') { + console.log('invalid txOutId type in txIn'); + return false; + } + else if (typeof txIn.txOutIndex !== 'number') { + console.log('invalid txOutIndex type in txIn'); + return false; + } + else { + return true; + } +}; +const isValidTxOutStructure = (txOut) => { + if (txOut == null) { + console.log('txOut is null'); + return false; + } + else if (typeof txOut.address !== 'string') { + console.log('invalid address type in txOut'); + return false; + } + else if (!isValidAddress(txOut.address)) { + console.log('invalid TxOut address'); + return false; + } + else if (typeof txOut.amount !== 'number') { + console.log('invalid amount type in txOut'); + return false; + } + else { + return true; + } +}; +const isValidTransactionStructure = (transaction) => { + if (typeof transaction.id !== 'string') { + console.log('transactionId missing'); + return false; + } + if (!(transaction.txIns instanceof Array)) { + console.log('invalid txIns type in transaction'); + return false; + } + if (!transaction.txIns + .map(isValidTxInStructure) + .reduce((a, b) => (a && b), true)) { + return false; + } + if (!(transaction.txOuts instanceof Array)) { + console.log('invalid txIns type in transaction'); + return false; + } + if (!transaction.txOuts + .map(isValidTxOutStructure) + .reduce((a, b) => (a && b), true)) { + return false; + } + return true; +}; +// valid address is a valid ecdsa public key in the 04 + X-coordinate + Y-coordinate format +const isValidAddress = (address) => { + if (address.length !== 130) { + console.log(address); + console.log('invalid public key length'); + return false; + } + else if (address.match('^[a-fA-F0-9]+$') === null) { + console.log('public key must contain only hex characters'); + return false; + } + else if (!address.startsWith('04')) { + console.log('public key must start with 04'); + return false; + } + return true; +}; +exports.isValidAddress = isValidAddress; +//# sourceMappingURL=transaction.js.map \ No newline at end of file diff --git a/cloud/src/transaction.js.map b/cloud/src/transaction.js.map new file mode 100644 index 0000000..fd33576 --- /dev/null +++ b/cloud/src/transaction.js.map @@ -0,0 +1 @@ +{"version":3,"file":"transaction.js","sourceRoot":"","sources":["transaction.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/transaction.ts b/cloud/src/transaction.ts similarity index 100% rename from src/transaction.ts rename to cloud/src/transaction.ts diff --git a/cloud/src/transactionPool.js b/cloud/src/transactionPool.js new file mode 100644 index 0000000..c7a53d3 --- /dev/null +++ b/cloud/src/transactionPool.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const _ = require("lodash"); +const transaction_1 = require("./transaction"); +let transactionPool = []; +const getTransactionPool = () => { + return _.cloneDeep(transactionPool); +}; +exports.getTransactionPool = getTransactionPool; +const addToTransactionPool = (tx, unspentTxOuts) => { + if (!transaction_1.validateTransaction(tx, unspentTxOuts)) { + throw Error('Trying to add invalid tx to pool'); + } + if (!isValidTxForPool(tx, transactionPool)) { + throw Error('Trying to add invalid tx to pool'); + } + console.log('adding to txPool: %s', JSON.stringify(tx)); + transactionPool.push(tx); +}; +exports.addToTransactionPool = addToTransactionPool; +const hasTxIn = (txIn, unspentTxOuts) => { + const foundTxIn = unspentTxOuts.find((uTxO) => { + return uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex; + }); + return foundTxIn !== undefined; +}; +const updateTransactionPool = (unspentTxOuts) => { + const invalidTxs = []; + for (const tx of transactionPool) { + for (const txIn of tx.txIns) { + if (!hasTxIn(txIn, unspentTxOuts)) { + invalidTxs.push(tx); + break; + } + } + } + if (invalidTxs.length > 0) { + console.log('removing the following transactions from txPool: %s', JSON.stringify(invalidTxs)); + transactionPool = _.without(transactionPool, ...invalidTxs); + } +}; +exports.updateTransactionPool = updateTransactionPool; +const getTxPoolIns = (aTransactionPool) => { + return _(aTransactionPool) + .map((tx) => tx.txIns) + .flatten() + .value(); +}; +const isValidTxForPool = (tx, aTtransactionPool) => { + const txPoolIns = getTxPoolIns(aTtransactionPool); + const containsTxIn = (txIns, txIn) => { + return _.find(txPoolIns, ((txPoolIn) => { + return txIn.txOutIndex === txPoolIn.txOutIndex && txIn.txOutId === txPoolIn.txOutId; + })); + }; + for (const txIn of tx.txIns) { + if (containsTxIn(txPoolIns, txIn)) { + console.log('txIn already found in the txPool'); + return false; + } + } + return true; +}; +//# sourceMappingURL=transactionPool.js.map \ No newline at end of file diff --git a/cloud/src/transactionPool.js.map b/cloud/src/transactionPool.js.map new file mode 100644 index 0000000..50a6e7c --- /dev/null +++ b/cloud/src/transactionPool.js.map @@ -0,0 +1 @@ +{"version":3,"file":"transactionPool.js","sourceRoot":"","sources":["transactionPool.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/transactionPool.ts b/cloud/src/transactionPool.ts similarity index 100% rename from src/transactionPool.ts rename to cloud/src/transactionPool.ts diff --git a/cloud/src/util.js b/cloud/src/util.js new file mode 100644 index 0000000..9ccd8be --- /dev/null +++ b/cloud/src/util.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const hexToBinary = (s) => { + let ret = ''; + const lookupTable = { + '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', + '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', + 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', + 'e': '1110', 'f': '1111' + }; + for (let i = 0; i < s.length; i = i + 1) { + if (lookupTable[s[i]]) { + ret += lookupTable[s[i]]; + } + else { + return null; + } + } + return ret; +}; +exports.hexToBinary = hexToBinary; +//# sourceMappingURL=util.js.map \ No newline at end of file diff --git a/cloud/src/util.js.map b/cloud/src/util.js.map new file mode 100644 index 0000000..c8d4f6c --- /dev/null +++ b/cloud/src/util.js.map @@ -0,0 +1 @@ +{"version":3,"file":"util.js","sourceRoot":"","sources":["util.ts"],"names":[],"mappings":";;AAAA,MAAM,WAAW,GAAG,CAAC,CAAS;IAC1B,IAAI,GAAG,GAAW,EAAE,CAAC;IACrB,MAAM,WAAW,GAAG;QAChB,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAC/D,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAC/D,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAClD,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;KAC3B,CAAC;IACF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpB,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,MAAM,CAAC,GAAG,CAAC;AACf,CAAC,CAAC;AAEM,kCAAW"} \ No newline at end of file diff --git a/src/util.ts b/cloud/src/util.ts similarity index 100% rename from src/util.ts rename to cloud/src/util.ts diff --git a/cloud/src/wallet.js b/cloud/src/wallet.js new file mode 100644 index 0000000..0501bf4 --- /dev/null +++ b/cloud/src/wallet.js @@ -0,0 +1,120 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const elliptic_1 = require("elliptic"); +const fs_1 = require("fs"); +const _ = require("lodash"); +const transaction_1 = require("./transaction"); +const EC = new elliptic_1.ec('secp256k1'); +const privateKeyLocation = process.env.PRIVATE_KEY || 'node/wallet/private_key'; +const getPrivateFromWallet = () => { + const buffer = fs_1.readFileSync(privateKeyLocation, 'utf8'); + return buffer.toString(); +}; +exports.getPrivateFromWallet = getPrivateFromWallet; +const getPublicFromWallet = () => { + const privateKey = getPrivateFromWallet(); + const key = EC.keyFromPrivate(privateKey, 'hex'); + return key.getPublic().encode('hex'); +}; +exports.getPublicFromWallet = getPublicFromWallet; +const generatePrivateKey = () => { + const keyPair = EC.genKeyPair(); + const privateKey = keyPair.getPrivate(); + return privateKey.toString(16); +}; +exports.generatePrivateKey = generatePrivateKey; +const initWallet = () => { + // let's not override existing private keys + if (fs_1.existsSync(privateKeyLocation)) { + return; + } + const newPrivateKey = generatePrivateKey(); + fs_1.writeFileSync(privateKeyLocation, newPrivateKey); + console.log('new wallet with private key created to : %s', privateKeyLocation); +}; +exports.initWallet = initWallet; +const deleteWallet = () => { + if (fs_1.existsSync(privateKeyLocation)) { + fs_1.unlinkSync(privateKeyLocation); + } +}; +exports.deleteWallet = deleteWallet; +const getBalance = (address, unspentTxOuts) => { + return _(findUnspentTxOuts(address, unspentTxOuts)) + .map((uTxO) => uTxO.amount) + .sum(); +}; +exports.getBalance = getBalance; +const findUnspentTxOuts = (ownerAddress, unspentTxOuts) => { + return _.filter(unspentTxOuts, (uTxO) => uTxO.address === ownerAddress); +}; +exports.findUnspentTxOuts = findUnspentTxOuts; +const findTxOutsForAmount = (amount, myUnspentTxOuts) => { + let currentAmount = 0; + const includedUnspentTxOuts = []; + for (const myUnspentTxOut of myUnspentTxOuts) { + includedUnspentTxOuts.push(myUnspentTxOut); + currentAmount = currentAmount + myUnspentTxOut.amount; + if (currentAmount >= amount) { + const leftOverAmount = currentAmount - amount; + return { includedUnspentTxOuts, leftOverAmount }; + } + } + const eMsg = 'Cannot create transaction from the available unspent transaction outputs.' + + ' Required amount:' + amount + '. Available unspentTxOuts:' + JSON.stringify(myUnspentTxOuts); + throw Error(eMsg); +}; +const createTxOuts = (receiverAddress, myAddress, amount, leftOverAmount) => { + const txOut1 = new transaction_1.TxOut(receiverAddress, amount); + if (leftOverAmount === 0) { + return [txOut1]; + } + else { + const leftOverTx = new transaction_1.TxOut(myAddress, leftOverAmount); + return [txOut1, leftOverTx]; + } +}; +const filterTxPoolTxs = (unspentTxOuts, transactionPool) => { + const txIns = _(transactionPool) + .map((tx) => tx.txIns) + .flatten() + .value(); + const removable = []; + for (const unspentTxOut of unspentTxOuts) { + const txIn = _.find(txIns, (aTxIn) => { + return aTxIn.txOutIndex === unspentTxOut.txOutIndex && aTxIn.txOutId === unspentTxOut.txOutId; + }); + if (txIn === undefined) { + } + else { + removable.push(unspentTxOut); + } + } + return _.without(unspentTxOuts, ...removable); +}; +const createTransaction = (receiverAddress, amount, privateKey, unspentTxOuts, txPool) => { + console.log('txPool: %s', JSON.stringify(txPool)); + const myAddress = transaction_1.getPublicKey(privateKey); + const myUnspentTxOutsA = unspentTxOuts.filter((uTxO) => uTxO.address === myAddress); + const myUnspentTxOuts = filterTxPoolTxs(myUnspentTxOutsA, txPool); + // filter from unspentOutputs such inputs that are referenced in pool + const { includedUnspentTxOuts, leftOverAmount } = findTxOutsForAmount(amount, myUnspentTxOuts); + const toUnsignedTxIn = (unspentTxOut) => { + const txIn = new transaction_1.TxIn(); + txIn.txOutId = unspentTxOut.txOutId; + txIn.txOutIndex = unspentTxOut.txOutIndex; + return txIn; + }; + const unsignedTxIns = includedUnspentTxOuts.map(toUnsignedTxIn); + const tx = new transaction_1.Transaction(); + tx.txIns = unsignedTxIns; + tx.txOuts = createTxOuts(receiverAddress, myAddress, amount, leftOverAmount); + tx.id = transaction_1.getTransactionId(tx); + tx.txIns = tx.txIns.map((txIn, index) => { + txIn.signature = transaction_1.signTxIn(tx, index, privateKey, unspentTxOuts); + return txIn; + }); + return tx; +}; +exports.createTransaction = createTransaction; +//# sourceMappingURL=wallet.js.map \ No newline at end of file diff --git a/cloud/src/wallet.js.map b/cloud/src/wallet.js.map new file mode 100644 index 0000000..5895928 --- /dev/null +++ b/cloud/src/wallet.js.map @@ -0,0 +1 @@ +{"version":3,"file":"wallet.js","sourceRoot":"","sources":["wallet.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/wallet.ts b/cloud/src/wallet.ts similarity index 100% rename from src/wallet.ts rename to cloud/src/wallet.ts diff --git a/tsconfig.json b/cloud/tsconfig.json similarity index 100% rename from tsconfig.json rename to cloud/tsconfig.json diff --git a/tslint.json b/cloud/tslint.json similarity index 100% rename from tslint.json rename to cloud/tslint.json diff --git a/dew/README.md b/dew/README.md new file mode 100644 index 0000000..839b976 --- /dev/null +++ b/dew/README.md @@ -0,0 +1,55 @@ +# Dewcoin + +naivecoin dew computing version. a proof of concept for blockchain applications that follow dew computing principles. http://www.dewcomputing.org/ + +(in progress) + +Basic principles of naivecoin can be found in: A tutorial for building a cryptocurrency https://lhartikk.github.io/ +``` +npm install +npm start +``` + +##### Get blockchain +``` +curl http://localhost:3001/blocks +``` + +##### Mine a block +``` +curl -X POST http://localhost:3001/mineBlock +``` + +##### Send transaction +``` +curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction +``` + +##### Query transaction pool +``` +curl http://localhost:3001/transactionPool +``` + +##### Mine transaction +``` +curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction +``` + +##### Get balance +``` +curl http://localhost:3001/balance +``` + +#### Query information about a specific address +``` +curl http://localhost:3001/address/04f72a4541275aeb4344a8b049bfe2734b49fe25c08d56918f033507b96a61f9e3c330c4fcd46d0854a712dc878b9c280abe90c788c47497e06df78b25bf60ae64 +``` + +##### Add peer +``` +curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addPeer +``` +#### Query connected peers +``` +curl http://localhost:3001/peers +``` diff --git a/dew/node/wallet/.gitignore b/dew/node/wallet/.gitignore new file mode 100644 index 0000000..aa8f673 --- /dev/null +++ b/dew/node/wallet/.gitignore @@ -0,0 +1,2 @@ +!.gitignore +private_key diff --git a/dew/package-lock.json b/dew/package-lock.json new file mode 100644 index 0000000..985c1ef --- /dev/null +++ b/dew/package-lock.json @@ -0,0 +1,1077 @@ +{ + "name": "naivechain", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/body-parser": { + "version": "1.16.4", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.16.4.tgz", + "integrity": "sha512-y8GxleWZ4ep0GG9IFMg+HpZWqLPjAjqc65cAopXPAWONWGCWGT0FCPVlXbUEBOPWpYtFrvlp2D7EJJnrqLUnEQ==", + "dev": true, + "requires": { + "@types/express": "4.0.36", + "@types/node": "8.0.9" + } + }, + "@types/crypto-js": { + "version": "3.1.33", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-3.1.33.tgz", + "integrity": "sha1-fmyRYDUz4M2fJ5qEBam543mIDF0=", + "dev": true + }, + "@types/express": { + "version": "4.0.36", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.0.36.tgz", + "integrity": "sha512-bT9q2eqH/E72AGBQKT50dh6AXzheTqigGZ1GwDiwmx7vfHff0bZOrvUWjvGpNWPNkRmX1vDF6wonG6rlpBHb1A==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "4.0.49", + "@types/serve-static": "1.7.31" + } + }, + "@types/express-serve-static-core": { + "version": "4.0.49", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.0.49.tgz", + "integrity": "sha512-b7mVHoURu1xaP/V6xw1sYwyv9V0EZ7euyi+sdnbnTZxEkAh4/hzPsI6Eflq+ZzHQ/Tgl7l16Jz+0oz8F46MLnA==", + "dev": true, + "requires": { + "@types/node": "8.0.9" + } + }, + "@types/lodash": { + "version": "4.14.85", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.85.tgz", + "integrity": "sha512-HrZiwDl62if0z31+rB99CLlg7WzS7b+KmyW75XAHEl/ZG0De2ACo6skZ89Zh3jOWkjKObN0Apq3MUezg7u9NKQ==", + "dev": true + }, + "@types/mime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.1.tgz", + "integrity": "sha512-rek8twk9C58gHYqIrUlJsx8NQMhlxqHzln9Z9ODqiNgv3/s+ZwIrfr+djqzsnVM12xe9hL98iJ20lj2RvCBv6A==", + "dev": true + }, + "@types/node": { + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.9.tgz", + "integrity": "sha512-UkiiJp6Iz2h4xzapN8BPKjhq+/BlyXcISwPVk2Kd7VJ/I1TREFokjBtvM6hftANXdsfo1IoWMXhmg8G8X+SS8Q==", + "dev": true + }, + "@types/serve-static": { + "version": "1.7.31", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.7.31.tgz", + "integrity": "sha1-FUVt6NmNa0z/Mb5savdJKuY/Uho=", + "dev": true, + "requires": { + "@types/express-serve-static-core": "4.0.49", + "@types/mime": "1.3.1" + } + }, + "@types/ws": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-3.0.1.tgz", + "integrity": "sha512-cfBmtvCOil/OIeNU+qB0cfKaVcVqnnJQDSy1jwBltV76mWIxtieITsvKEyIC1bYn4rx/M8q0Pn9qa52sMbtRGg==", + "dev": true, + "requires": { + "@types/node": "8.0.9" + } + }, + "accepts": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz", + "integrity": "sha1-5fHzkoxtlf2WVYw27D2dDeSm7Oo=", + "requires": { + "mime-types": "2.1.15", + "negotiator": "0.5.3" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz", + "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=", + "requires": { + "color-convert": "1.9.0" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "axios": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.16.2.tgz", + "integrity": "sha1-uk+S8XFn37q0CYN4VFS5rBScPG0=", + "requires": { + "follow-redirects": "1.2.4", + "is-buffer": "1.1.5" + } + }, + "babel-code-frame": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bn.js": { + "version": "4.11.7", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.7.tgz", + "integrity": "sha512-LxFiV5mefv0ley0SzqkOPR1bC4EbpPx8LkOz5vMe/Yi15t5hzwgO/G+tc7wOtL4PZTYjwHu8JnEiSLumuSjSfA==" + }, + "body-parser": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.17.2.tgz", + "integrity": "sha1-+IkqvI+eYn1Crtr7yma/WrmRBO4=", + "requires": { + "bytes": "2.4.0", + "content-type": "1.0.2", + "debug": "2.6.7", + "depd": "1.1.0", + "http-errors": "1.6.1", + "iconv-lite": "0.4.15", + "on-finished": "2.3.0", + "qs": "6.4.0", + "raw-body": "2.2.0", + "type-is": "1.6.15" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "bytes": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz", + "integrity": "sha1-fZcZb51br39pNeJZhVSe3SpsIzk=" + }, + "chalk": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.0.1.tgz", + "integrity": "sha512-Mp+FXEI+FrwY/XYV45b2YD3E8i3HwnEAoFcM0qlZzq/RZ9RwWitt2Y/c7cqRAz70U7hfekqx6qNYthuKFO6K0g==", + "requires": { + "ansi-styles": "3.1.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.2.0" + } + }, + "color-convert": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", + "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", + "requires": { + "color-name": "1.1.2" + } + }, + "color-name": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.2.tgz", + "integrity": "sha1-XIq3K2S9IhXWF66VWeuxSEdc+Y0=" + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "content-disposition": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.0.tgz", + "integrity": "sha1-QoT+auBjCHRjnkToCkGMKTQTXp4=" + }, + "content-type": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz", + "integrity": "sha1-t9ETrueo3Se9IRM8TcJSnfFyHu0=" + }, + "cookie": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.2.tgz", + "integrity": "sha1-cv7D0k5Io0Mgc9kMEmQgBQYQBLE=" + }, + "cookie-signature": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.5.tgz", + "integrity": "sha1-oSLj8VA+yg9TVXlbBxG7I2jUUPk=" + }, + "crc": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.2.1.tgz", + "integrity": "sha1-XZyPt3okXNXsopHl0tAFM0urAII=" + }, + "cross-env": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.0.1.tgz", + "integrity": "sha1-/05y6kO0faJIa0On8gQ7JgnkSRM=", + "requires": { + "cross-spawn": "5.1.0", + "is-windows": "1.0.1" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.2.14" + } + }, + "crypto-js": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.8.tgz", + "integrity": "sha1-cV8HC/YBTyrpkqmLOSkli3E/CNU=" + }, + "debug": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.7.tgz", + "integrity": "sha1-krrR9tBbu2u6Isyoi80OyJTChh4=", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz", + "integrity": "sha1-4b2Cxqq2ztlluXuIsX7T5SjKGMM=" + }, + "destroy": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.3.tgz", + "integrity": "sha1-tDO0ck5x/YVR2YhRdIUcX8N34sk=" + }, + "diff": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.0.tgz", + "integrity": "sha512-w0XZubFWn0Adlsapj9EAWX0FqWdO4tz8kc3RiYdWLh4k/V8PTb6i0SMgXt0vRM3zyKnT8tKO7mUlieRQHIjMNg==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "elliptic": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", + "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "requires": { + "bn.js": "4.11.7", + "brorand": "1.1.0", + "hash.js": "1.1.3", + "hmac-drbg": "1.0.1", + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "escape-html": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz", + "integrity": "sha1-GBoobq05ejmpKFfPsdQwUuNWv/A=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "etag": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.5.1.tgz", + "integrity": "sha1-VMUN4E7kJpVWKSWsVmWIKRvn6eo=", + "requires": { + "crc": "3.2.1" + } + }, + "express": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.11.2.tgz", + "integrity": "sha1-jfPVqayEhYXwCgd3YBgj+uzTsUg=", + "requires": { + "accepts": "1.2.13", + "content-disposition": "0.5.0", + "cookie": "0.1.2", + "cookie-signature": "1.0.5", + "debug": "2.1.3", + "depd": "1.0.1", + "escape-html": "1.0.1", + "etag": "1.5.1", + "finalhandler": "0.3.3", + "fresh": "0.2.4", + "media-typer": "0.3.0", + "merge-descriptors": "0.0.2", + "methods": "1.1.2", + "on-finished": "2.2.1", + "parseurl": "1.3.1", + "path-to-regexp": "0.1.3", + "proxy-addr": "1.0.10", + "qs": "2.3.3", + "range-parser": "1.0.3", + "send": "0.11.1", + "serve-static": "1.8.1", + "type-is": "1.5.7", + "utils-merge": "1.0.0", + "vary": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.1.3.tgz", + "integrity": "sha1-zoqxte6PvuK/o7Yzyrk9NmtjQY4=", + "requires": { + "ms": "0.7.0" + } + }, + "depd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", + "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=" + }, + "ee-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.0.tgz", + "integrity": "sha1-ag18YiHkkP7v2S7D9EHJzozQl/Q=" + }, + "mime-db": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz", + "integrity": "sha1-PQxjGA9FjrENMlqqN9fFiuMS6dc=" + }, + "mime-types": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz", + "integrity": "sha1-MQ4VnbI+B3+Lsit0jav6SVcUCqY=", + "requires": { + "mime-db": "1.12.0" + } + }, + "ms": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.0.tgz", + "integrity": "sha1-hlvpTC5zl62KV9pqYzpuLzB5i4M=" + }, + "on-finished": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.2.1.tgz", + "integrity": "sha1-XIXBzDYpn3gCllP2Z/J7a5nrwCk=", + "requires": { + "ee-first": "1.1.0" + } + }, + "qs": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz", + "integrity": "sha1-6eha2+ddoLvkyOBHaghikPhjtAQ=" + }, + "type-is": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.5.7.tgz", + "integrity": "sha1-uTaKWTzG730GReeLL0xky+zQXpA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.0.14" + } + } + } + }, + "finalhandler": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.3.3.tgz", + "integrity": "sha1-saCaoeamB7NUFmmwm8tyf0YM1CY=", + "requires": { + "debug": "2.1.3", + "escape-html": "1.0.1", + "on-finished": "2.2.1" + }, + "dependencies": { + "debug": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.1.3.tgz", + "integrity": "sha1-zoqxte6PvuK/o7Yzyrk9NmtjQY4=", + "requires": { + "ms": "0.7.0" + } + }, + "ee-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.0.tgz", + "integrity": "sha1-ag18YiHkkP7v2S7D9EHJzozQl/Q=" + }, + "ms": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.0.tgz", + "integrity": "sha1-hlvpTC5zl62KV9pqYzpuLzB5i4M=" + }, + "on-finished": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.2.1.tgz", + "integrity": "sha1-XIXBzDYpn3gCllP2Z/J7a5nrwCk=", + "requires": { + "ee-first": "1.1.0" + } + } + } + }, + "follow-redirects": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.2.4.tgz", + "integrity": "sha512-Suw6KewLV2hReSyEOeql+UUkBVyiBm3ok1VPrVFRZnQInWpdoZbbiG5i8aJVSjTr0yQ4Ava0Sh6/joCg1Brdqw==", + "requires": { + "debug": "2.6.7" + } + }, + "forwarded": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz", + "integrity": "sha1-Ge+YdMSuHCl7zweP3mOgm2aoQ2M=" + }, + "fresh": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.4.tgz", + "integrity": "sha1-NYJJkgbJcjcUGQ7ddLRgT+tKYUw=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + }, + "hash.js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", + "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "requires": { + "inherits": "2.0.3", + "minimalistic-assert": "1.0.0" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "1.1.3", + "minimalistic-assert": "1.0.0", + "minimalistic-crypto-utils": "1.0.1" + } + }, + "http-errors": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.1.tgz", + "integrity": "sha1-X4uO2YrKVFZWv1cplzh/kEpyIlc=", + "requires": { + "depd": "1.1.0", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.3.1" + } + }, + "iconv-lite": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ipaddr.js": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz", + "integrity": "sha1-X6eM8wG4JceKvDBC2BJyMEnqI8c=" + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" + }, + "is-windows": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.1.tgz", + "integrity": "sha1-MQ23D3QtJZoWo2kgK1GvhCMzENk=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "make-error": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.0.tgz", + "integrity": "sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y=" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-descriptors": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-0.0.2.tgz", + "integrity": "sha1-w2pSp4FDdRPFcnXzndnTF1FKyMc=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA=" + }, + "mime-db": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" + }, + "mime-types": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "requires": { + "mime-db": "1.27.0" + } + }, + "minimalistic-assert": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", + "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz", + "integrity": "sha1-Jp1cR2gQ7JLtvntsLygxY4T5p+g=" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "parseurl": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz", + "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.3.tgz", + "integrity": "sha1-IbmrgidCed4lsVbqCP0SylG4rss=" + }, + "proxy-addr": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz", + "integrity": "sha1-DUCoL4Afw1VWfS7LZe/j8HfxIcU=", + "requires": { + "forwarded": "0.1.0", + "ipaddr.js": "1.0.5" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + }, + "range-parser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz", + "integrity": "sha1-aHKCNTXGkuLCoBA4Jq/YLC4P8XU=" + }, + "raw-body": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.2.0.tgz", + "integrity": "sha1-mUl2z2pQlqQRYoQEkvC9xdbn+5Y=", + "requires": { + "bytes": "2.4.0", + "iconv-lite": "0.4.15", + "unpipe": "1.0.0" + } + }, + "resolve": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", + "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "safe-buffer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", + "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + }, + "send": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.11.1.tgz", + "integrity": "sha1-G+q/1C+eJwn5kCivMHisErRwktU=", + "requires": { + "debug": "2.1.3", + "depd": "1.0.1", + "destroy": "1.0.3", + "escape-html": "1.0.1", + "etag": "1.5.1", + "fresh": "0.2.4", + "mime": "1.2.11", + "ms": "0.7.0", + "on-finished": "2.2.1", + "range-parser": "1.0.3" + }, + "dependencies": { + "debug": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.1.3.tgz", + "integrity": "sha1-zoqxte6PvuK/o7Yzyrk9NmtjQY4=", + "requires": { + "ms": "0.7.0" + } + }, + "depd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.0.1.tgz", + "integrity": "sha1-gK7GTJ1tl+ZcwqnKqTwKpqv3Oqo=" + }, + "ee-first": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.0.tgz", + "integrity": "sha1-ag18YiHkkP7v2S7D9EHJzozQl/Q=" + }, + "ms": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.0.tgz", + "integrity": "sha1-hlvpTC5zl62KV9pqYzpuLzB5i4M=" + }, + "on-finished": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.2.1.tgz", + "integrity": "sha1-XIXBzDYpn3gCllP2Z/J7a5nrwCk=", + "requires": { + "ee-first": "1.1.0" + } + } + } + }, + "serve-static": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.8.1.tgz", + "integrity": "sha1-CPq9OZmfBQ/DEUQ/RtWIinfs/Hw=", + "requires": { + "escape-html": "1.0.1", + "parseurl": "1.3.1", + "send": "0.11.1", + "utils-merge": "1.0.0" + } + }, + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=" + }, + "source-map-support": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.15.tgz", + "integrity": "sha1-AyAt9lwG0r2MfsI2KhkwVv7407E=", + "requires": { + "source-map": "0.5.6" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.2.0.tgz", + "integrity": "sha512-Ts0Mu/A1S1aZxEJNG88I4Oc9rcZSBFNac5e27yh4j2mqbhZSSzR1Ah79EYwSn9Zuh7lrlGD2cVGzw1RKGzyLSg==", + "requires": { + "has-flag": "2.0.0" + } + }, + "ts-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.2.0.tgz", + "integrity": "sha1-mBTwwBQXhJAM8S/vEZetS39NI9E=", + "requires": { + "arrify": "1.0.1", + "chalk": "2.0.1", + "diff": "3.3.0", + "make-error": "1.3.0", + "minimist": "1.2.0", + "mkdirp": "0.5.1", + "source-map-support": "0.4.15", + "tsconfig": "6.0.0", + "v8flags": "2.1.1", + "yn": "2.0.0" + } + }, + "tsconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-6.0.0.tgz", + "integrity": "sha1-aw6DdgA9evGGT434+J3QBZ/80DI=", + "requires": { + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1" + } + }, + "tslib": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz", + "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=", + "dev": true + }, + "tslint": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.5.0.tgz", + "integrity": "sha1-EOjas+MGH6YelELozuOYKs8gpqo=", + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "colors": "1.1.2", + "commander": "2.11.0", + "diff": "3.3.0", + "glob": "7.1.2", + "minimatch": "3.0.4", + "resolve": "1.3.3", + "semver": "5.3.0", + "tslib": "1.7.1", + "tsutils": "2.6.0" + } + }, + "tsutils": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.6.0.tgz", + "integrity": "sha1-5emceaiszTl3zhjYP98dI1psLrs=", + "dev": true, + "requires": { + "tslib": "1.7.1" + } + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.15" + } + }, + "typescript": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.4.1.tgz", + "integrity": "sha1-w8yxbdqgsjFN4DHn5v7onlujRrw=" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "user-home": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=" + }, + "utils-merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" + }, + "v8flags": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", + "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "requires": { + "user-home": "1.1.1" + } + }, + "vary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz", + "integrity": "sha1-meSYFWaihhGN+yuBc1ffeZM3bRA=" + }, + "which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "requires": { + "isexe": "2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.0.0.tgz", + "integrity": "sha1-mN2wAFbIOQy3Ued4h4hJf5kQO2w=", + "requires": { + "safe-buffer": "5.0.1", + "ultron": "1.1.0" + }, + "dependencies": { + "ultron": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.0.tgz", + "integrity": "sha1-sHoualQagV/Go0zNRTO67DB8qGQ=" + } + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=" + } + } +} diff --git a/dew/package.json b/dew/package.json new file mode 100644 index 0000000..8e10554 --- /dev/null +++ b/dew/package.json @@ -0,0 +1,34 @@ +{ + "name": "naivechain", + "version": "1.0.0", + "description": "", + "scripts": { + "prestart": "npm run compile", + "start": "node src/main.js", + "compile": "tsc" + }, + "dependencies": { + "axios": "^0.16.2", + "body-parser": "^1.15.2", + "cross-env": "^5.0.1", + "crypto-js": "^3.1.6", + "elliptic": "^6.4.0", + "express": "~4.11.1", + "lodash": "^4.17.4", + "ts-node": "^3.2.0", + "typescript": "^2.4.1", + "ws": "^3.0.0" + }, + "engines": { + "node": ">=8.5.0" + }, + "devDependencies": { + "@types/body-parser": "^1.16.4", + "@types/crypto-js": "^3.1.33", + "@types/express": "^4.0.36", + "@types/lodash": "^4.14.85", + "@types/node": "^8.0.9", + "@types/ws": "^3.0.1", + "tslint": "^5.5.0" + } +} diff --git a/dew/src/blockchain.js b/dew/src/blockchain.js new file mode 100644 index 0000000..1b51687 --- /dev/null +++ b/dew/src/blockchain.js @@ -0,0 +1,261 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const CryptoJS = require("crypto-js"); +const _ = require("lodash"); +const p2p_1 = require("./p2p"); +const transaction_1 = require("./transaction"); +const transactionPool_1 = require("./transactionPool"); +const util_1 = require("./util"); +const wallet_1 = require("./wallet"); +class Block { + constructor(index, hash, previousHash, timestamp, data, difficulty, nonce) { + this.index = index; + this.previousHash = previousHash; + this.timestamp = timestamp; + this.data = data; + this.hash = hash; + this.difficulty = difficulty; + this.nonce = nonce; + } +} +exports.Block = Block; +const genesisTransaction = { + 'txIns': [{ 'signature': '', 'txOutId': '', 'txOutIndex': 0 }], + 'txOuts': [{ + 'address': '04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a', + 'amount': 50 + }], + 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3' +}; +const genesisBlock = new Block(0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1465154705, [genesisTransaction], 0, 0); +let blockchain = [genesisBlock]; +// the unspent txOut of genesis block is set to unspentTxOuts on startup +let unspentTxOuts = transaction_1.processTransactions(blockchain[0].data, [], 0); +const getBlockchain = () => blockchain; +exports.getBlockchain = getBlockchain; +const getUnspentTxOuts = () => _.cloneDeep(unspentTxOuts); +exports.getUnspentTxOuts = getUnspentTxOuts; +// and txPool should be only updated at the same time +const setUnspentTxOuts = (newUnspentTxOut) => { + console.log('replacing unspentTxouts with: %s', newUnspentTxOut); + unspentTxOuts = newUnspentTxOut; +}; +const getLatestBlock = () => blockchain[blockchain.length - 1]; +exports.getLatestBlock = getLatestBlock; +// in seconds +const BLOCK_GENERATION_INTERVAL = 10; +// in blocks +const DIFFICULTY_ADJUSTMENT_INTERVAL = 10; +const getDifficulty = (aBlockchain) => { + const latestBlock = aBlockchain[blockchain.length - 1]; + if (latestBlock.index % DIFFICULTY_ADJUSTMENT_INTERVAL === 0 && latestBlock.index !== 0) { + return getAdjustedDifficulty(latestBlock, aBlockchain); + } + else { + return latestBlock.difficulty; + } +}; +const getAdjustedDifficulty = (latestBlock, aBlockchain) => { + const prevAdjustmentBlock = aBlockchain[blockchain.length - DIFFICULTY_ADJUSTMENT_INTERVAL]; + const timeExpected = BLOCK_GENERATION_INTERVAL * DIFFICULTY_ADJUSTMENT_INTERVAL; + const timeTaken = latestBlock.timestamp - prevAdjustmentBlock.timestamp; + if (timeTaken < timeExpected / 2) { + return prevAdjustmentBlock.difficulty + 1; + } + else if (timeTaken > timeExpected * 2) { + return prevAdjustmentBlock.difficulty - 1; + } + else { + return prevAdjustmentBlock.difficulty; + } +}; +const getCurrentTimestamp = () => Math.round(new Date().getTime() / 1000); +const generateRawNextBlock = (blockData) => { + const previousBlock = getLatestBlock(); + const difficulty = getDifficulty(getBlockchain()); + const nextIndex = previousBlock.index + 1; + const nextTimestamp = getCurrentTimestamp(); + const newBlock = findBlock(nextIndex, previousBlock.hash, nextTimestamp, blockData, difficulty); + if (addBlockToChain(newBlock)) { + p2p_1.broadcastLatest(); + return newBlock; + } + else { + return null; + } +}; +exports.generateRawNextBlock = generateRawNextBlock; +// gets the unspent transaction outputs owned by the wallet +const getMyUnspentTransactionOutputs = () => { + return wallet_1.findUnspentTxOuts(wallet_1.getPublicFromWallet(), getUnspentTxOuts()); +}; +exports.getMyUnspentTransactionOutputs = getMyUnspentTransactionOutputs; +const generateNextBlock = () => { + const coinbaseTx = transaction_1.getCoinbaseTransaction(wallet_1.getPublicFromWallet(), getLatestBlock().index + 1); + const blockData = [coinbaseTx].concat(transactionPool_1.getTransactionPool()); + return generateRawNextBlock(blockData); +}; +exports.generateNextBlock = generateNextBlock; +const generatenextBlockWithTransaction = (receiverAddress, amount) => { + if (!transaction_1.isValidAddress(receiverAddress)) { + throw Error('invalid address'); + } + if (typeof amount !== 'number') { + throw Error('invalid amount'); + } + const coinbaseTx = transaction_1.getCoinbaseTransaction(wallet_1.getPublicFromWallet(), getLatestBlock().index + 1); + const tx = wallet_1.createTransaction(receiverAddress, amount, wallet_1.getPrivateFromWallet(), getUnspentTxOuts(), transactionPool_1.getTransactionPool()); + const blockData = [coinbaseTx, tx]; + return generateRawNextBlock(blockData); +}; +exports.generatenextBlockWithTransaction = generatenextBlockWithTransaction; +const findBlock = (index, previousHash, timestamp, data, difficulty) => { + let nonce = 0; + while (true) { + const hash = calculateHash(index, previousHash, timestamp, data, difficulty, nonce); + if (hashMatchesDifficulty(hash, difficulty)) { + return new Block(index, hash, previousHash, timestamp, data, difficulty, nonce); + } + nonce++; + } +}; +const getAccountBalance = () => { + return wallet_1.getBalance(wallet_1.getPublicFromWallet(), getUnspentTxOuts()); +}; +exports.getAccountBalance = getAccountBalance; +const sendTransaction = (address, amount) => { + const tx = wallet_1.createTransaction(address, amount, wallet_1.getPrivateFromWallet(), getUnspentTxOuts(), transactionPool_1.getTransactionPool()); + transactionPool_1.addToTransactionPool(tx, getUnspentTxOuts()); + p2p_1.broadCastTransactionPool(); + return tx; +}; +exports.sendTransaction = sendTransaction; +const calculateHashForBlock = (block) => calculateHash(block.index, block.previousHash, block.timestamp, block.data, block.difficulty, block.nonce); +const calculateHash = (index, previousHash, timestamp, data, difficulty, nonce) => CryptoJS.SHA256(index + previousHash + timestamp + data + difficulty + nonce).toString(); +const isValidBlockStructure = (block) => { + return typeof block.index === 'number' + && typeof block.hash === 'string' + && typeof block.previousHash === 'string' + && typeof block.timestamp === 'number' + && typeof block.data === 'object'; +}; +exports.isValidBlockStructure = isValidBlockStructure; +const isValidNewBlock = (newBlock, previousBlock) => { + if (!isValidBlockStructure(newBlock)) { + console.log('invalid block structure: %s', JSON.stringify(newBlock)); + return false; + } + if (previousBlock.index + 1 !== newBlock.index) { + console.log('invalid index'); + return false; + } + else if (previousBlock.hash !== newBlock.previousHash) { + console.log('invalid previoushash'); + return false; + } + else if (!isValidTimestamp(newBlock, previousBlock)) { + console.log('invalid timestamp'); + return false; + } + else if (!hasValidHash(newBlock)) { + return false; + } + return true; +}; +const getAccumulatedDifficulty = (aBlockchain) => { + return aBlockchain + .map((block) => block.difficulty) + .map((difficulty) => Math.pow(2, difficulty)) + .reduce((a, b) => a + b); +}; +const isValidTimestamp = (newBlock, previousBlock) => { + return (previousBlock.timestamp - 60 < newBlock.timestamp) + && newBlock.timestamp - 60 < getCurrentTimestamp(); +}; +const hasValidHash = (block) => { + if (!hashMatchesBlockContent(block)) { + console.log('invalid hash, got:' + block.hash); + return false; + } + if (!hashMatchesDifficulty(block.hash, block.difficulty)) { + console.log('block difficulty not satisfied. Expected: ' + block.difficulty + 'got: ' + block.hash); + } + return true; +}; +const hashMatchesBlockContent = (block) => { + const blockHash = calculateHashForBlock(block); + return blockHash === block.hash; +}; +const hashMatchesDifficulty = (hash, difficulty) => { + const hashInBinary = util_1.hexToBinary(hash); + const requiredPrefix = '0'.repeat(difficulty); + return hashInBinary.startsWith(requiredPrefix); +}; +/* + Checks if the given blockchain is valid. Return the unspent txOuts if the chain is valid + */ +const isValidChain = (blockchainToValidate) => { + console.log('isValidChain:'); + console.log(JSON.stringify(blockchainToValidate)); + const isValidGenesis = (block) => { + return JSON.stringify(block) === JSON.stringify(genesisBlock); + }; + if (!isValidGenesis(blockchainToValidate[0])) { + return null; + } + /* + Validate each block in the chain. The block is valid if the block structure is valid + and the transaction are valid + */ + let aUnspentTxOuts = []; + for (let i = 0; i < blockchainToValidate.length; i++) { + const currentBlock = blockchainToValidate[i]; + if (i !== 0 && !isValidNewBlock(blockchainToValidate[i], blockchainToValidate[i - 1])) { + return null; + } + aUnspentTxOuts = transaction_1.processTransactions(currentBlock.data, aUnspentTxOuts, currentBlock.index); + if (aUnspentTxOuts === null) { + console.log('invalid transactions in blockchain'); + return null; + } + } + return aUnspentTxOuts; +}; +const addBlockToChain = (newBlock) => { + if (isValidNewBlock(newBlock, getLatestBlock())) { + const retVal = transaction_1.processTransactions(newBlock.data, getUnspentTxOuts(), newBlock.index); + if (retVal === null) { + console.log('block is not valid in terms of transactions'); + return false; + } + else { + blockchain.push(newBlock); + setUnspentTxOuts(retVal); + transactionPool_1.updateTransactionPool(unspentTxOuts); + return true; + } + } + return false; +}; +exports.addBlockToChain = addBlockToChain; +const replaceChain = (newBlocks) => { + const aUnspentTxOuts = isValidChain(newBlocks); + const validChain = aUnspentTxOuts !== null; + if (validChain && + getAccumulatedDifficulty(newBlocks) > getAccumulatedDifficulty(getBlockchain())) { + console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); + blockchain = newBlocks; + setUnspentTxOuts(aUnspentTxOuts); + transactionPool_1.updateTransactionPool(unspentTxOuts); + p2p_1.broadcastLatest(); + } + else { + console.log('Received blockchain invalid'); + } +}; +exports.replaceChain = replaceChain; +const handleReceivedTransaction = (transaction) => { + transactionPool_1.addToTransactionPool(transaction, getUnspentTxOuts()); +}; +exports.handleReceivedTransaction = handleReceivedTransaction; +//# sourceMappingURL=blockchain.js.map \ No newline at end of file diff --git a/dew/src/blockchain.js.map b/dew/src/blockchain.js.map new file mode 100644 index 0000000..94bd3e2 --- /dev/null +++ b/dew/src/blockchain.js.map @@ -0,0 +1 @@ +{"version":3,"file":"blockchain.js","sourceRoot":"","sources":["blockchain.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dew/src/blockchain.ts b/dew/src/blockchain.ts new file mode 100644 index 0000000..85aedc3 --- /dev/null +++ b/dew/src/blockchain.ts @@ -0,0 +1,299 @@ +import * as CryptoJS from 'crypto-js'; +import * as _ from 'lodash'; +import {broadcastLatest, broadCastTransactionPool} from './p2p'; +import { + getCoinbaseTransaction, isValidAddress, processTransactions, Transaction, UnspentTxOut +} from './transaction'; +import {addToTransactionPool, getTransactionPool, updateTransactionPool} from './transactionPool'; +import {hexToBinary} from './util'; +import {createTransaction, findUnspentTxOuts, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; + +class Block { + + public index: number; + public hash: string; + public previousHash: string; + public timestamp: number; + public data: Transaction[]; + public difficulty: number; + public nonce: number; + + constructor(index: number, hash: string, previousHash: string, + timestamp: number, data: Transaction[], difficulty: number, nonce: number) { + this.index = index; + this.previousHash = previousHash; + this.timestamp = timestamp; + this.data = data; + this.hash = hash; + this.difficulty = difficulty; + this.nonce = nonce; + } +} + +const genesisTransaction = { + 'txIns': [{'signature': '', 'txOutId': '', 'txOutIndex': 0}], + 'txOuts': [{ + 'address': '04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a', + 'amount': 50 + }], + 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3' +}; + +const genesisBlock: Block = new Block( + 0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1465154705, [genesisTransaction], 0, 0 +); + +let blockchain: Block[] = [genesisBlock]; + +// the unspent txOut of genesis block is set to unspentTxOuts on startup +let unspentTxOuts: UnspentTxOut[] = processTransactions(blockchain[0].data, [], 0); + +const getBlockchain = (): Block[] => blockchain; + +const getUnspentTxOuts = (): UnspentTxOut[] => _.cloneDeep(unspentTxOuts); + +// and txPool should be only updated at the same time +const setUnspentTxOuts = (newUnspentTxOut: UnspentTxOut[]) => { + console.log('replacing unspentTxouts with: %s', newUnspentTxOut); + unspentTxOuts = newUnspentTxOut; +}; + +const getLatestBlock = (): Block => blockchain[blockchain.length - 1]; + +// in seconds +const BLOCK_GENERATION_INTERVAL: number = 10; + +// in blocks +const DIFFICULTY_ADJUSTMENT_INTERVAL: number = 10; + +const getDifficulty = (aBlockchain: Block[]): number => { + const latestBlock: Block = aBlockchain[blockchain.length - 1]; + if (latestBlock.index % DIFFICULTY_ADJUSTMENT_INTERVAL === 0 && latestBlock.index !== 0) { + return getAdjustedDifficulty(latestBlock, aBlockchain); + } else { + return latestBlock.difficulty; + } +}; + +const getAdjustedDifficulty = (latestBlock: Block, aBlockchain: Block[]) => { + const prevAdjustmentBlock: Block = aBlockchain[blockchain.length - DIFFICULTY_ADJUSTMENT_INTERVAL]; + const timeExpected: number = BLOCK_GENERATION_INTERVAL * DIFFICULTY_ADJUSTMENT_INTERVAL; + const timeTaken: number = latestBlock.timestamp - prevAdjustmentBlock.timestamp; + if (timeTaken < timeExpected / 2) { + return prevAdjustmentBlock.difficulty + 1; + } else if (timeTaken > timeExpected * 2) { + return prevAdjustmentBlock.difficulty - 1; + } else { + return prevAdjustmentBlock.difficulty; + } +}; + +const getCurrentTimestamp = (): number => Math.round(new Date().getTime() / 1000); + +const generateRawNextBlock = (blockData: Transaction[]) => { + const previousBlock: Block = getLatestBlock(); + const difficulty: number = getDifficulty(getBlockchain()); + const nextIndex: number = previousBlock.index + 1; + const nextTimestamp: number = getCurrentTimestamp(); + const newBlock: Block = findBlock(nextIndex, previousBlock.hash, nextTimestamp, blockData, difficulty); + if (addBlockToChain(newBlock)) { + broadcastLatest(); + return newBlock; + } else { + return null; + } + +}; + +// gets the unspent transaction outputs owned by the wallet +const getMyUnspentTransactionOutputs = () => { + return findUnspentTxOuts(getPublicFromWallet(), getUnspentTxOuts()); +}; + +const generateNextBlock = () => { + const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet(), getLatestBlock().index + 1); + const blockData: Transaction[] = [coinbaseTx].concat(getTransactionPool()); + return generateRawNextBlock(blockData); +}; + +const generatenextBlockWithTransaction = (receiverAddress: string, amount: number) => { + if (!isValidAddress(receiverAddress)) { + throw Error('invalid address'); + } + if (typeof amount !== 'number') { + throw Error('invalid amount'); + } + const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet(), getLatestBlock().index + 1); + const tx: Transaction = createTransaction(receiverAddress, amount, getPrivateFromWallet(), getUnspentTxOuts(), getTransactionPool()); + const blockData: Transaction[] = [coinbaseTx, tx]; + return generateRawNextBlock(blockData); +}; + +const findBlock = (index: number, previousHash: string, timestamp: number, data: Transaction[], difficulty: number): Block => { + let nonce = 0; + while (true) { + const hash: string = calculateHash(index, previousHash, timestamp, data, difficulty, nonce); + if (hashMatchesDifficulty(hash, difficulty)) { + return new Block(index, hash, previousHash, timestamp, data, difficulty, nonce); + } + nonce++; + } +}; + +const getAccountBalance = (): number => { + return getBalance(getPublicFromWallet(), getUnspentTxOuts()); +}; + +const sendTransaction = (address: string, amount: number): Transaction => { + const tx: Transaction = createTransaction(address, amount, getPrivateFromWallet(), getUnspentTxOuts(), getTransactionPool()); + addToTransactionPool(tx, getUnspentTxOuts()); + broadCastTransactionPool(); + return tx; +}; + +const calculateHashForBlock = (block: Block): string => + calculateHash(block.index, block.previousHash, block.timestamp, block.data, block.difficulty, block.nonce); + +const calculateHash = (index: number, previousHash: string, timestamp: number, data: Transaction[], + difficulty: number, nonce: number): string => + CryptoJS.SHA256(index + previousHash + timestamp + data + difficulty + nonce).toString(); + +const isValidBlockStructure = (block: Block): boolean => { + return typeof block.index === 'number' + && typeof block.hash === 'string' + && typeof block.previousHash === 'string' + && typeof block.timestamp === 'number' + && typeof block.data === 'object'; +}; + +const isValidNewBlock = (newBlock: Block, previousBlock: Block): boolean => { + if (!isValidBlockStructure(newBlock)) { + console.log('invalid block structure: %s', JSON.stringify(newBlock)); + return false; + } + if (previousBlock.index + 1 !== newBlock.index) { + console.log('invalid index'); + return false; + } else if (previousBlock.hash !== newBlock.previousHash) { + console.log('invalid previoushash'); + return false; + } else if (!isValidTimestamp(newBlock, previousBlock)) { + console.log('invalid timestamp'); + return false; + } else if (!hasValidHash(newBlock)) { + return false; + } + return true; +}; + +const getAccumulatedDifficulty = (aBlockchain: Block[]): number => { + return aBlockchain + .map((block) => block.difficulty) + .map((difficulty) => Math.pow(2, difficulty)) + .reduce((a, b) => a + b); +}; + +const isValidTimestamp = (newBlock: Block, previousBlock: Block): boolean => { + return ( previousBlock.timestamp - 60 < newBlock.timestamp ) + && newBlock.timestamp - 60 < getCurrentTimestamp(); +}; + +const hasValidHash = (block: Block): boolean => { + + if (!hashMatchesBlockContent(block)) { + console.log('invalid hash, got:' + block.hash); + return false; + } + + if (!hashMatchesDifficulty(block.hash, block.difficulty)) { + console.log('block difficulty not satisfied. Expected: ' + block.difficulty + 'got: ' + block.hash); + } + return true; +}; + +const hashMatchesBlockContent = (block: Block): boolean => { + const blockHash: string = calculateHashForBlock(block); + return blockHash === block.hash; +}; + +const hashMatchesDifficulty = (hash: string, difficulty: number): boolean => { + const hashInBinary: string = hexToBinary(hash); + const requiredPrefix: string = '0'.repeat(difficulty); + return hashInBinary.startsWith(requiredPrefix); +}; + +/* + Checks if the given blockchain is valid. Return the unspent txOuts if the chain is valid + */ +const isValidChain = (blockchainToValidate: Block[]): UnspentTxOut[] => { + console.log('isValidChain:'); + console.log(JSON.stringify(blockchainToValidate)); + const isValidGenesis = (block: Block): boolean => { + return JSON.stringify(block) === JSON.stringify(genesisBlock); + }; + + if (!isValidGenesis(blockchainToValidate[0])) { + return null; + } + /* + Validate each block in the chain. The block is valid if the block structure is valid + and the transaction are valid + */ + let aUnspentTxOuts: UnspentTxOut[] = []; + + for (let i = 0; i < blockchainToValidate.length; i++) { + const currentBlock: Block = blockchainToValidate[i]; + if (i !== 0 && !isValidNewBlock(blockchainToValidate[i], blockchainToValidate[i - 1])) { + return null; + } + + aUnspentTxOuts = processTransactions(currentBlock.data, aUnspentTxOuts, currentBlock.index); + if (aUnspentTxOuts === null) { + console.log('invalid transactions in blockchain'); + return null; + } + } + return aUnspentTxOuts; +}; + +const addBlockToChain = (newBlock: Block): boolean => { + if (isValidNewBlock(newBlock, getLatestBlock())) { + const retVal: UnspentTxOut[] = processTransactions(newBlock.data, getUnspentTxOuts(), newBlock.index); + if (retVal === null) { + console.log('block is not valid in terms of transactions'); + return false; + } else { + blockchain.push(newBlock); + setUnspentTxOuts(retVal); + updateTransactionPool(unspentTxOuts); + return true; + } + } + return false; +}; + +const replaceChain = (newBlocks: Block[]) => { + const aUnspentTxOuts = isValidChain(newBlocks); + const validChain: boolean = aUnspentTxOuts !== null; + if (validChain && + getAccumulatedDifficulty(newBlocks) > getAccumulatedDifficulty(getBlockchain())) { + console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); + blockchain = newBlocks; + setUnspentTxOuts(aUnspentTxOuts); + updateTransactionPool(unspentTxOuts); + broadcastLatest(); + } else { + console.log('Received blockchain invalid'); + } +}; + +const handleReceivedTransaction = (transaction: Transaction) => { + addToTransactionPool(transaction, getUnspentTxOuts()); +}; + +export { + Block, getBlockchain, getUnspentTxOuts, getLatestBlock, sendTransaction, + generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, + handleReceivedTransaction, getMyUnspentTransactionOutputs, + getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain +}; diff --git a/dew/src/main.js b/dew/src/main.js new file mode 100644 index 0000000..2bb1a93 --- /dev/null +++ b/dew/src/main.js @@ -0,0 +1,122 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const bodyParser = require("body-parser"); +const express = require("express"); +const _ = require("lodash"); +const blockchain_1 = require("./blockchain"); +const p2p_1 = require("./p2p"); +const transactionPool_1 = require("./transactionPool"); +const wallet_1 = require("./wallet"); +const httpPort = parseInt(process.env.HTTP_PORT) || 3001; +const p2pPort = parseInt(process.env.P2P_PORT) || 6001; +const initHttpServer = (myHttpPort) => { + const app = express(); + app.use(bodyParser.json()); + app.use((err, req, res, next) => { + if (err) { + res.status(400).send(err.message); + } + }); + app.get('/blocks', (req, res) => { + res.send(blockchain_1.getBlockchain()); + }); + app.get('/block/:hash', (req, res) => { + const block = _.find(blockchain_1.getBlockchain(), { 'hash': req.params.hash }); + res.send(block); + }); + app.get('/transaction/:id', (req, res) => { + const tx = _(blockchain_1.getBlockchain()) + .map((blocks) => blocks.data) + .flatten() + .find({ 'id': req.params.id }); + res.send(tx); + }); + app.get('/address/:address', (req, res) => { + const unspentTxOuts = _.filter(blockchain_1.getUnspentTxOuts(), (uTxO) => uTxO.address === req.params.address); + res.send({ 'unspentTxOuts': unspentTxOuts }); + }); + app.get('/unspentTransactionOutputs', (req, res) => { + res.send(blockchain_1.getUnspentTxOuts()); + }); + app.get('/myUnspentTransactionOutputs', (req, res) => { + res.send(blockchain_1.getMyUnspentTransactionOutputs()); + }); + app.post('/mineRawBlock', (req, res) => { + if (req.body.data == null) { + res.send('data parameter is missing'); + return; + } + const newBlock = blockchain_1.generateRawNextBlock(req.body.data); + if (newBlock === null) { + res.status(400).send('could not generate block'); + } + else { + res.send(newBlock); + } + }); + app.post('/mineBlock', (req, res) => { + const newBlock = blockchain_1.generateNextBlock(); + if (newBlock === null) { + res.status(400).send('could not generate block'); + } + else { + res.send(newBlock); + } + }); + app.get('/balance', (req, res) => { + const balance = blockchain_1.getAccountBalance(); + res.send({ 'balance': balance }); + }); + app.get('/address', (req, res) => { + const address = wallet_1.getPublicFromWallet(); + res.send({ 'address': address }); + }); + app.post('/mineTransaction', (req, res) => { + const address = req.body.address; + const amount = req.body.amount; + try { + const resp = blockchain_1.generatenextBlockWithTransaction(address, amount); + res.send(resp); + } + catch (e) { + console.log(e.message); + res.status(400).send(e.message); + } + }); + app.post('/sendTransaction', (req, res) => { + try { + const address = req.body.address; + const amount = req.body.amount; + if (address === undefined || amount === undefined) { + throw Error('invalid address or amount'); + } + const resp = blockchain_1.sendTransaction(address, amount); + res.send(resp); + } + catch (e) { + console.log(e.message); + res.status(400).send(e.message); + } + }); + app.get('/transactionPool', (req, res) => { + res.send(transactionPool_1.getTransactionPool()); + }); + app.get('/peers', (req, res) => { + res.send(p2p_1.getSockets().map((s) => s._socket.remoteAddress + ':' + s._socket.remotePort)); + }); + app.post('/addPeer', (req, res) => { + p2p_1.connectToPeers(req.body.peer); + res.send(); + }); + app.post('/stop', (req, res) => { + res.send({ 'msg': 'stopping server' }); + process.exit(); + }); + app.listen(myHttpPort, () => { + console.log('Listening http on port: ' + myHttpPort); + }); +}; +initHttpServer(httpPort); +p2p_1.initP2PServer(p2pPort); +wallet_1.initWallet(); +//# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/dew/src/main.js.map b/dew/src/main.js.map new file mode 100644 index 0000000..b723beb --- /dev/null +++ b/dew/src/main.js.map @@ -0,0 +1 @@ +{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/main.ts b/dew/src/main.ts similarity index 100% rename from src/main.ts rename to dew/src/main.ts diff --git a/dew/src/p2p.js b/dew/src/p2p.js new file mode 100644 index 0000000..db14e7e --- /dev/null +++ b/dew/src/p2p.js @@ -0,0 +1,175 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const WebSocket = require("ws"); +const blockchain_1 = require("./blockchain"); +const transactionPool_1 = require("./transactionPool"); +const sockets = []; +var MessageType; +(function (MessageType) { + MessageType[MessageType["QUERY_LATEST"] = 0] = "QUERY_LATEST"; + MessageType[MessageType["QUERY_ALL"] = 1] = "QUERY_ALL"; + MessageType[MessageType["RESPONSE_BLOCKCHAIN"] = 2] = "RESPONSE_BLOCKCHAIN"; + MessageType[MessageType["QUERY_TRANSACTION_POOL"] = 3] = "QUERY_TRANSACTION_POOL"; + MessageType[MessageType["RESPONSE_TRANSACTION_POOL"] = 4] = "RESPONSE_TRANSACTION_POOL"; +})(MessageType || (MessageType = {})); +class Message { +} +const initP2PServer = (p2pPort) => { + const server = new WebSocket.Server({ port: p2pPort }); + server.on('connection', (ws) => { + initConnection(ws); + }); + console.log('listening websocket p2p port on: ' + p2pPort); +}; +exports.initP2PServer = initP2PServer; +const getSockets = () => sockets; +exports.getSockets = getSockets; +const initConnection = (ws) => { + sockets.push(ws); + initMessageHandler(ws); + initErrorHandler(ws); + write(ws, queryChainLengthMsg()); + // query transactions pool only some time after chain query + setTimeout(() => { + broadcast(queryTransactionPoolMsg()); + }, 500); +}; +const JSONToObject = (data) => { + try { + return JSON.parse(data); + } + catch (e) { + console.log(e); + return null; + } +}; +const initMessageHandler = (ws) => { + ws.on('message', (data) => { + try { + const message = JSONToObject(data); + if (message === null) { + console.log('could not parse received JSON message: ' + data); + return; + } + console.log('Received message: %s', JSON.stringify(message)); + switch (message.type) { + case MessageType.QUERY_LATEST: + write(ws, responseLatestMsg()); + break; + case MessageType.QUERY_ALL: + write(ws, responseChainMsg()); + break; + case MessageType.RESPONSE_BLOCKCHAIN: + const receivedBlocks = JSONToObject(message.data); + if (receivedBlocks === null) { + console.log('invalid blocks received: %s', JSON.stringify(message.data)); + break; + } + handleBlockchainResponse(receivedBlocks); + break; + case MessageType.QUERY_TRANSACTION_POOL: + write(ws, responseTransactionPoolMsg()); + break; + case MessageType.RESPONSE_TRANSACTION_POOL: + const receivedTransactions = JSONToObject(message.data); + if (receivedTransactions === null) { + console.log('invalid transaction received: %s', JSON.stringify(message.data)); + break; + } + receivedTransactions.forEach((transaction) => { + try { + blockchain_1.handleReceivedTransaction(transaction); + // if no error is thrown, transaction was indeed added to the pool + // let's broadcast transaction pool + broadCastTransactionPool(); + } + catch (e) { + console.log(e.message); + } + }); + break; + } + } + catch (e) { + console.log(e); + } + }); +}; +const write = (ws, message) => ws.send(JSON.stringify(message)); +const broadcast = (message) => sockets.forEach((socket) => write(socket, message)); +const queryChainLengthMsg = () => ({ 'type': MessageType.QUERY_LATEST, 'data': null }); +const queryAllMsg = () => ({ 'type': MessageType.QUERY_ALL, 'data': null }); +const responseChainMsg = () => ({ + 'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify(blockchain_1.getBlockchain()) +}); +const responseLatestMsg = () => ({ + 'type': MessageType.RESPONSE_BLOCKCHAIN, + 'data': JSON.stringify([blockchain_1.getLatestBlock()]) +}); +const queryTransactionPoolMsg = () => ({ + 'type': MessageType.QUERY_TRANSACTION_POOL, + 'data': null +}); +const responseTransactionPoolMsg = () => ({ + 'type': MessageType.RESPONSE_TRANSACTION_POOL, + 'data': JSON.stringify(transactionPool_1.getTransactionPool()) +}); +const initErrorHandler = (ws) => { + const closeConnection = (myWs) => { + console.log('connection failed to peer: ' + myWs.url); + sockets.splice(sockets.indexOf(myWs), 1); + }; + ws.on('close', () => closeConnection(ws)); + ws.on('error', () => closeConnection(ws)); +}; +const handleBlockchainResponse = (receivedBlocks) => { + if (receivedBlocks.length === 0) { + console.log('received block chain size of 0'); + return; + } + const latestBlockReceived = receivedBlocks[receivedBlocks.length - 1]; + if (!blockchain_1.isValidBlockStructure(latestBlockReceived)) { + console.log('block structuture not valid'); + return; + } + const latestBlockHeld = blockchain_1.getLatestBlock(); + if (latestBlockReceived.index > latestBlockHeld.index) { + console.log('blockchain possibly behind. We got: ' + + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index); + if (latestBlockHeld.hash === latestBlockReceived.previousHash) { + if (blockchain_1.addBlockToChain(latestBlockReceived)) { + broadcast(responseLatestMsg()); + } + } + else if (receivedBlocks.length === 1) { + console.log('We have to query the chain from our peer'); + broadcast(queryAllMsg()); + } + else { + console.log('Received blockchain is longer than current blockchain'); + blockchain_1.replaceChain(receivedBlocks); + } + } + else { + console.log('received blockchain is not longer than received blockchain. Do nothing'); + } +}; +const broadcastLatest = () => { + broadcast(responseLatestMsg()); +}; +exports.broadcastLatest = broadcastLatest; +const connectToPeers = (newPeer) => { + const ws = new WebSocket(newPeer); + ws.on('open', () => { + initConnection(ws); + }); + ws.on('error', () => { + console.log('connection failed'); + }); +}; +exports.connectToPeers = connectToPeers; +const broadCastTransactionPool = () => { + broadcast(responseTransactionPoolMsg()); +}; +exports.broadCastTransactionPool = broadCastTransactionPool; +//# sourceMappingURL=p2p.js.map \ No newline at end of file diff --git a/dew/src/p2p.js.map b/dew/src/p2p.js.map new file mode 100644 index 0000000..c86c349 --- /dev/null +++ b/dew/src/p2p.js.map @@ -0,0 +1 @@ +{"version":3,"file":"p2p.js","sourceRoot":"","sources":["p2p.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts new file mode 100644 index 0000000..d15c8de --- /dev/null +++ b/dew/src/p2p.ts @@ -0,0 +1,191 @@ +import * as WebSocket from 'ws'; +import {Server} from 'ws'; +import { + addBlockToChain, Block, getBlockchain, getLatestBlock, handleReceivedTransaction, isValidBlockStructure, + replaceChain +} from './blockchain'; +import {Transaction} from './transaction'; +import {getTransactionPool} from './transactionPool'; + +const sockets: WebSocket[] = []; + +enum MessageType { + QUERY_LATEST = 0, + QUERY_ALL = 1, + RESPONSE_BLOCKCHAIN = 2, + QUERY_TRANSACTION_POOL = 3, + RESPONSE_TRANSACTION_POOL = 4 +} + +class Message { + public type: MessageType; + public data: any; +} + +const initP2PServer = (p2pPort: number) => { + const server: Server = new WebSocket.Server({port: p2pPort}); + server.on('connection', (ws: WebSocket) => { + initConnection(ws); + }); + console.log('listening websocket p2p port on: ' + p2pPort); +}; + +const getSockets = () => sockets; + +const initConnection = (ws: WebSocket) => { + sockets.push(ws); + initMessageHandler(ws); + initErrorHandler(ws); + write(ws, queryChainLengthMsg()); + + // query transactions pool only some time after chain query + setTimeout(() => { + broadcast(queryTransactionPoolMsg()); + }, 500); +}; + +const JSONToObject = (data: string): T => { + try { + return JSON.parse(data); + } catch (e) { + console.log(e); + return null; + } +}; + +const initMessageHandler = (ws: WebSocket) => { + ws.on('message', (data: string) => { + + try { + const message: Message = JSONToObject(data); + if (message === null) { + console.log('could not parse received JSON message: ' + data); + return; + } + console.log('Received message: %s', JSON.stringify(message)); + switch (message.type) { + case MessageType.QUERY_LATEST: + write(ws, responseLatestMsg()); + break; + case MessageType.QUERY_ALL: + write(ws, responseChainMsg()); + break; + case MessageType.RESPONSE_BLOCKCHAIN: + const receivedBlocks: Block[] = JSONToObject(message.data); + if (receivedBlocks === null) { + console.log('invalid blocks received: %s', JSON.stringify(message.data)); + break; + } + handleBlockchainResponse(receivedBlocks); + break; + case MessageType.QUERY_TRANSACTION_POOL: + write(ws, responseTransactionPoolMsg()); + break; + case MessageType.RESPONSE_TRANSACTION_POOL: + const receivedTransactions: Transaction[] = JSONToObject(message.data); + if (receivedTransactions === null) { + console.log('invalid transaction received: %s', JSON.stringify(message.data)); + break; + } + receivedTransactions.forEach((transaction: Transaction) => { + try { + handleReceivedTransaction(transaction); + // if no error is thrown, transaction was indeed added to the pool + // let's broadcast transaction pool + broadCastTransactionPool(); + } catch (e) { + console.log(e.message); + } + }); + break; + } + } catch (e) { + console.log(e); + } + }); +}; + +const write = (ws: WebSocket, message: Message): void => ws.send(JSON.stringify(message)); +const broadcast = (message: Message): void => sockets.forEach((socket) => write(socket, message)); + +const queryChainLengthMsg = (): Message => ({'type': MessageType.QUERY_LATEST, 'data': null}); + +const queryAllMsg = (): Message => ({'type': MessageType.QUERY_ALL, 'data': null}); + +const responseChainMsg = (): Message => ({ + 'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify(getBlockchain()) +}); + +const responseLatestMsg = (): Message => ({ + 'type': MessageType.RESPONSE_BLOCKCHAIN, + 'data': JSON.stringify([getLatestBlock()]) +}); + +const queryTransactionPoolMsg = (): Message => ({ + 'type': MessageType.QUERY_TRANSACTION_POOL, + 'data': null +}); + +const responseTransactionPoolMsg = (): Message => ({ + 'type': MessageType.RESPONSE_TRANSACTION_POOL, + 'data': JSON.stringify(getTransactionPool()) +}); + +const initErrorHandler = (ws: WebSocket) => { + const closeConnection = (myWs: WebSocket) => { + console.log('connection failed to peer: ' + myWs.url); + sockets.splice(sockets.indexOf(myWs), 1); + }; + ws.on('close', () => closeConnection(ws)); + ws.on('error', () => closeConnection(ws)); +}; + +const handleBlockchainResponse = (receivedBlocks: Block[]) => { + if (receivedBlocks.length === 0) { + console.log('received block chain size of 0'); + return; + } + const latestBlockReceived: Block = receivedBlocks[receivedBlocks.length - 1]; + if (!isValidBlockStructure(latestBlockReceived)) { + console.log('block structuture not valid'); + return; + } + const latestBlockHeld: Block = getLatestBlock(); + if (latestBlockReceived.index > latestBlockHeld.index) { + console.log('blockchain possibly behind. We got: ' + + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index); + if (latestBlockHeld.hash === latestBlockReceived.previousHash) { + if (addBlockToChain(latestBlockReceived)) { + broadcast(responseLatestMsg()); + } + } else if (receivedBlocks.length === 1) { + console.log('We have to query the chain from our peer'); + broadcast(queryAllMsg()); + } else { + console.log('Received blockchain is longer than current blockchain'); + replaceChain(receivedBlocks); + } + } else { + console.log('received blockchain is not longer than received blockchain. Do nothing'); + } +}; + +const broadcastLatest = (): void => { + broadcast(responseLatestMsg()); +}; + +const connectToPeers = (newPeer: string): void => { + const ws: WebSocket = new WebSocket(newPeer); + ws.on('open', () => { + initConnection(ws); + }); + ws.on('error', () => { + console.log('connection failed'); + }); +}; + +const broadCastTransactionPool = () => { + broadcast(responseTransactionPoolMsg()); +}; + +export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets}; diff --git a/dew/src/transaction.js b/dew/src/transaction.js new file mode 100644 index 0000000..bb1a059 --- /dev/null +++ b/dew/src/transaction.js @@ -0,0 +1,298 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const CryptoJS = require("crypto-js"); +const ecdsa = require("elliptic"); +const _ = require("lodash"); +const ec = new ecdsa.ec('secp256k1'); +const COINBASE_AMOUNT = 50; +class UnspentTxOut { + constructor(txOutId, txOutIndex, address, amount) { + this.txOutId = txOutId; + this.txOutIndex = txOutIndex; + this.address = address; + this.amount = amount; + } +} +exports.UnspentTxOut = UnspentTxOut; +class TxIn { +} +exports.TxIn = TxIn; +class TxOut { + constructor(address, amount) { + this.address = address; + this.amount = amount; + } +} +exports.TxOut = TxOut; +class Transaction { +} +exports.Transaction = Transaction; +const getTransactionId = (transaction) => { + const txInContent = transaction.txIns + .map((txIn) => txIn.txOutId + txIn.txOutIndex) + .reduce((a, b) => a + b, ''); + const txOutContent = transaction.txOuts + .map((txOut) => txOut.address + txOut.amount) + .reduce((a, b) => a + b, ''); + return CryptoJS.SHA256(txInContent + txOutContent).toString(); +}; +exports.getTransactionId = getTransactionId; +const validateTransaction = (transaction, aUnspentTxOuts) => { + if (!isValidTransactionStructure(transaction)) { + return false; + } + if (getTransactionId(transaction) !== transaction.id) { + console.log('invalid tx id: ' + transaction.id); + return false; + } + const hasValidTxIns = transaction.txIns + .map((txIn) => validateTxIn(txIn, transaction, aUnspentTxOuts)) + .reduce((a, b) => a && b, true); + if (!hasValidTxIns) { + console.log('some of the txIns are invalid in tx: ' + transaction.id); + return false; + } + const totalTxInValues = transaction.txIns + .map((txIn) => getTxInAmount(txIn, aUnspentTxOuts)) + .reduce((a, b) => (a + b), 0); + const totalTxOutValues = transaction.txOuts + .map((txOut) => txOut.amount) + .reduce((a, b) => (a + b), 0); + if (totalTxOutValues !== totalTxInValues) { + console.log('totalTxOutValues !== totalTxInValues in tx: ' + transaction.id); + return false; + } + return true; +}; +exports.validateTransaction = validateTransaction; +const validateBlockTransactions = (aTransactions, aUnspentTxOuts, blockIndex) => { + const coinbaseTx = aTransactions[0]; + if (!validateCoinbaseTx(coinbaseTx, blockIndex)) { + console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); + return false; + } + // check for duplicate txIns. Each txIn can be included only once + const txIns = _(aTransactions) + .map((tx) => tx.txIns) + .flatten() + .value(); + if (hasDuplicates(txIns)) { + return false; + } + // all but coinbase transactions + const normalTransactions = aTransactions.slice(1); + return normalTransactions.map((tx) => validateTransaction(tx, aUnspentTxOuts)) + .reduce((a, b) => (a && b), true); +}; +const hasDuplicates = (txIns) => { + const groups = _.countBy(txIns, (txIn) => txIn.txOutId + txIn.txOutIndex); + return _(groups) + .map((value, key) => { + if (value > 1) { + console.log('duplicate txIn: ' + key); + return true; + } + else { + return false; + } + }) + .includes(true); +}; +exports.hasDuplicates = hasDuplicates; +const validateCoinbaseTx = (transaction, blockIndex) => { + if (transaction == null) { + console.log('the first transaction in the block must be coinbase transaction'); + return false; + } + if (getTransactionId(transaction) !== transaction.id) { + console.log('invalid coinbase tx id: ' + transaction.id); + return false; + } + if (transaction.txIns.length !== 1) { + console.log('one txIn must be specified in the coinbase transaction'); + return; + } + if (transaction.txIns[0].txOutIndex !== blockIndex) { + console.log('the txIn signature in coinbase tx must be the block height'); + return false; + } + if (transaction.txOuts.length !== 1) { + console.log('invalid number of txOuts in coinbase transaction'); + return false; + } + if (transaction.txOuts[0].amount !== COINBASE_AMOUNT) { + console.log('invalid coinbase amount in coinbase transaction'); + return false; + } + return true; +}; +const validateTxIn = (txIn, transaction, aUnspentTxOuts) => { + const referencedUTxOut = aUnspentTxOuts.find((uTxO) => uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex); + if (referencedUTxOut == null) { + console.log('referenced txOut not found: ' + JSON.stringify(txIn)); + return false; + } + const address = referencedUTxOut.address; + const key = ec.keyFromPublic(address, 'hex'); + const validSignature = key.verify(transaction.id, txIn.signature); + if (!validSignature) { + console.log('invalid txIn signature: %s txId: %s address: %s', txIn.signature, transaction.id, referencedUTxOut.address); + return false; + } + return true; +}; +const getTxInAmount = (txIn, aUnspentTxOuts) => { + return findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts).amount; +}; +const findUnspentTxOut = (transactionId, index, aUnspentTxOuts) => { + return aUnspentTxOuts.find((uTxO) => uTxO.txOutId === transactionId && uTxO.txOutIndex === index); +}; +const getCoinbaseTransaction = (address, blockIndex) => { + const t = new Transaction(); + const txIn = new TxIn(); + txIn.signature = ''; + txIn.txOutId = ''; + txIn.txOutIndex = blockIndex; + t.txIns = [txIn]; + t.txOuts = [new TxOut(address, COINBASE_AMOUNT)]; + t.id = getTransactionId(t); + return t; +}; +exports.getCoinbaseTransaction = getCoinbaseTransaction; +const signTxIn = (transaction, txInIndex, privateKey, aUnspentTxOuts) => { + const txIn = transaction.txIns[txInIndex]; + const dataToSign = transaction.id; + const referencedUnspentTxOut = findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts); + if (referencedUnspentTxOut == null) { + console.log('could not find referenced txOut'); + throw Error(); + } + const referencedAddress = referencedUnspentTxOut.address; + if (getPublicKey(privateKey) !== referencedAddress) { + console.log('trying to sign an input with private' + + ' key that does not match the address that is referenced in txIn'); + throw Error(); + } + const key = ec.keyFromPrivate(privateKey, 'hex'); + const signature = toHexString(key.sign(dataToSign).toDER()); + return signature; +}; +exports.signTxIn = signTxIn; +const updateUnspentTxOuts = (aTransactions, aUnspentTxOuts) => { + const newUnspentTxOuts = aTransactions + .map((t) => { + return t.txOuts.map((txOut, index) => new UnspentTxOut(t.id, index, txOut.address, txOut.amount)); + }) + .reduce((a, b) => a.concat(b), []); + const consumedTxOuts = aTransactions + .map((t) => t.txIns) + .reduce((a, b) => a.concat(b), []) + .map((txIn) => new UnspentTxOut(txIn.txOutId, txIn.txOutIndex, '', 0)); + const resultingUnspentTxOuts = aUnspentTxOuts + .filter(((uTxO) => !findUnspentTxOut(uTxO.txOutId, uTxO.txOutIndex, consumedTxOuts))) + .concat(newUnspentTxOuts); + return resultingUnspentTxOuts; +}; +const processTransactions = (aTransactions, aUnspentTxOuts, blockIndex) => { + if (!validateBlockTransactions(aTransactions, aUnspentTxOuts, blockIndex)) { + console.log('invalid block transactions'); + return null; + } + return updateUnspentTxOuts(aTransactions, aUnspentTxOuts); +}; +exports.processTransactions = processTransactions; +const toHexString = (byteArray) => { + return Array.from(byteArray, (byte) => { + return ('0' + (byte & 0xFF).toString(16)).slice(-2); + }).join(''); +}; +const getPublicKey = (aPrivateKey) => { + return ec.keyFromPrivate(aPrivateKey, 'hex').getPublic().encode('hex'); +}; +exports.getPublicKey = getPublicKey; +const isValidTxInStructure = (txIn) => { + if (txIn == null) { + console.log('txIn is null'); + return false; + } + else if (typeof txIn.signature !== 'string') { + console.log('invalid signature type in txIn'); + return false; + } + else if (typeof txIn.txOutId !== 'string') { + console.log('invalid txOutId type in txIn'); + return false; + } + else if (typeof txIn.txOutIndex !== 'number') { + console.log('invalid txOutIndex type in txIn'); + return false; + } + else { + return true; + } +}; +const isValidTxOutStructure = (txOut) => { + if (txOut == null) { + console.log('txOut is null'); + return false; + } + else if (typeof txOut.address !== 'string') { + console.log('invalid address type in txOut'); + return false; + } + else if (!isValidAddress(txOut.address)) { + console.log('invalid TxOut address'); + return false; + } + else if (typeof txOut.amount !== 'number') { + console.log('invalid amount type in txOut'); + return false; + } + else { + return true; + } +}; +const isValidTransactionStructure = (transaction) => { + if (typeof transaction.id !== 'string') { + console.log('transactionId missing'); + return false; + } + if (!(transaction.txIns instanceof Array)) { + console.log('invalid txIns type in transaction'); + return false; + } + if (!transaction.txIns + .map(isValidTxInStructure) + .reduce((a, b) => (a && b), true)) { + return false; + } + if (!(transaction.txOuts instanceof Array)) { + console.log('invalid txIns type in transaction'); + return false; + } + if (!transaction.txOuts + .map(isValidTxOutStructure) + .reduce((a, b) => (a && b), true)) { + return false; + } + return true; +}; +// valid address is a valid ecdsa public key in the 04 + X-coordinate + Y-coordinate format +const isValidAddress = (address) => { + if (address.length !== 130) { + console.log(address); + console.log('invalid public key length'); + return false; + } + else if (address.match('^[a-fA-F0-9]+$') === null) { + console.log('public key must contain only hex characters'); + return false; + } + else if (!address.startsWith('04')) { + console.log('public key must start with 04'); + return false; + } + return true; +}; +exports.isValidAddress = isValidAddress; +//# sourceMappingURL=transaction.js.map \ No newline at end of file diff --git a/dew/src/transaction.js.map b/dew/src/transaction.js.map new file mode 100644 index 0000000..fd33576 --- /dev/null +++ b/dew/src/transaction.js.map @@ -0,0 +1 @@ +{"version":3,"file":"transaction.js","sourceRoot":"","sources":["transaction.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dew/src/transaction.ts b/dew/src/transaction.ts new file mode 100644 index 0000000..200a2a8 --- /dev/null +++ b/dew/src/transaction.ts @@ -0,0 +1,429 @@ +import * as CryptoJS from 'crypto-js'; +import * as ecdsa from 'elliptic'; +import * as _ from 'lodash'; + +const ec = new ecdsa.ec('secp256k1'); + +const COINBASE_AMOUNT: number = 50; + +/* +class UnspentTxOut { + public readonly txOutId: string; + public readonly txOutIndex: number; + public readonly address: string; + public readonly amount: number; + + constructor(txOutId: string, txOutIndex: number, address: string, amount: number) { + this.txOutId = txOutId; + this.txOutIndex = txOutIndex; + this.address = address; + this.amount = amount; + } +} +*/ +class Account { + public readonly address: string; + public balance: number; + public txIndex: number; + public transactions: Transaction[]; + + constructor(address: string) { + this.address = address; + this.balance = 0; + this.txIndex = 0; + this.transactions = []; + } +} + + + +/* +class TxIn { + public txOutId: string; + public txOutIndex: number; + public signature: string; +} + +class TxOut { + public address: string; + public amount: number; + + constructor(address: string, amount: number) { + this.address = address; + this.amount = amount; + } +} +class Transaction { + + public id: string; + + public txIns: TxIn[]; + public txOuts: TxOut[]; +} +*/ +class Transaction { + + public id: string; + + public sender: Account; //sender address + public receiver: Account; //receiver address. + public prev-balance: number; + public amount: number; + public after-balance: number; + public timestamp: number; + public txIndex: number; + public signature: string; + + constructor(sender: Account, receiver: Account, amount: number) { + this.sender = sender; + this.receiver = receiver + thia.prev-balance = 0; + this.amount = amount; + this.after-balance = 0; + this.timestampt = getCurrentTimestamp(); + this.txIndex = ++sender.txIndex; + } +} + +/* +const getTransactionId = (transaction: Transaction): string => { + const txInContent: string = transaction.txIns + .map((txIn: TxIn) => txIn.txOutId + txIn.txOutIndex) + .reduce((a, b) => a + b, ''); + + const txOutContent: string = transaction.txOuts + .map((txOut: TxOut) => txOut.address + txOut.amount) + .reduce((a, b) => a + b, ''); + + return CryptoJS.SHA256(txInContent + txOutContent).toString(); +}; +*/ +const getTransactionId = (transaction: Transaction): string => { + return CryptoJS.SHA256(transaction.sender.address + transaction.receiver.address + transaction.amount + transaction.timestampt + transaction.txIndex).toString(); +}; + +/* +const validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean => { + + if (!isValidTransactionStructure(transaction)) { + return false; + } + + if (getTransactionId(transaction) !== transaction.id) { + console.log('invalid tx id: ' + transaction.id); + return false; + } + const hasValidTxIns: boolean = transaction.txIns + .map((txIn) => validateTxIn(txIn, transaction, aUnspentTxOuts)) + .reduce((a, b) => a && b, true); + + if (!hasValidTxIns) { + console.log('some of the txIns are invalid in tx: ' + transaction.id); + return false; + } + + const totalTxInValues: number = transaction.txIns + .map((txIn) => getTxInAmount(txIn, aUnspentTxOuts)) + .reduce((a, b) => (a + b), 0); + + const totalTxOutValues: number = transaction.txOuts + .map((txOut) => txOut.amount) + .reduce((a, b) => (a + b), 0); + + if (totalTxOutValues !== totalTxInValues) { + console.log('totalTxOutValues !== totalTxInValues in tx: ' + transaction.id); + return false; + } + + return true; +}; +*/ +const validateTransaction = (transaction: Transaction, AccountDB: Account[]): boolean => { + + if (!isValidTransactionStructure(transaction)) { + return false; + } + + if (getTransactionId(transaction) !== transaction.id) { + console.log('invalid tx id: ' + transaction.id); + return false; + } + if (!exsitAccount(transaction.sender)) { + console.log('The sender does not have an account. tx: ' + transaction.id); + return false; + } + if (!exsitAccount(transaction.receiver)) { + console.log('The receiver does not have an account. tx: ' + transaction.id); + return false; + } + if (transaction.amount > transaction.sender.balance) { + console.log('The sender does not have enough coins. tx: ' + transaction.id); + return false; + } + const AccountActivePeriod = 10000; //n days. + if (transaction.timestampt < Date() - AccountActivePeriod){ + console.log('The transaction is too old. tx: ' + transaction.id); + return false; + } + if (transaction.txIndex IN transaction.sender.transactions.map(txIndex)){ + console.log('The transaction is duplicated. tx: ' + transaction.id); + return false; + } + + return true; +}; + + +const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number): boolean => { + const coinbaseTx = aTransactions[0]; + if (!validateCoinbaseTx(coinbaseTx, blockIndex)) { + console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); + return false; + } + + // currently, duplicate transactions are allowed as long as the + + + const txIns: TxIn[] = _(aTransactions) + .map((tx) => tx.txIns) + .flatten() + .value(); + + if (hasDuplicates(txIns)) { + return false; + } + + // all but coinbase transactions + const normalTransactions: Transaction[] = aTransactions.slice(1); + return normalTransactions.map((tx) => validateTransaction(tx, aUnspentTxOuts)) + .reduce((a, b) => (a && b), true); + +}; + +const hasDuplicates = (txIns: TxIn[]): boolean => { + const groups = _.countBy(txIns, (txIn: TxIn) => txIn.txOutId + txIn.txOutIndex); + return _(groups) + .map((value, key) => { + if (value > 1) { + console.log('duplicate txIn: ' + key); + return true; + } else { + return false; + } + }) + .includes(true); +}; + +const validateCoinbaseTx = (transaction: Transaction, blockIndex: number): boolean => { + if (transaction == null) { + console.log('the first transaction in the block must be coinbase transaction'); + return false; + } + if (getTransactionId(transaction) !== transaction.id) { + console.log('invalid coinbase tx id: ' + transaction.id); + return false; + } + if (transaction.txIns.length !== 1) { + console.log('one txIn must be specified in the coinbase transaction'); + return; + } + if (transaction.txIns[0].txOutIndex !== blockIndex) { + console.log('the txIn signature in coinbase tx must be the block height'); + return false; + } + if (transaction.txOuts.length !== 1) { + console.log('invalid number of txOuts in coinbase transaction'); + return false; + } + if (transaction.txOuts[0].amount !== COINBASE_AMOUNT) { + console.log('invalid coinbase amount in coinbase transaction'); + return false; + } + return true; +}; + +const validateTxIn = (txIn: TxIn, transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean => { + const referencedUTxOut: UnspentTxOut = + aUnspentTxOuts.find((uTxO) => uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex); + if (referencedUTxOut == null) { + console.log('referenced txOut not found: ' + JSON.stringify(txIn)); + return false; + } + const address = referencedUTxOut.address; + + const key = ec.keyFromPublic(address, 'hex'); + const validSignature: boolean = key.verify(transaction.id, txIn.signature); + if (!validSignature) { + console.log('invalid txIn signature: %s txId: %s address: %s', txIn.signature, transaction.id, referencedUTxOut.address); + return false; + } + return true; +}; + +const getTxInAmount = (txIn: TxIn, aUnspentTxOuts: UnspentTxOut[]): number => { + return findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts).amount; +}; + +const findUnspentTxOut = (transactionId: string, index: number, aUnspentTxOuts: UnspentTxOut[]): UnspentTxOut => { + return aUnspentTxOuts.find((uTxO) => uTxO.txOutId === transactionId && uTxO.txOutIndex === index); +}; + +const getCoinbaseTransaction = (address: string, blockIndex: number): Transaction => { + const t = new Transaction(); + const txIn: TxIn = new TxIn(); + txIn.signature = ''; + txIn.txOutId = ''; + txIn.txOutIndex = blockIndex; + + t.txIns = [txIn]; + t.txOuts = [new TxOut(address, COINBASE_AMOUNT)]; + t.id = getTransactionId(t); + return t; +}; + +const signTxIn = (transaction: Transaction, txInIndex: number, + privateKey: string, aUnspentTxOuts: UnspentTxOut[]): string => { + const txIn: TxIn = transaction.txIns[txInIndex]; + + const dataToSign = transaction.id; + const referencedUnspentTxOut: UnspentTxOut = findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts); + if (referencedUnspentTxOut == null) { + console.log('could not find referenced txOut'); + throw Error(); + } + const referencedAddress = referencedUnspentTxOut.address; + + if (getPublicKey(privateKey) !== referencedAddress) { + console.log('trying to sign an input with private' + + ' key that does not match the address that is referenced in txIn'); + throw Error(); + } + const key = ec.keyFromPrivate(privateKey, 'hex'); + const signature: string = toHexString(key.sign(dataToSign).toDER()); + + return signature; +}; + +const updateUnspentTxOuts = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[]): UnspentTxOut[] => { + const newUnspentTxOuts: UnspentTxOut[] = aTransactions + .map((t) => { + return t.txOuts.map((txOut, index) => new UnspentTxOut(t.id, index, txOut.address, txOut.amount)); + }) + .reduce((a, b) => a.concat(b), []); + + const consumedTxOuts: UnspentTxOut[] = aTransactions + .map((t) => t.txIns) + .reduce((a, b) => a.concat(b), []) + .map((txIn) => new UnspentTxOut(txIn.txOutId, txIn.txOutIndex, '', 0)); + + const resultingUnspentTxOuts = aUnspentTxOuts + .filter(((uTxO) => !findUnspentTxOut(uTxO.txOutId, uTxO.txOutIndex, consumedTxOuts))) + .concat(newUnspentTxOuts); + + return resultingUnspentTxOuts; +}; + +const processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number) => { + + if (!validateBlockTransactions(aTransactions, aUnspentTxOuts, blockIndex)) { + console.log('invalid block transactions'); + return null; + } + return updateUnspentTxOuts(aTransactions, aUnspentTxOuts); +}; + +const toHexString = (byteArray): string => { + return Array.from(byteArray, (byte: any) => { + return ('0' + (byte & 0xFF).toString(16)).slice(-2); + }).join(''); +}; + +const getPublicKey = (aPrivateKey: string): string => { + return ec.keyFromPrivate(aPrivateKey, 'hex').getPublic().encode('hex'); +}; + +const isValidTxInStructure = (txIn: TxIn): boolean => { + if (txIn == null) { + console.log('txIn is null'); + return false; + } else if (typeof txIn.signature !== 'string') { + console.log('invalid signature type in txIn'); + return false; + } else if (typeof txIn.txOutId !== 'string') { + console.log('invalid txOutId type in txIn'); + return false; + } else if (typeof txIn.txOutIndex !== 'number') { + console.log('invalid txOutIndex type in txIn'); + return false; + } else { + return true; + } +}; + +const isValidTxOutStructure = (txOut: TxOut): boolean => { + if (txOut == null) { + console.log('txOut is null'); + return false; + } else if (typeof txOut.address !== 'string') { + console.log('invalid address type in txOut'); + return false; + } else if (!isValidAddress(txOut.address)) { + console.log('invalid TxOut address'); + return false; + } else if (typeof txOut.amount !== 'number') { + console.log('invalid amount type in txOut'); + return false; + } else { + return true; + } +}; + +const isValidTransactionStructure = (transaction: Transaction) => { + if (typeof transaction.id !== 'string') { + console.log('transactionId missing'); + return false; + } + if (!(transaction.txIns instanceof Array)) { + console.log('invalid txIns type in transaction'); + return false; + } + if (!transaction.txIns + .map(isValidTxInStructure) + .reduce((a, b) => (a && b), true)) { + return false; + } + + if (!(transaction.txOuts instanceof Array)) { + console.log('invalid txIns type in transaction'); + return false; + } + + if (!transaction.txOuts + .map(isValidTxOutStructure) + .reduce((a, b) => (a && b), true)) { + return false; + } + return true; +}; + +// valid address is a valid ecdsa public key in the 04 + X-coordinate + Y-coordinate format +const isValidAddress = (address: string): boolean => { + if (address.length !== 130) { + console.log(address); + console.log('invalid public key length'); + return false; + } else if (address.match('^[a-fA-F0-9]+$') === null) { + console.log('public key must contain only hex characters'); + return false; + } else if (!address.startsWith('04')) { + console.log('public key must start with 04'); + return false; + } + return true; +}; + +export { + processTransactions, signTxIn, getTransactionId, isValidAddress, validateTransaction, + UnspentTxOut, TxIn, TxOut, getCoinbaseTransaction, getPublicKey, hasDuplicates, + Transaction +}; diff --git a/dew/src/transactionPool.js b/dew/src/transactionPool.js new file mode 100644 index 0000000..c7a53d3 --- /dev/null +++ b/dew/src/transactionPool.js @@ -0,0 +1,64 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const _ = require("lodash"); +const transaction_1 = require("./transaction"); +let transactionPool = []; +const getTransactionPool = () => { + return _.cloneDeep(transactionPool); +}; +exports.getTransactionPool = getTransactionPool; +const addToTransactionPool = (tx, unspentTxOuts) => { + if (!transaction_1.validateTransaction(tx, unspentTxOuts)) { + throw Error('Trying to add invalid tx to pool'); + } + if (!isValidTxForPool(tx, transactionPool)) { + throw Error('Trying to add invalid tx to pool'); + } + console.log('adding to txPool: %s', JSON.stringify(tx)); + transactionPool.push(tx); +}; +exports.addToTransactionPool = addToTransactionPool; +const hasTxIn = (txIn, unspentTxOuts) => { + const foundTxIn = unspentTxOuts.find((uTxO) => { + return uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex; + }); + return foundTxIn !== undefined; +}; +const updateTransactionPool = (unspentTxOuts) => { + const invalidTxs = []; + for (const tx of transactionPool) { + for (const txIn of tx.txIns) { + if (!hasTxIn(txIn, unspentTxOuts)) { + invalidTxs.push(tx); + break; + } + } + } + if (invalidTxs.length > 0) { + console.log('removing the following transactions from txPool: %s', JSON.stringify(invalidTxs)); + transactionPool = _.without(transactionPool, ...invalidTxs); + } +}; +exports.updateTransactionPool = updateTransactionPool; +const getTxPoolIns = (aTransactionPool) => { + return _(aTransactionPool) + .map((tx) => tx.txIns) + .flatten() + .value(); +}; +const isValidTxForPool = (tx, aTtransactionPool) => { + const txPoolIns = getTxPoolIns(aTtransactionPool); + const containsTxIn = (txIns, txIn) => { + return _.find(txPoolIns, ((txPoolIn) => { + return txIn.txOutIndex === txPoolIn.txOutIndex && txIn.txOutId === txPoolIn.txOutId; + })); + }; + for (const txIn of tx.txIns) { + if (containsTxIn(txPoolIns, txIn)) { + console.log('txIn already found in the txPool'); + return false; + } + } + return true; +}; +//# sourceMappingURL=transactionPool.js.map \ No newline at end of file diff --git a/dew/src/transactionPool.js.map b/dew/src/transactionPool.js.map new file mode 100644 index 0000000..50a6e7c --- /dev/null +++ b/dew/src/transactionPool.js.map @@ -0,0 +1 @@ +{"version":3,"file":"transactionPool.js","sourceRoot":"","sources":["transactionPool.ts"],"names":[],"mappings":";;AAAA,4BAA4B;AAC5B,+CAAmF;AAEnF,IAAI,eAAe,GAAkB,EAAE,CAAC;AAExC,MAAM,kBAAkB,GAAG;IACvB,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;AACxC,CAAC,CAAC;AA+D4B,gDAAkB;AA7DhD,MAAM,oBAAoB,GAAG,CAAC,EAAe,EAAE,aAA6B;IAExE,EAAE,CAAC,CAAC,CAAC,iCAAmB,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;QAC1C,MAAM,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACpD,CAAC;IAED,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,sBAAsB,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;IACxD,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC,CAAC;AAkDM,oDAAoB;AAhD5B,MAAM,OAAO,GAAG,CAAC,IAAU,EAAE,aAA6B;IACtD,MAAM,SAAS,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,IAAkB;QACpD,MAAM,CAAC,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU,CAAC;IAChF,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC;AACnC,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,aAA6B;IACxD,MAAM,UAAU,GAAG,EAAE,CAAC;IACtB,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,eAAe,CAAC,CAAC,CAAC;QAC/B,GAAG,CAAC,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;YAC1B,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;gBAChC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACpB,KAAK,CAAC;YACV,CAAC;QACL,CAAC;IACL,CAAC;IACD,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,qDAAqD,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;QAC/F,eAAe,GAAG,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,UAAU,CAAC,CAAC;IAChE,CAAC;AACL,CAAC,CAAC;AA2BgD,sDAAqB;AAzBvE,MAAM,YAAY,GAAG,CAAC,gBAA+B;IACjD,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC;SACrB,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC;SACrB,OAAO,EAAE;SACT,KAAK,EAAE,CAAC;AACjB,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,EAAe,EAAE,iBAAgC;IACvE,MAAM,SAAS,GAAW,YAAY,CAAC,iBAAiB,CAAC,CAAC;IAE1D,MAAM,YAAY,GAAG,CAAC,KAAa,EAAE,IAAU;QAC3C,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,QAAQ;YAC/B,MAAM,CAAC,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,OAAO,CAAC;QACxF,CAAC,CAAC,CAAC,CAAC;IACR,CAAC,CAAC;IAEF,GAAG,CAAC,CAAC,MAAM,IAAI,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1B,EAAE,CAAC,CAAC,YAAY,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;YAChD,MAAM,CAAC,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC,CAAC"} \ No newline at end of file diff --git a/dew/src/transactionPool.ts b/dew/src/transactionPool.ts new file mode 100644 index 0000000..5296b72 --- /dev/null +++ b/dew/src/transactionPool.ts @@ -0,0 +1,71 @@ +import * as _ from 'lodash'; +import {Transaction, TxIn, UnspentTxOut, validateTransaction} from './transaction'; + +let transactionPool: Transaction[] = []; + +const getTransactionPool = () => { + return _.cloneDeep(transactionPool); +}; + +const addToTransactionPool = (tx: Transaction, unspentTxOuts: UnspentTxOut[]) => { + + if (!validateTransaction(tx, unspentTxOuts)) { + throw Error('Trying to add invalid tx to pool'); + } + + if (!isValidTxForPool(tx, transactionPool)) { + throw Error('Trying to add invalid tx to pool'); + } + console.log('adding to txPool: %s', JSON.stringify(tx)); + transactionPool.push(tx); +}; + +const hasTxIn = (txIn: TxIn, unspentTxOuts: UnspentTxOut[]): boolean => { + const foundTxIn = unspentTxOuts.find((uTxO: UnspentTxOut) => { + return uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex; + }); + return foundTxIn !== undefined; +}; + +const updateTransactionPool = (unspentTxOuts: UnspentTxOut[]) => { + const invalidTxs = []; + for (const tx of transactionPool) { + for (const txIn of tx.txIns) { + if (!hasTxIn(txIn, unspentTxOuts)) { + invalidTxs.push(tx); + break; + } + } + } + if (invalidTxs.length > 0) { + console.log('removing the following transactions from txPool: %s', JSON.stringify(invalidTxs)); + transactionPool = _.without(transactionPool, ...invalidTxs); + } +}; + +const getTxPoolIns = (aTransactionPool: Transaction[]): TxIn[] => { + return _(aTransactionPool) + .map((tx) => tx.txIns) + .flatten() + .value(); +}; + +const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): boolean => { + const txPoolIns: TxIn[] = getTxPoolIns(aTtransactionPool); + + const containsTxIn = (txIns: TxIn[], txIn: TxIn) => { + return _.find(txPoolIns, ((txPoolIn) => { + return txIn.txOutIndex === txPoolIn.txOutIndex && txIn.txOutId === txPoolIn.txOutId; + })); + }; + + for (const txIn of tx.txIns) { + if (containsTxIn(txPoolIns, txIn)) { + console.log('txIn already found in the txPool'); + return false; + } + } + return true; +}; + +export {addToTransactionPool, getTransactionPool, updateTransactionPool}; diff --git a/dew/src/util.js b/dew/src/util.js new file mode 100644 index 0000000..9ccd8be --- /dev/null +++ b/dew/src/util.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const hexToBinary = (s) => { + let ret = ''; + const lookupTable = { + '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', + '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', + 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', + 'e': '1110', 'f': '1111' + }; + for (let i = 0; i < s.length; i = i + 1) { + if (lookupTable[s[i]]) { + ret += lookupTable[s[i]]; + } + else { + return null; + } + } + return ret; +}; +exports.hexToBinary = hexToBinary; +//# sourceMappingURL=util.js.map \ No newline at end of file diff --git a/dew/src/util.js.map b/dew/src/util.js.map new file mode 100644 index 0000000..c8d4f6c --- /dev/null +++ b/dew/src/util.js.map @@ -0,0 +1 @@ +{"version":3,"file":"util.js","sourceRoot":"","sources":["util.ts"],"names":[],"mappings":";;AAAA,MAAM,WAAW,GAAG,CAAC,CAAS;IAC1B,IAAI,GAAG,GAAW,EAAE,CAAC;IACrB,MAAM,WAAW,GAAG;QAChB,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAC/D,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAC/D,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAClD,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;KAC3B,CAAC;IACF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpB,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,MAAM,CAAC,GAAG,CAAC;AACf,CAAC,CAAC;AAEM,kCAAW"} \ No newline at end of file diff --git a/dew/src/util.ts b/dew/src/util.ts new file mode 100644 index 0000000..32d8f47 --- /dev/null +++ b/dew/src/util.ts @@ -0,0 +1,19 @@ +const hexToBinary = (s: string): string => { + let ret: string = ''; + const lookupTable = { + '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', + '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', + 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', + 'e': '1110', 'f': '1111' + }; + for (let i: number = 0; i < s.length; i = i + 1) { + if (lookupTable[s[i]]) { + ret += lookupTable[s[i]]; + } else { + return null; + } + } + return ret; +}; + +export {hexToBinary}; diff --git a/dew/src/wallet.js b/dew/src/wallet.js new file mode 100644 index 0000000..0501bf4 --- /dev/null +++ b/dew/src/wallet.js @@ -0,0 +1,120 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const elliptic_1 = require("elliptic"); +const fs_1 = require("fs"); +const _ = require("lodash"); +const transaction_1 = require("./transaction"); +const EC = new elliptic_1.ec('secp256k1'); +const privateKeyLocation = process.env.PRIVATE_KEY || 'node/wallet/private_key'; +const getPrivateFromWallet = () => { + const buffer = fs_1.readFileSync(privateKeyLocation, 'utf8'); + return buffer.toString(); +}; +exports.getPrivateFromWallet = getPrivateFromWallet; +const getPublicFromWallet = () => { + const privateKey = getPrivateFromWallet(); + const key = EC.keyFromPrivate(privateKey, 'hex'); + return key.getPublic().encode('hex'); +}; +exports.getPublicFromWallet = getPublicFromWallet; +const generatePrivateKey = () => { + const keyPair = EC.genKeyPair(); + const privateKey = keyPair.getPrivate(); + return privateKey.toString(16); +}; +exports.generatePrivateKey = generatePrivateKey; +const initWallet = () => { + // let's not override existing private keys + if (fs_1.existsSync(privateKeyLocation)) { + return; + } + const newPrivateKey = generatePrivateKey(); + fs_1.writeFileSync(privateKeyLocation, newPrivateKey); + console.log('new wallet with private key created to : %s', privateKeyLocation); +}; +exports.initWallet = initWallet; +const deleteWallet = () => { + if (fs_1.existsSync(privateKeyLocation)) { + fs_1.unlinkSync(privateKeyLocation); + } +}; +exports.deleteWallet = deleteWallet; +const getBalance = (address, unspentTxOuts) => { + return _(findUnspentTxOuts(address, unspentTxOuts)) + .map((uTxO) => uTxO.amount) + .sum(); +}; +exports.getBalance = getBalance; +const findUnspentTxOuts = (ownerAddress, unspentTxOuts) => { + return _.filter(unspentTxOuts, (uTxO) => uTxO.address === ownerAddress); +}; +exports.findUnspentTxOuts = findUnspentTxOuts; +const findTxOutsForAmount = (amount, myUnspentTxOuts) => { + let currentAmount = 0; + const includedUnspentTxOuts = []; + for (const myUnspentTxOut of myUnspentTxOuts) { + includedUnspentTxOuts.push(myUnspentTxOut); + currentAmount = currentAmount + myUnspentTxOut.amount; + if (currentAmount >= amount) { + const leftOverAmount = currentAmount - amount; + return { includedUnspentTxOuts, leftOverAmount }; + } + } + const eMsg = 'Cannot create transaction from the available unspent transaction outputs.' + + ' Required amount:' + amount + '. Available unspentTxOuts:' + JSON.stringify(myUnspentTxOuts); + throw Error(eMsg); +}; +const createTxOuts = (receiverAddress, myAddress, amount, leftOverAmount) => { + const txOut1 = new transaction_1.TxOut(receiverAddress, amount); + if (leftOverAmount === 0) { + return [txOut1]; + } + else { + const leftOverTx = new transaction_1.TxOut(myAddress, leftOverAmount); + return [txOut1, leftOverTx]; + } +}; +const filterTxPoolTxs = (unspentTxOuts, transactionPool) => { + const txIns = _(transactionPool) + .map((tx) => tx.txIns) + .flatten() + .value(); + const removable = []; + for (const unspentTxOut of unspentTxOuts) { + const txIn = _.find(txIns, (aTxIn) => { + return aTxIn.txOutIndex === unspentTxOut.txOutIndex && aTxIn.txOutId === unspentTxOut.txOutId; + }); + if (txIn === undefined) { + } + else { + removable.push(unspentTxOut); + } + } + return _.without(unspentTxOuts, ...removable); +}; +const createTransaction = (receiverAddress, amount, privateKey, unspentTxOuts, txPool) => { + console.log('txPool: %s', JSON.stringify(txPool)); + const myAddress = transaction_1.getPublicKey(privateKey); + const myUnspentTxOutsA = unspentTxOuts.filter((uTxO) => uTxO.address === myAddress); + const myUnspentTxOuts = filterTxPoolTxs(myUnspentTxOutsA, txPool); + // filter from unspentOutputs such inputs that are referenced in pool + const { includedUnspentTxOuts, leftOverAmount } = findTxOutsForAmount(amount, myUnspentTxOuts); + const toUnsignedTxIn = (unspentTxOut) => { + const txIn = new transaction_1.TxIn(); + txIn.txOutId = unspentTxOut.txOutId; + txIn.txOutIndex = unspentTxOut.txOutIndex; + return txIn; + }; + const unsignedTxIns = includedUnspentTxOuts.map(toUnsignedTxIn); + const tx = new transaction_1.Transaction(); + tx.txIns = unsignedTxIns; + tx.txOuts = createTxOuts(receiverAddress, myAddress, amount, leftOverAmount); + tx.id = transaction_1.getTransactionId(tx); + tx.txIns = tx.txIns.map((txIn, index) => { + txIn.signature = transaction_1.signTxIn(tx, index, privateKey, unspentTxOuts); + return txIn; + }); + return tx; +}; +exports.createTransaction = createTransaction; +//# sourceMappingURL=wallet.js.map \ No newline at end of file diff --git a/dew/src/wallet.js.map b/dew/src/wallet.js.map new file mode 100644 index 0000000..5895928 --- /dev/null +++ b/dew/src/wallet.js.map @@ -0,0 +1 @@ +{"version":3,"file":"wallet.js","sourceRoot":"","sources":["wallet.ts"],"names":[],"mappings":";;AAAA,uCAA4B;AAC5B,2BAAuE;AACvE,4BAA4B;AAC5B,+CAA+G;AAE/G,MAAM,EAAE,GAAG,IAAI,aAAE,CAAC,WAAW,CAAC,CAAC;AAC/B,MAAM,kBAAkB,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,yBAAyB,CAAC;AAEhF,MAAM,oBAAoB,GAAG;IACzB,MAAM,MAAM,GAAG,iBAAY,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;IACxD,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC,CAAC;AA4HE,oDAAoB;AA1HxB,MAAM,mBAAmB,GAAG;IACxB,MAAM,UAAU,GAAG,oBAAoB,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,EAAE,CAAC,cAAc,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACjD,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC,CAAC;AAqHyB,kDAAmB;AAnH9C,MAAM,kBAAkB,GAAG;IACvB,MAAM,OAAO,GAAG,EAAE,CAAC,UAAU,EAAE,CAAC;IAChC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IACxC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACnC,CAAC,CAAC;AAgHoC,gDAAkB;AA9GxD,MAAM,UAAU,GAAG;IACf,2CAA2C;IAC3C,EAAE,CAAC,CAAC,eAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC;IACX,CAAC;IACD,MAAM,aAAa,GAAG,kBAAkB,EAAE,CAAC;IAE3C,kBAAa,CAAC,kBAAkB,EAAE,aAAa,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,6CAA6C,EAAE,kBAAkB,CAAC,CAAC;AACnF,CAAC,CAAC;AAqGwD,gCAAU;AAnGpE,MAAM,YAAY,GAAG;IACjB,EAAE,CAAC,CAAC,eAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC;QACjC,eAAU,CAAC,kBAAkB,CAAC,CAAC;IACnC,CAAC;AACL,CAAC,CAAC;AA+FoE,oCAAY;AA7FlF,MAAM,UAAU,GAAG,CAAC,OAAe,EAAE,aAA6B;IAC9D,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;SAC9C,GAAG,CAAC,CAAC,IAAkB,KAAK,IAAI,CAAC,MAAM,CAAC;SACxC,GAAG,EAAE,CAAC;AACf,CAAC,CAAC;AAyFwB,gCAAU;AAvFpC,MAAM,iBAAiB,GAAG,CAAC,YAAoB,EAAE,aAA6B;IAC1E,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,IAAkB,KAAK,IAAI,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC;AAC1F,CAAC,CAAC;AAqFkF,8CAAiB;AAnFrG,MAAM,mBAAmB,GAAG,CAAC,MAAc,EAAE,eAA+B;IACxE,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,MAAM,qBAAqB,GAAG,EAAE,CAAC;IACjC,GAAG,CAAC,CAAC,MAAM,cAAc,IAAI,eAAe,CAAC,CAAC,CAAC;QAC3C,qBAAqB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3C,aAAa,GAAG,aAAa,GAAG,cAAc,CAAC,MAAM,CAAC;QACtD,EAAE,CAAC,CAAC,aAAa,IAAI,MAAM,CAAC,CAAC,CAAC;YAC1B,MAAM,cAAc,GAAG,aAAa,GAAG,MAAM,CAAC;YAC9C,MAAM,CAAC,EAAC,qBAAqB,EAAE,cAAc,EAAC,CAAC;QACnD,CAAC;IACL,CAAC;IAED,MAAM,IAAI,GAAG,2EAA2E;QACpF,mBAAmB,GAAG,MAAM,GAAG,4BAA4B,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,CAAC;IAClG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,eAAuB,EAAE,SAAiB,EAAE,MAAM,EAAE,cAAsB;IAC5F,MAAM,MAAM,GAAU,IAAI,mBAAK,CAAC,eAAe,EAAE,MAAM,CAAC,CAAC;IACzD,EAAE,CAAC,CAAC,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC;QACvB,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,MAAM,UAAU,GAAG,IAAI,mBAAK,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;QACxD,MAAM,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAChC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,aAA6B,EAAE,eAA8B;IAClF,MAAM,KAAK,GAAW,CAAC,CAAC,eAAe,CAAC;SACnC,GAAG,CAAC,CAAC,EAAe,KAAK,EAAE,CAAC,KAAK,CAAC;SAClC,OAAO,EAAE;SACT,KAAK,EAAE,CAAC;IACb,MAAM,SAAS,GAAmB,EAAE,CAAC;IACrC,GAAG,CAAC,CAAC,MAAM,YAAY,IAAI,aAAa,CAAC,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAW;YACnC,MAAM,CAAC,KAAK,CAAC,UAAU,KAAK,YAAY,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,KAAK,YAAY,CAAC,OAAO,CAAC;QAClG,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC;QAEzB,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACjC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,SAAS,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,eAAuB,EAAE,MAAc,EAAE,UAAkB,EAC3D,aAA6B,EAAE,MAAqB;IAE3E,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAClD,MAAM,SAAS,GAAW,0BAAY,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,IAAkB,KAAK,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC;IAElG,MAAM,eAAe,GAAG,eAAe,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAElE,qEAAqE;IACrE,MAAM,EAAC,qBAAqB,EAAE,cAAc,EAAC,GAAG,mBAAmB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAE7F,MAAM,cAAc,GAAG,CAAC,YAA0B;QAC9C,MAAM,IAAI,GAAS,IAAI,kBAAI,EAAE,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC;QACpC,IAAI,CAAC,UAAU,GAAG,YAAY,CAAC,UAAU,CAAC;QAC1C,MAAM,CAAC,IAAI,CAAC;IAChB,CAAC,CAAC;IAEF,MAAM,aAAa,GAAW,qBAAqB,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAExE,MAAM,EAAE,GAAgB,IAAI,yBAAW,EAAE,CAAC;IAC1C,EAAE,CAAC,KAAK,GAAG,aAAa,CAAC;IACzB,EAAE,CAAC,MAAM,GAAG,YAAY,CAAC,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC;IAC7E,EAAE,CAAC,EAAE,GAAG,8BAAgB,CAAC,EAAE,CAAC,CAAC;IAE7B,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAU,EAAE,KAAa;QAC9C,IAAI,CAAC,SAAS,GAAG,sBAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;QAChE,MAAM,CAAC,IAAI,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC;AACd,CAAC,CAAC;AAEM,8CAAiB"} \ No newline at end of file diff --git a/dew/src/wallet.ts b/dew/src/wallet.ts new file mode 100644 index 0000000..315a939 --- /dev/null +++ b/dew/src/wallet.ts @@ -0,0 +1,136 @@ +import {ec} from 'elliptic'; +import {existsSync, readFileSync, unlinkSync, writeFileSync} from 'fs'; +import * as _ from 'lodash'; +import {getPublicKey, getTransactionId, signTxIn, Transaction, TxIn, TxOut, UnspentTxOut} from './transaction'; + +const EC = new ec('secp256k1'); +const privateKeyLocation = process.env.PRIVATE_KEY || 'node/wallet/private_key'; + +const getPrivateFromWallet = (): string => { + const buffer = readFileSync(privateKeyLocation, 'utf8'); + return buffer.toString(); +}; + +const getPublicFromWallet = (): string => { + const privateKey = getPrivateFromWallet(); + const key = EC.keyFromPrivate(privateKey, 'hex'); + return key.getPublic().encode('hex'); +}; + +const generatePrivateKey = (): string => { + const keyPair = EC.genKeyPair(); + const privateKey = keyPair.getPrivate(); + return privateKey.toString(16); +}; + +const initWallet = () => { + // let's not override existing private keys + if (existsSync(privateKeyLocation)) { + return; + } + const newPrivateKey = generatePrivateKey(); + + writeFileSync(privateKeyLocation, newPrivateKey); + console.log('new wallet with private key created to : %s', privateKeyLocation); +}; + +const deleteWallet = () => { + if (existsSync(privateKeyLocation)) { + unlinkSync(privateKeyLocation); + } +}; + +const getBalance = (address: string, unspentTxOuts: UnspentTxOut[]): number => { + return _(findUnspentTxOuts(address, unspentTxOuts)) + .map((uTxO: UnspentTxOut) => uTxO.amount) + .sum(); +}; + +const findUnspentTxOuts = (ownerAddress: string, unspentTxOuts: UnspentTxOut[]) => { + return _.filter(unspentTxOuts, (uTxO: UnspentTxOut) => uTxO.address === ownerAddress); +}; + +const findTxOutsForAmount = (amount: number, myUnspentTxOuts: UnspentTxOut[]) => { + let currentAmount = 0; + const includedUnspentTxOuts = []; + for (const myUnspentTxOut of myUnspentTxOuts) { + includedUnspentTxOuts.push(myUnspentTxOut); + currentAmount = currentAmount + myUnspentTxOut.amount; + if (currentAmount >= amount) { + const leftOverAmount = currentAmount - amount; + return {includedUnspentTxOuts, leftOverAmount}; + } + } + + const eMsg = 'Cannot create transaction from the available unspent transaction outputs.' + + ' Required amount:' + amount + '. Available unspentTxOuts:' + JSON.stringify(myUnspentTxOuts); + throw Error(eMsg); +}; + +const createTxOuts = (receiverAddress: string, myAddress: string, amount, leftOverAmount: number) => { + const txOut1: TxOut = new TxOut(receiverAddress, amount); + if (leftOverAmount === 0) { + return [txOut1]; + } else { + const leftOverTx = new TxOut(myAddress, leftOverAmount); + return [txOut1, leftOverTx]; + } +}; + +const filterTxPoolTxs = (unspentTxOuts: UnspentTxOut[], transactionPool: Transaction[]): UnspentTxOut[] => { + const txIns: TxIn[] = _(transactionPool) + .map((tx: Transaction) => tx.txIns) + .flatten() + .value(); + const removable: UnspentTxOut[] = []; + for (const unspentTxOut of unspentTxOuts) { + const txIn = _.find(txIns, (aTxIn: TxIn) => { + return aTxIn.txOutIndex === unspentTxOut.txOutIndex && aTxIn.txOutId === unspentTxOut.txOutId; + }); + + if (txIn === undefined) { + + } else { + removable.push(unspentTxOut); + } + } + + return _.without(unspentTxOuts, ...removable); +}; + +const createTransaction = (receiverAddress: string, amount: number, privateKey: string, + unspentTxOuts: UnspentTxOut[], txPool: Transaction[]): Transaction => { + + console.log('txPool: %s', JSON.stringify(txPool)); + const myAddress: string = getPublicKey(privateKey); + const myUnspentTxOutsA = unspentTxOuts.filter((uTxO: UnspentTxOut) => uTxO.address === myAddress); + + const myUnspentTxOuts = filterTxPoolTxs(myUnspentTxOutsA, txPool); + + // filter from unspentOutputs such inputs that are referenced in pool + const {includedUnspentTxOuts, leftOverAmount} = findTxOutsForAmount(amount, myUnspentTxOuts); + + const toUnsignedTxIn = (unspentTxOut: UnspentTxOut) => { + const txIn: TxIn = new TxIn(); + txIn.txOutId = unspentTxOut.txOutId; + txIn.txOutIndex = unspentTxOut.txOutIndex; + return txIn; + }; + + const unsignedTxIns: TxIn[] = includedUnspentTxOuts.map(toUnsignedTxIn); + + const tx: Transaction = new Transaction(); + tx.txIns = unsignedTxIns; + tx.txOuts = createTxOuts(receiverAddress, myAddress, amount, leftOverAmount); + tx.id = getTransactionId(tx); + + tx.txIns = tx.txIns.map((txIn: TxIn, index: number) => { + txIn.signature = signTxIn(tx, index, privateKey, unspentTxOuts); + return txIn; + }); + + return tx; +}; + +export {createTransaction, getPublicFromWallet, + getPrivateFromWallet, getBalance, generatePrivateKey, initWallet, deleteWallet, findUnspentTxOuts}; diff --git a/dew/tsconfig.json b/dew/tsconfig.json new file mode 100644 index 0000000..73e4689 --- /dev/null +++ b/dew/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES2015", + "sourceMap": true + }, + "include": [ + "src/main.ts", + "src/block.ts", + "src/p2p.ts", + "src/util.ts", + "src/transaction.ts", + "src/wallet.ts", + "src/transactionPool.ts" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/dew/tslint.json b/dew/tslint.json new file mode 100644 index 0000000..3434404 --- /dev/null +++ b/dew/tslint.json @@ -0,0 +1,26 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "no-bitwise": false, + "eofline": false, + "no-empty": false, + "max-line-length": [140], + "max-classes-per-file": [4], + "prefer-for-of": false, + "radix": false, + "trailing-comma": false, + "object-literal-sort-keys": false, + "object-literal-key-quotes": false, + "no-console": false, + "quotemark": [ + true, + "single", + "avoid-escape" + ] + }, + "rulesDirectory": [] +} From f2f4dcca5f0f961bdfba1d097c24933928174630 Mon Sep 17 00:00:00 2001 From: ywang Date: Thu, 2 Aug 2018 16:42:30 -0400 Subject: [PATCH 04/36] transaction to account --- dew/src/transaction.ts | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/dew/src/transaction.ts b/dew/src/transaction.ts index 200a2a8..2f8783f 100644 --- a/dew/src/transaction.ts +++ b/dew/src/transaction.ts @@ -6,6 +6,9 @@ const ec = new ecdsa.ec('secp256k1'); const COINBASE_AMOUNT: number = 50; +const ACCOUNT_ACTIVE_PERIOD: number = 10000; //n days.//should check + + /* class UnspentTxOut { public readonly txOutId: string; @@ -77,9 +80,9 @@ class Transaction { constructor(sender: Account, receiver: Account, amount: number) { this.sender = sender; this.receiver = receiver - thia.prev-balance = 0; + thia.prev-balance = 0;//This item is only used when put in an account this.amount = amount; - this.after-balance = 0; + this.after-balance = 0;//This item is only used when it is put in an account. this.timestampt = getCurrentTimestamp(); this.txIndex = ++sender.txIndex; } @@ -160,12 +163,11 @@ const validateTransaction = (transaction: Transaction, AccountDB: Account[]): bo console.log('The sender does not have enough coins. tx: ' + transaction.id); return false; } - const AccountActivePeriod = 10000; //n days. - if (transaction.timestampt < Date() - AccountActivePeriod){ + if (transaction.timestampt < (Date() - ACCOUNT_ACTIVE_PERIOD)){//should check console.log('The transaction is too old. tx: ' + transaction.id); return false; } - if (transaction.txIndex IN transaction.sender.transactions.map(txIndex)){ + if (transaction.txIndex IN transaction.sender.transactions.map((tx: Transaction) => tx.txIndex)){//should check console.log('The transaction is duplicated. tx: ' + transaction.id); return false; } @@ -174,6 +176,31 @@ const validateTransaction = (transaction: Transaction, AccountDB: Account[]): bo }; + +/* +const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number): boolean => { + const coinbaseTx = aTransactions[0]; + if (!validateCoinbaseTx(coinbaseTx, blockIndex)) { + console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); + return false; + } + + const txIns: TxIn[] = _(aTransactions) + .map((tx) => tx.txIns) + .flatten() + .value(); + + if (hasDuplicates(txIns)) { + return false; + } + + // all but coinbase transactions + const normalTransactions: Transaction[] = aTransactions.slice(1); + return normalTransactions.map((tx) => validateTransaction(tx, aUnspentTxOuts)) + .reduce((a, b) => (a && b), true); + +}; +*/ const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number): boolean => { const coinbaseTx = aTransactions[0]; if (!validateCoinbaseTx(coinbaseTx, blockIndex)) { @@ -181,7 +208,6 @@ const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: return false; } - // currently, duplicate transactions are allowed as long as the const txIns: TxIn[] = _(aTransactions) @@ -200,6 +226,7 @@ const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: }; + const hasDuplicates = (txIns: TxIn[]): boolean => { const groups = _.countBy(txIns, (txIn: TxIn) => txIn.txOutId + txIn.txOutIndex); return _(groups) From a2876c65440a1bc4a7a7ed1f0aa481233819d475 Mon Sep 17 00:00:00 2001 From: ywang Date: Thu, 2 Aug 2018 17:03:58 -0400 Subject: [PATCH 05/36] ignore node/ --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e5d4fe4..8514289 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ npm-debug.log .idea src/*.js src/*.map +node + From f4eb05bc9bd7d9f3ff043836a3e233cda1f0caf2 Mon Sep 17 00:00:00 2001 From: ywang Date: Thu, 2 Aug 2018 17:12:45 -0400 Subject: [PATCH 06/36] updated to fit the cloud-dew folers --- .gitignore | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index e5d4fe4..47f510f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,13 @@ -node_modules -npm-debug.log -.idea -src/*.js -src/*.map +cloud/node_modules +cloud/npm-debug.log +cloud/.idea +cloud/src/*.js +cloud/src/*.map +cloud/node +dew/node_modules +dew/npm-debug.log +dew/.idea +dew/src/*.js +dew/src/*.map +dew/node + From 6cc596f90962432da504744b0c210e3bc7b48250 Mon Sep 17 00:00:00 2001 From: ywang Date: Thu, 2 Aug 2018 17:17:32 -0400 Subject: [PATCH 07/36] Revert "ignore node/" This reverts commit a2876c65440a1bc4a7a7ed1f0aa481233819d475. --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 8514289..e5d4fe4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,3 @@ npm-debug.log .idea src/*.js src/*.map -node - From 09d333de19fa2c3c226f13bf5813b9893389e611 Mon Sep 17 00:00:00 2001 From: ywang Date: Thu, 2 Aug 2018 17:22:13 -0400 Subject: [PATCH 08/36] conform with master --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 47f510f..577f66e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,9 @@ cloud/npm-debug.log cloud/.idea cloud/src/*.js cloud/src/*.map -cloud/node dew/node_modules dew/npm-debug.log dew/.idea dew/src/*.js dew/src/*.map -dew/node From 610438d143d8fcd8c4670ef90e4e1dd1713fa83a Mon Sep 17 00:00:00 2001 From: ywang Date: Sat, 4 Aug 2018 15:50:32 -0400 Subject: [PATCH 09/36] finished draft change for transaction.ts --- dew/src/transaction.ts | 281 ++++++++++++++++++++++++++++++++++------- 1 file changed, 237 insertions(+), 44 deletions(-) diff --git a/dew/src/transaction.ts b/dew/src/transaction.ts index 2f8783f..b9c4bfb 100644 --- a/dew/src/transaction.ts +++ b/dew/src/transaction.ts @@ -2,12 +2,15 @@ import * as CryptoJS from 'crypto-js'; import * as ecdsa from 'elliptic'; import * as _ from 'lodash'; -const ec = new ecdsa.ec('secp256k1'); +//dewcoin +import {getCurrentTimestamp} from './blockchain'; +const ec = new ecdsa.ec('secp256k1'); const COINBASE_AMOUNT: number = 50; -const ACCOUNT_ACTIVE_PERIOD: number = 10000; //n days.//should check - +//dewcoin +const ACCOUNT_ACTIVE_PERIOD: number = 60*60*24*31; //31 days. +const ACCOUNT_PURGE_PERIOD: number = 60*60*24*32; //32 days. /* class UnspentTxOut { @@ -27,14 +30,12 @@ class UnspentTxOut { class Account { public readonly address: string; public balance: number; - public txIndex: number; - public transactions: Transaction[]; + public txHistory: TxHistory[]; constructor(address: string) { this.address = address; this.balance = 0; - this.txIndex = 0; - this.transactions = []; + this.txHistory = []; } } @@ -65,26 +66,30 @@ class Transaction { } */ class Transaction { - public id: string; - - public sender: Account; //sender address - public receiver: Account; //receiver address. - public prev-balance: number; + public sender: string; + public receiver: string; public amount: number; - public after-balance: number; public timestamp: number; - public txIndex: number; public signature: string; - constructor(sender: Account, receiver: Account, amount: number) { + constructor(sender: string, receiver: string, amount: number) { this.sender = sender; - this.receiver = receiver - thia.prev-balance = 0;//This item is only used when put in an account + this.receiver = receiver; + this.amount = amount; + } +} +class TxHistory { + public id: string; + public txAccount: string; //the account that this transaction involvs. + public prevBalance: number; + public amount: number; // plus or minus. reflect the change of the balance. + public afterBalance: number; + public timestamp: number; + + constructor(txAccount: string, amount: number) { + this.txAccount = txAccount; this.amount = amount; - this.after-balance = 0;//This item is only used when it is put in an account. - this.timestampt = getCurrentTimestamp(); - this.txIndex = ++sender.txIndex; } } @@ -102,9 +107,11 @@ const getTransactionId = (transaction: Transaction): string => { }; */ const getTransactionId = (transaction: Transaction): string => { - return CryptoJS.SHA256(transaction.sender.address + transaction.receiver.address + transaction.amount + transaction.timestampt + transaction.txIndex).toString(); + return CryptoJS.SHA256(transaction.sender + transaction.receiver + transaction.amount + transaction.timestamp).toString(); }; + + /* const validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean => { @@ -141,7 +148,19 @@ const validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTx return true; }; */ -const validateTransaction = (transaction: Transaction, AccountDB: Account[]): boolean => { +const existAccount = (address: string, accounts: Account[]): boolean => { + return _(accounts).map((acc: Account) => acc.address).includes(address); +} +const createAccount = (address: string, accounts: Account[]): boolean => { + var acc: Account = new Account(address); + accounts.push(acc); + return true; +} +const findAccount = (address: string, accounts: Account[]): Account => { + var account: Account = _.find(accounts, (acc: Account) => {return acc.address == address}); + return account; +} +const validateTransaction = (transaction: Transaction, accounts: Account[]): boolean => { if (!isValidTransactionStructure(transaction)) { return false; @@ -151,23 +170,22 @@ const validateTransaction = (transaction: Transaction, AccountDB: Account[]): bo console.log('invalid tx id: ' + transaction.id); return false; } - if (!exsitAccount(transaction.sender)) { - console.log('The sender does not have an account. tx: ' + transaction.id); - return false; - } - if (!exsitAccount(transaction.receiver)) { - console.log('The receiver does not have an account. tx: ' + transaction.id); + + const hasValidSignature: boolean = validateSignature(transaction); + if (!hasValidSignature) { + console.log('The signature is invalid in tx: ' + transaction.id); return false; } - if (transaction.amount > transaction.sender.balance) { + accSender = _.find(accounts, (acc: Account) => {return acc.address == transaction.sender}); + if (transaction.amount > accSender.balance) { console.log('The sender does not have enough coins. tx: ' + transaction.id); return false; } - if (transaction.timestampt < (Date() - ACCOUNT_ACTIVE_PERIOD)){//should check + if (transaction.timestamp < (getCurrentTimestamp() - ACCOUNT_ACTIVE_PERIOD)){ console.log('The transaction is too old. tx: ' + transaction.id); return false; } - if (transaction.txIndex IN transaction.sender.transactions.map((tx: Transaction) => tx.txIndex)){//should check + if (_(accSender.txHistory).map((th: TxHistory) => th.id).includes(transaction.id)){ console.log('The transaction is duplicated. tx: ' + transaction.id); return false; } @@ -201,32 +219,28 @@ const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: }; */ -const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number): boolean => { +const validateBlockTransactions = (aTransactions: Transaction[], accounts: Account[]): boolean => { const coinbaseTx = aTransactions[0]; - if (!validateCoinbaseTx(coinbaseTx, blockIndex)) { + if (!validateCoinbaseTx(coinbaseTx)) { console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); return false; } - - - - const txIns: TxIn[] = _(aTransactions) - .map((tx) => tx.txIns) - .flatten() + const txIds: number[] = _(aTransactions) + .map((tx) => tx.id) .value(); - if (hasDuplicates(txIns)) { + if (hasDuplicates(txIds)) { return false; } // all but coinbase transactions const normalTransactions: Transaction[] = aTransactions.slice(1); - return normalTransactions.map((tx) => validateTransaction(tx, aUnspentTxOuts)) + return normalTransactions.map((tx) => validateTransaction(tx, accounts)) .reduce((a, b) => (a && b), true); - }; +/* const hasDuplicates = (txIns: TxIn[]): boolean => { const groups = _.countBy(txIns, (txIn: TxIn) => txIn.txOutId + txIn.txOutIndex); return _(groups) @@ -240,7 +254,23 @@ const hasDuplicates = (txIns: TxIn[]): boolean => { }) .includes(true); }; +*/ +const hasDuplicates = (nums: number[]): boolean => { + const groups = _.countBy(nums); + return _(groups) + .map((value, key) => { + if (value > 1) { + console.log('duplicate number: ' + key); + return true; + } else { + return false; + } + }) + .includes(true); +}; + +/* const validateCoinbaseTx = (transaction: Transaction, blockIndex: number): boolean => { if (transaction == null) { console.log('the first transaction in the block must be coinbase transaction'); @@ -268,7 +298,30 @@ const validateCoinbaseTx = (transaction: Transaction, blockIndex: number): boole } return true; }; +*/ +const validateCoinbaseTx = (transaction: Transaction): boolean => { + if (transaction == null) { + console.log('the first transaction in the block must be coinbase transaction'); + return false; + } + if (getTransactionId(transaction) !== transaction.id) { + console.log('invalid coinbase tx id: ' + transaction.id); + return false; + } + if (transaction.sender !== "coinbase") { + console.log('It is not a coinbase transaction'); + return; + } + if (transaction.amount !== COINBASE_AMOUNT) { + console.log('invalid coinbase amount in coinbase transaction'); + return false; + } + return true; +}; + + +/* const validateTxIn = (txIn: TxIn, transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean => { const referencedUTxOut: UnspentTxOut = aUnspentTxOuts.find((uTxO) => uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex); @@ -286,15 +339,30 @@ const validateTxIn = (txIn: TxIn, transaction: Transaction, aUnspentTxOuts: Unsp } return true; }; +*/ +const validateSignature = (transaction: Transaction): boolean => { + const key = ec.keyFromPublic(transaction.sender, 'hex'); + const validSignature: boolean = key.verify(transaction.id, transaction.signature); + if (!validSignature) { + console.log('invalid tx signature: %s txId: %s address: %s', transaction.signature, transaction.id, transaction.sender); + return false; + } + return true; +}; + + +/* const getTxInAmount = (txIn: TxIn, aUnspentTxOuts: UnspentTxOut[]): number => { return findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts).amount; }; - const findUnspentTxOut = (transactionId: string, index: number, aUnspentTxOuts: UnspentTxOut[]): UnspentTxOut => { return aUnspentTxOuts.find((uTxO) => uTxO.txOutId === transactionId && uTxO.txOutIndex === index); }; +*/ + +/* const getCoinbaseTransaction = (address: string, blockIndex: number): Transaction => { const t = new Transaction(); const txIn: TxIn = new TxIn(); @@ -307,7 +375,16 @@ const getCoinbaseTransaction = (address: string, blockIndex: number): Transactio t.id = getTransactionId(t); return t; }; +*/ +const getCoinbaseTransaction = (miner: string): Transaction => { + const t = new Transaction("coinbase", miner, COINBASE_AMOUNT); + t.timestamp = getCurrentTimestamp(); + t.id = getTransactionId(t); + return t; +}; + +/* const signTxIn = (transaction: Transaction, txInIndex: number, privateKey: string, aUnspentTxOuts: UnspentTxOut[]): string => { const txIn: TxIn = transaction.txIns[txInIndex]; @@ -330,7 +407,22 @@ const signTxIn = (transaction: Transaction, txInIndex: number, return signature; }; +*/ +const signTransaction = (transaction: Transaction, privateKey: string): string => { + const dataToSign = transaction.id; + if (getPublicKey(privateKey) !== transaction.sender) { + console.log('trying to sign an input with private' + + ' key that does not match the address'); + throw Error(); + } + const key = ec.keyFromPrivate(privateKey, 'hex'); + const signature: string = toHexString(key.sign(dataToSign).toDER()); + + return signature; +}; + +/* const updateUnspentTxOuts = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[]): UnspentTxOut[] => { const newUnspentTxOuts: UnspentTxOut[] = aTransactions .map((t) => { @@ -349,7 +441,50 @@ const updateUnspentTxOuts = (aTransactions: Transaction[], aUnspentTxOuts: Unspe return resultingUnspentTxOuts; }; +*/ +const updateAccounts = (aTransactions: Transaction[], accounts: Account[]): Account[] => { + var amt: number; + var thSender: TxHistory; + var thReceiver: TxHistory; + var accSender: Account; + var accReceiver: Account; + var now: number; + + for(var i=0; i {th.timsstamp < (now + ACCOUNT_PURGE_PERIOD)}).push(thSender); + //clean txHistory at the same time. + } + if (!exsitAccount(aTransactions[i].receiver, accounts)) { + createAccount(aTransactions[i].receiver, accounts); + } + accReceiver = findAccount(aTransactions[i].receiver, accounts); + thReceiver = new TxHistory(aTransactions[i].sender, amt); + thReceiver.id = aTransactions[i].id; + thReceiver.timestamp = aTransactions[i].timestamp; + thReceiver.prevBalance = accReceiver.balance; + accReceiver.balance += amt; + thReceiver.afterBalance = accSender.balance; + accReceiver.txHistory = _(accReceiver.txHistory).filter((th: TxHistory) => {th.timsstamp < (now + ACCOUNT_PURGE_PERIOD)}).push(thReceiver); + //clean txHistory at the same time. + } + return accounts;//check again +}; + +/* const processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number) => { if (!validateBlockTransactions(aTransactions, aUnspentTxOuts, blockIndex)) { @@ -358,6 +493,18 @@ const processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: Unspe } return updateUnspentTxOuts(aTransactions, aUnspentTxOuts); }; +*/ +const processTransactions = (aTransactions: Transaction[], accounts: Account[]) => { + + if (!validateBlockTransactions(aTransactions, accounts)) { + console.log('invalid block transactions'); + return null; + } + return updateAccounts(aTransactions, accounts); +}; + + + const toHexString = (byteArray): string => { return Array.from(byteArray, (byte: any) => { @@ -369,6 +516,8 @@ const getPublicKey = (aPrivateKey: string): string => { return ec.keyFromPrivate(aPrivateKey, 'hex').getPublic().encode('hex'); }; + +/* const isValidTxInStructure = (txIn: TxIn): boolean => { if (txIn == null) { console.log('txIn is null'); @@ -386,7 +535,6 @@ const isValidTxInStructure = (txIn: TxIn): boolean => { return true; } }; - const isValidTxOutStructure = (txOut: TxOut): boolean => { if (txOut == null) { console.log('txOut is null'); @@ -404,7 +552,11 @@ const isValidTxOutStructure = (txOut: TxOut): boolean => { return true; } }; +*/ + + +/* const isValidTransactionStructure = (transaction: Transaction) => { if (typeof transaction.id !== 'string') { console.log('transactionId missing'); @@ -432,6 +584,35 @@ const isValidTransactionStructure = (transaction: Transaction) => { } return true; }; +*/ +const isValidTransactionStructure = (transaction: Transaction) => { + if (typeof transaction.id !== 'string') { + console.log('transactionId missing'); + return false; + } + if (typeof transaction.sender !== 'string') { + console.log('transaction sender missing'); + return false; + } + if (typeof transaction.receiver !== 'string') { + console.log('transaction receiver missing'); + return false; + } + if (typeof transaction.amount !== 'number') { + console.log('transaction amount missing'); + return false; + } + if (typeof transaction.timsstamp !== 'number') { + console.log('transaction timestamp missing'); + return false; + } + if (typeof transaction.signature !== 'string') { + console.log('transaction signature missing'); + return false; + } + return true; +}; + // valid address is a valid ecdsa public key in the 04 + X-coordinate + Y-coordinate format const isValidAddress = (address: string): boolean => { @@ -449,8 +630,20 @@ const isValidAddress = (address: string): boolean => { return true; }; + +/* export { processTransactions, signTxIn, getTransactionId, isValidAddress, validateTransaction, UnspentTxOut, TxIn, TxOut, getCoinbaseTransaction, getPublicKey, hasDuplicates, Transaction }; +*/ +export { + processTransactions, signTransaction, getTransactionId, isValidAddress, validateTransaction, + Account, getCoinbaseTransaction, getPublicKey, hasDuplicates, + Transaction +}; +//signTxIn => signTransaction +//UnspentTxOut => Account +//TxIn +//TxOut From 6b4ab700026cde544d8561e0321b7d527ee24a18 Mon Sep 17 00:00:00 2001 From: ywang Date: Sun, 5 Aug 2018 09:50:59 -0400 Subject: [PATCH 10/36] changed 4 files --- dew/src/blockchain.ts | 162 +++++++++++++++++++++++++++++++++++-- dew/src/main.ts | 33 +++++++- dew/src/transaction.ts | 53 +++++++++--- dew/src/transactionPool.ts | 46 ++++++++++- dew/src/util.js | 11 ++- dew/src/wallet.js | 104 ++++++++++++------------ 6 files changed, 332 insertions(+), 77 deletions(-) diff --git a/dew/src/blockchain.ts b/dew/src/blockchain.ts index 85aedc3..a92dec7 100644 --- a/dew/src/blockchain.ts +++ b/dew/src/blockchain.ts @@ -1,9 +1,16 @@ import * as CryptoJS from 'crypto-js'; import * as _ from 'lodash'; import {broadcastLatest, broadCastTransactionPool} from './p2p'; + +/* import { getCoinbaseTransaction, isValidAddress, processTransactions, Transaction, UnspentTxOut } from './transaction'; +*/ +import { + getCoinbaseTransaction, isValidAddress, processTransactions, Transaction, Account, findAccount +} from './transaction'; + import {addToTransactionPool, getTransactionPool, updateTransactionPool} from './transactionPool'; import {hexToBinary} from './util'; import {createTransaction, findUnspentTxOuts, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; @@ -30,6 +37,7 @@ class Block { } } +/* const genesisTransaction = { 'txIns': [{'signature': '', 'txOutId': '', 'txOutIndex': 0}], 'txOuts': [{ @@ -38,6 +46,15 @@ const genesisTransaction = { }], 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3' }; +*/ +var stamp: number = getCurrentTimestamp(); +const genesisTransaction = { + 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3', + 'sender': 'coinbase', + 'receiver': '04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a', + 'amount': 50, + 'timestamp': stamp +}; const genesisBlock: Block = new Block( 0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1465154705, [genesisTransaction], 0, 0 @@ -46,17 +63,25 @@ const genesisBlock: Block = new Block( let blockchain: Block[] = [genesisBlock]; // the unspent txOut of genesis block is set to unspentTxOuts on startup -let unspentTxOuts: UnspentTxOut[] = processTransactions(blockchain[0].data, [], 0); +//let unspentTxOuts: UnspentTxOut[] = processTransactions(blockchain[0].data, []); +let accounts: Account[] = processTransactions(blockchain[0].data); const getBlockchain = (): Block[] => blockchain; -const getUnspentTxOuts = (): UnspentTxOut[] => _.cloneDeep(unspentTxOuts); +//const getUnspentTxOuts = (): UnspentTxOut[] => _.cloneDeep(unspentTxOuts); +const getAccounts = (): Account[] => _.cloneDeep(accounts); // and txPool should be only updated at the same time +/* const setUnspentTxOuts = (newUnspentTxOut: UnspentTxOut[]) => { console.log('replacing unspentTxouts with: %s', newUnspentTxOut); unspentTxOuts = newUnspentTxOut; }; +*/ +const setAccounts = (newAccount: Account[]) => { + console.log('replacing accounts with: %s', newAccount); + accounts = newAccount; +}; const getLatestBlock = (): Block => blockchain[blockchain.length - 1]; @@ -106,16 +131,29 @@ const generateRawNextBlock = (blockData: Transaction[]) => { }; // gets the unspent transaction outputs owned by the wallet +/* const getMyUnspentTransactionOutputs = () => { return findUnspentTxOuts(getPublicFromWallet(), getUnspentTxOuts()); }; +*/ +const getMyAccount = () => { + return findAccount(getPublicFromWallet(), getAccounts()); +}; +/* const generateNextBlock = () => { const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet(), getLatestBlock().index + 1); const blockData: Transaction[] = [coinbaseTx].concat(getTransactionPool()); return generateRawNextBlock(blockData); }; +*/ +const generateNextBlock = () => { + const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet()); + const blockData: Transaction[] = [coinbaseTx].concat(getTransactionPool()); + return generateRawNextBlock(blockData); +}; +/* const generatenextBlockWithTransaction = (receiverAddress: string, amount: number) => { if (!isValidAddress(receiverAddress)) { throw Error('invalid address'); @@ -128,6 +166,19 @@ const generatenextBlockWithTransaction = (receiverAddress: string, amount: numbe const blockData: Transaction[] = [coinbaseTx, tx]; return generateRawNextBlock(blockData); }; +*/ +const generatenextBlockWithTransaction = (receiverAddress: string, amount: number) => { + if (!isValidAddress(receiverAddress)) { + throw Error('invalid address'); + } + if (typeof amount !== 'number') { + throw Error('invalid amount'); + } + const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet()); + const tx: Transaction = createTransaction(receiverAddress, amount, getPrivateFromWallet(), getAccounts(), getTransactionPool()); + const blockData: Transaction[] = [coinbaseTx, tx]; + return generateRawNextBlock(blockData); +}; const findBlock = (index: number, previousHash: string, timestamp: number, data: Transaction[], difficulty: number): Block => { let nonce = 0; @@ -140,16 +191,29 @@ const findBlock = (index: number, previousHash: string, timestamp: number, data: } }; +/* const getAccountBalance = (): number => { return getBalance(getPublicFromWallet(), getUnspentTxOuts()); }; +*/ +const getAccountBalance = (): number => { + return getBalance(getPublicFromWallet(), getAccounts()); +}; +/* const sendTransaction = (address: string, amount: number): Transaction => { const tx: Transaction = createTransaction(address, amount, getPrivateFromWallet(), getUnspentTxOuts(), getTransactionPool()); addToTransactionPool(tx, getUnspentTxOuts()); broadCastTransactionPool(); return tx; }; +*/ +const sendTransaction = (address: string, amount: number): Transaction => { + const tx: Transaction = createTransaction(address, amount, getPrivateFromWallet(), getAccounts(), getTransactionPool()); + addToTransactionPool(tx, getAccounts()); + broadCastTransactionPool(); + return tx; +}; const calculateHashForBlock = (block: Block): string => calculateHash(block.index, block.previousHash, block.timestamp, block.data, block.difficulty, block.nonce); @@ -225,6 +289,7 @@ const hashMatchesDifficulty = (hash: string, difficulty: number): boolean => { /* Checks if the given blockchain is valid. Return the unspent txOuts if the chain is valid */ +/* const isValidChain = (blockchainToValidate: Block[]): UnspentTxOut[] => { console.log('isValidChain:'); console.log(JSON.stringify(blockchainToValidate)); @@ -235,10 +300,10 @@ const isValidChain = (blockchainToValidate: Block[]): UnspentTxOut[] => { if (!isValidGenesis(blockchainToValidate[0])) { return null; } - /* - Validate each block in the chain. The block is valid if the block structure is valid - and the transaction are valid - */ + + //Validate each block in the chain. The block is valid if the block structure is valid + // and the transaction are valid + let aUnspentTxOuts: UnspentTxOut[] = []; for (let i = 0; i < blockchainToValidate.length; i++) { @@ -255,7 +320,39 @@ const isValidChain = (blockchainToValidate: Block[]): UnspentTxOut[] => { } return aUnspentTxOuts; }; +*/ +const isValidChain = (blockchainToValidate: Block[]): Account[] => { + console.log('isValidChain:'); + console.log(JSON.stringify(blockchainToValidate)); + const isValidGenesis = (block: Block): boolean => { + return JSON.stringify(block) === JSON.stringify(genesisBlock); + }; + if (!isValidGenesis(blockchainToValidate[0])) { + return null; + } + /* + Validate each block in the chain. The block is valid if the block structure is valid + and the transaction are valid + */ + let accts: Account[] = []; + + for (let i = 0; i < blockchainToValidate.length; i++) { + const currentBlock: Block = blockchainToValidate[i]; + if (i !== 0 && !isValidNewBlock(blockchainToValidate[i], blockchainToValidate[i - 1])) { + return null; + } + + accts = processTransactions(currentBlock.data, accts); + if (accts === null) { + console.log('invalid transactions in blockchain'); + return null; + } + } + return accts; +}; + +/* const addBlockToChain = (newBlock: Block): boolean => { if (isValidNewBlock(newBlock, getLatestBlock())) { const retVal: UnspentTxOut[] = processTransactions(newBlock.data, getUnspentTxOuts(), newBlock.index); @@ -271,7 +368,24 @@ const addBlockToChain = (newBlock: Block): boolean => { } return false; }; +*/ +const addBlockToChain = (newBlock: Block): boolean => { + if (isValidNewBlock(newBlock, getLatestBlock())) { + const retVal: Account[] = processTransactions(newBlock.data, getAccounts()); + if (retVal === null) { + console.log('block is not valid in terms of transactions'); + return false; + } else { + blockchain.push(newBlock); + setAccounts(retVal); + updateTransactionPool(accounts); + return true; + } + } + return false; +}; +/* const replaceChain = (newBlocks: Block[]) => { const aUnspentTxOuts = isValidChain(newBlocks); const validChain: boolean = aUnspentTxOuts !== null; @@ -286,14 +400,50 @@ const replaceChain = (newBlocks: Block[]) => { console.log('Received blockchain invalid'); } }; +*/ +const replaceChain = (newBlocks: Block[]) => { + const accts = isValidChain(newBlocks); + const validChain: boolean = accts !== null; + if (validChain && + getAccumulatedDifficulty(newBlocks) > getAccumulatedDifficulty(getBlockchain())) { + console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); + blockchain = newBlocks; + setAccounts(accts); + updateTransactionPool(accounts); + broadcastLatest(); + } else { + console.log('Received blockchain invalid'); + } +}; +/* const handleReceivedTransaction = (transaction: Transaction) => { addToTransactionPool(transaction, getUnspentTxOuts()); }; +*/ +const handleReceivedTransaction = (transaction: Transaction) => { + addToTransactionPool(transaction, getAccounts()); +}; +/* export { Block, getBlockchain, getUnspentTxOuts, getLatestBlock, sendTransaction, generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, handleReceivedTransaction, getMyUnspentTransactionOutputs, getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain }; +*/ +export { + Block, getBlockchain, getAccounts, getLatestBlock, sendTransaction, + generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, + handleReceivedTransaction, getMyAccount, + getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain +}; + +/* +getUnspentTxOuts = (): UnspentTxOut[] +getAccounts = (): Account[] + +getMyUnspentTransactionOutputs() +getMyAccount() +*/ diff --git a/dew/src/main.ts b/dew/src/main.ts index a272ffe..8c513d5 100644 --- a/dew/src/main.ts +++ b/dew/src/main.ts @@ -1,12 +1,23 @@ import * as bodyParser from 'body-parser'; import * as express from 'express'; import * as _ from 'lodash'; + +/* import { Block, generateNextBlock, generatenextBlockWithTransaction, generateRawNextBlock, getAccountBalance, getBlockchain, getMyUnspentTransactionOutputs, getUnspentTxOuts, sendTransaction } from './blockchain'; +*/ +import { + Block, generateNextBlock, generatenextBlockWithTransaction, generateRawNextBlock, getAccountBalance, + getBlockchain, getAccounts, getMyAccount, sendTransaction +} from './blockchain'; + import {connectToPeers, getSockets, initP2PServer} from './p2p'; -import {UnspentTxOut} from './transaction'; + +//import {UnspentTxOut} from './transaction'; +import {Account} from './transaction'; + import {getTransactionPool} from './transactionPool'; import {getPublicFromWallet, initWallet} from './wallet'; @@ -40,19 +51,39 @@ const initHttpServer = (myHttpPort: number) => { res.send(tx); }); + /* app.get('/address/:address', (req, res) => { const unspentTxOuts: UnspentTxOut[] = _.filter(getUnspentTxOuts(), (uTxO) => uTxO.address === req.params.address); res.send({'unspentTxOuts': unspentTxOuts}); }); + */ + //redefined: obtain transaction history. + app.get('/address/:address', (req, res) => { + var acc: Account = findAccount(req.params.address, getAccounts); + if(acc==[]){ + res.send({'Error:': "address is wrong"}); + } + res.send({'accountTxHistory': acc.txHistory}); + }); + /* app.get('/unspentTransactionOutputs', (req, res) => { res.send(getUnspentTxOuts()); }); + */ + app.get('/accounts', (req, res) => { + res.send(getAccounts()); + }); + /* app.get('/myUnspentTransactionOutputs', (req, res) => { res.send(getMyUnspentTransactionOutputs()); }); + */ + app.get('/myAccount', (req, res) => { + res.send(getMyAccount()); + }); app.post('/mineRawBlock', (req, res) => { if (req.body.data == null) { diff --git a/dew/src/transaction.ts b/dew/src/transaction.ts index b9c4bfb..296c561 100644 --- a/dew/src/transaction.ts +++ b/dew/src/transaction.ts @@ -30,11 +30,13 @@ class UnspentTxOut { class Account { public readonly address: string; public balance: number; + public available: number; public txHistory: TxHistory[]; constructor(address: string) { this.address = address; this.balance = 0; + this.available = 0; this.txHistory = []; } } @@ -176,17 +178,13 @@ const validateTransaction = (transaction: Transaction, accounts: Account[]): boo console.log('The signature is invalid in tx: ' + transaction.id); return false; } - accSender = _.find(accounts, (acc: Account) => {return acc.address == transaction.sender}); - if (transaction.amount > accSender.balance) { - console.log('The sender does not have enough coins. tx: ' + transaction.id); - return false; - } if (transaction.timestamp < (getCurrentTimestamp() - ACCOUNT_ACTIVE_PERIOD)){ console.log('The transaction is too old. tx: ' + transaction.id); return false; } + accSender = _.find(accounts, (acc: Account) => {return acc.address == transaction.sender}); if (_(accSender.txHistory).map((th: TxHistory) => th.id).includes(transaction.id)){ - console.log('The transaction is duplicated. tx: ' + transaction.id); + console.log('The transaction is duplicated with the chain. tx: ' + transaction.id); return false; } @@ -225,14 +223,26 @@ const validateBlockTransactions = (aTransactions: Transaction[], accounts: Accou console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); return false; } - const txIds: number[] = _(aTransactions) + const txIds: string[] = _(aTransactions) .map((tx) => tx.id) .value(); if (hasDuplicates(txIds)) { + console.log('Transactions in block are duplicated.'); return false; } + for(var i=0; i < accounts.length; i++){ + accounts[i].available = accounts[i].balance; + } + for(var j=0; j < aTransactions.length; j++){ + accSender = findAccount(aTransactions[j].sender); + if (aTransactions[j].amount > accSender.available) { + console.log('The sender does not have enough coins. tx: ' + aTransactions[j].id); + return false; + } + accSender.available -=aTransactions[j].amount; + } // all but coinbase transactions const normalTransactions: Transaction[] = aTransactions.slice(1); return normalTransactions.map((tx) => validateTransaction(tx, accounts)) @@ -255,12 +265,12 @@ const hasDuplicates = (txIns: TxIn[]): boolean => { .includes(true); }; */ -const hasDuplicates = (nums: number[]): boolean => { - const groups = _.countBy(nums); +const hasDuplicates = (names: string[]): boolean => { + const groups = _.countBy(names); return _(groups) .map((value, key) => { if (value > 1) { - console.log('duplicate number: ' + key); + console.log('duplicate string: ' + key); return true; } else { return false; @@ -643,7 +653,24 @@ export { Account, getCoinbaseTransaction, getPublicKey, hasDuplicates, Transaction }; -//signTxIn => signTransaction +// +// +//Transaction //UnspentTxOut => Account -//TxIn -//TxOut +//-TxIn +//-TxOut +// +//signTxIn = (transaction: Transaction, txInIndex: number, +//signTransaction = (transaction: Transaction, privateKey: string): string => { +// +//processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number) +//processTransactions = (aTransactions: Transaction[], accounts: Account[]) +// +//validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean +//validateTransaction = (transaction: Transaction, accounts: Account[]): boolean +// +//getCoinbaseTransaction = (address: string, blockIndex: number): Transaction +//getCoinbaseTransaction = (miner: string): Transaction +// +//hasDuplicates = (txIns: TxIn[]): boolean +//hasDuplicates = (nums: number[]): boolean diff --git a/dew/src/transactionPool.ts b/dew/src/transactionPool.ts index 5296b72..87d2522 100644 --- a/dew/src/transactionPool.ts +++ b/dew/src/transactionPool.ts @@ -1,5 +1,7 @@ import * as _ from 'lodash'; -import {Transaction, TxIn, UnspentTxOut, validateTransaction} from './transaction'; + +//import {Transaction, TxIn, UnspentTxOut, validateTransaction} from './transaction'; +import {Transaction, Account, validateTransaction} from './transaction'; let transactionPool: Transaction[] = []; @@ -7,6 +9,7 @@ const getTransactionPool = () => { return _.cloneDeep(transactionPool); }; +/* const addToTransactionPool = (tx: Transaction, unspentTxOuts: UnspentTxOut[]) => { if (!validateTransaction(tx, unspentTxOuts)) { @@ -19,14 +22,30 @@ const addToTransactionPool = (tx: Transaction, unspentTxOuts: UnspentTxOut[]) => console.log('adding to txPool: %s', JSON.stringify(tx)); transactionPool.push(tx); }; +*/ +const addToTransactionPool = (tx: Transaction, accounts: Account[]) => { + + if (!validateTransaction(tx, accounts)) { + throw Error('Trying to add invalid tx to pool'); + } + + if (!isValidTxForPool(tx, transactionPool, accounts)) { + throw Error('Trying to add invalid tx to pool'); + } + console.log('adding to txPool: %s', JSON.stringify(tx)); + transactionPool.push(tx); +}; +/* const hasTxIn = (txIn: TxIn, unspentTxOuts: UnspentTxOut[]): boolean => { const foundTxIn = unspentTxOuts.find((uTxO: UnspentTxOut) => { return uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex; }); return foundTxIn !== undefined; }; +*/ +/* const updateTransactionPool = (unspentTxOuts: UnspentTxOut[]) => { const invalidTxs = []; for (const tx of transactionPool) { @@ -42,14 +61,39 @@ const updateTransactionPool = (unspentTxOuts: UnspentTxOut[]) => { transactionPool = _.without(transactionPool, ...invalidTxs); } }; +*/ +const updateTransactionPool = (accounts: Account[]) => { + transactionPool = _(transactionPool).filter(tx => validateTransaction(tx, accounts)); +}; +/* const getTxPoolIns = (aTransactionPool: Transaction[]): TxIn[] => { return _(aTransactionPool) .map((tx) => tx.txIns) .flatten() .value(); }; +*/ + +/* +const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): boolean => { + const txPoolIns: TxIn[] = getTxPoolIns(aTtransactionPool); + const containsTxIn = (txIns: TxIn[], txIn: TxIn) => { + return _.find(txPoolIns, ((txPoolIn) => { + return txIn.txOutIndex === txPoolIn.txOutIndex && txIn.txOutId === txPoolIn.txOutId; + })); + }; + + for (const txIn of tx.txIns) { + if (containsTxIn(txPoolIns, txIn)) { + console.log('txIn already found in the txPool'); + return false; + } + } + return true; +}; +*/ const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): boolean => { const txPoolIns: TxIn[] = getTxPoolIns(aTtransactionPool); diff --git a/dew/src/util.js b/dew/src/util.js index 9ccd8be..57d0d2e 100644 --- a/dew/src/util.js +++ b/dew/src/util.js @@ -1,14 +1,14 @@ "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const hexToBinary = (s) => { - let ret = ''; - const lookupTable = { +exports.__esModule = true; +var hexToBinary = function (s) { + var ret = ''; + var lookupTable = { '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', 'e': '1110', 'f': '1111' }; - for (let i = 0; i < s.length; i = i + 1) { + for (var i = 0; i < s.length; i = i + 1) { if (lookupTable[s[i]]) { ret += lookupTable[s[i]]; } @@ -19,4 +19,3 @@ const hexToBinary = (s) => { return ret; }; exports.hexToBinary = hexToBinary; -//# sourceMappingURL=util.js.map \ No newline at end of file diff --git a/dew/src/wallet.js b/dew/src/wallet.js index 0501bf4..67ae0c9 100644 --- a/dew/src/wallet.js +++ b/dew/src/wallet.js @@ -1,87 +1,88 @@ "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const elliptic_1 = require("elliptic"); -const fs_1 = require("fs"); -const _ = require("lodash"); -const transaction_1 = require("./transaction"); -const EC = new elliptic_1.ec('secp256k1'); -const privateKeyLocation = process.env.PRIVATE_KEY || 'node/wallet/private_key'; -const getPrivateFromWallet = () => { - const buffer = fs_1.readFileSync(privateKeyLocation, 'utf8'); +exports.__esModule = true; +var elliptic_1 = require("elliptic"); +var fs_1 = require("fs"); +var _ = require("lodash"); +var transaction_1 = require("./transaction"); +var EC = new elliptic_1.ec('secp256k1'); +var privateKeyLocation = process.env.PRIVATE_KEY || 'node/wallet/private_key'; +var getPrivateFromWallet = function () { + var buffer = fs_1.readFileSync(privateKeyLocation, 'utf8'); return buffer.toString(); }; exports.getPrivateFromWallet = getPrivateFromWallet; -const getPublicFromWallet = () => { - const privateKey = getPrivateFromWallet(); - const key = EC.keyFromPrivate(privateKey, 'hex'); +var getPublicFromWallet = function () { + var privateKey = getPrivateFromWallet(); + var key = EC.keyFromPrivate(privateKey, 'hex'); return key.getPublic().encode('hex'); }; exports.getPublicFromWallet = getPublicFromWallet; -const generatePrivateKey = () => { - const keyPair = EC.genKeyPair(); - const privateKey = keyPair.getPrivate(); +var generatePrivateKey = function () { + var keyPair = EC.genKeyPair(); + var privateKey = keyPair.getPrivate(); return privateKey.toString(16); }; exports.generatePrivateKey = generatePrivateKey; -const initWallet = () => { +var initWallet = function () { // let's not override existing private keys if (fs_1.existsSync(privateKeyLocation)) { return; } - const newPrivateKey = generatePrivateKey(); + var newPrivateKey = generatePrivateKey(); fs_1.writeFileSync(privateKeyLocation, newPrivateKey); console.log('new wallet with private key created to : %s', privateKeyLocation); }; exports.initWallet = initWallet; -const deleteWallet = () => { +var deleteWallet = function () { if (fs_1.existsSync(privateKeyLocation)) { fs_1.unlinkSync(privateKeyLocation); } }; exports.deleteWallet = deleteWallet; -const getBalance = (address, unspentTxOuts) => { +var getBalance = function (address, unspentTxOuts) { return _(findUnspentTxOuts(address, unspentTxOuts)) - .map((uTxO) => uTxO.amount) + .map(function (uTxO) { return uTxO.amount; }) .sum(); }; exports.getBalance = getBalance; -const findUnspentTxOuts = (ownerAddress, unspentTxOuts) => { - return _.filter(unspentTxOuts, (uTxO) => uTxO.address === ownerAddress); +var findUnspentTxOuts = function (ownerAddress, unspentTxOuts) { + return _.filter(unspentTxOuts, function (uTxO) { return uTxO.address === ownerAddress; }); }; exports.findUnspentTxOuts = findUnspentTxOuts; -const findTxOutsForAmount = (amount, myUnspentTxOuts) => { - let currentAmount = 0; - const includedUnspentTxOuts = []; - for (const myUnspentTxOut of myUnspentTxOuts) { +var findTxOutsForAmount = function (amount, myUnspentTxOuts) { + var currentAmount = 0; + var includedUnspentTxOuts = []; + for (var _i = 0, myUnspentTxOuts_1 = myUnspentTxOuts; _i < myUnspentTxOuts_1.length; _i++) { + var myUnspentTxOut = myUnspentTxOuts_1[_i]; includedUnspentTxOuts.push(myUnspentTxOut); currentAmount = currentAmount + myUnspentTxOut.amount; if (currentAmount >= amount) { - const leftOverAmount = currentAmount - amount; - return { includedUnspentTxOuts, leftOverAmount }; + var leftOverAmount = currentAmount - amount; + return { includedUnspentTxOuts: includedUnspentTxOuts, leftOverAmount: leftOverAmount }; } } - const eMsg = 'Cannot create transaction from the available unspent transaction outputs.' + + var eMsg = 'Cannot create transaction from the available unspent transaction outputs.' + ' Required amount:' + amount + '. Available unspentTxOuts:' + JSON.stringify(myUnspentTxOuts); throw Error(eMsg); }; -const createTxOuts = (receiverAddress, myAddress, amount, leftOverAmount) => { - const txOut1 = new transaction_1.TxOut(receiverAddress, amount); +var createTxOuts = function (receiverAddress, myAddress, amount, leftOverAmount) { + var txOut1 = new transaction_1.TxOut(receiverAddress, amount); if (leftOverAmount === 0) { return [txOut1]; } else { - const leftOverTx = new transaction_1.TxOut(myAddress, leftOverAmount); + var leftOverTx = new transaction_1.TxOut(myAddress, leftOverAmount); return [txOut1, leftOverTx]; } }; -const filterTxPoolTxs = (unspentTxOuts, transactionPool) => { - const txIns = _(transactionPool) - .map((tx) => tx.txIns) +var filterTxPoolTxs = function (unspentTxOuts, transactionPool) { + var txIns = _(transactionPool) + .map(function (tx) { return tx.txIns; }) .flatten() .value(); - const removable = []; - for (const unspentTxOut of unspentTxOuts) { - const txIn = _.find(txIns, (aTxIn) => { + var removable = []; + var _loop_1 = function (unspentTxOut) { + var txIn = _.find(txIns, function (aTxIn) { return aTxIn.txOutIndex === unspentTxOut.txOutIndex && aTxIn.txOutId === unspentTxOut.txOutId; }); if (txIn === undefined) { @@ -89,32 +90,35 @@ const filterTxPoolTxs = (unspentTxOuts, transactionPool) => { else { removable.push(unspentTxOut); } + }; + for (var _i = 0, unspentTxOuts_1 = unspentTxOuts; _i < unspentTxOuts_1.length; _i++) { + var unspentTxOut = unspentTxOuts_1[_i]; + _loop_1(unspentTxOut); } - return _.without(unspentTxOuts, ...removable); + return _.without.apply(_, [unspentTxOuts].concat(removable)); }; -const createTransaction = (receiverAddress, amount, privateKey, unspentTxOuts, txPool) => { +var createTransaction = function (receiverAddress, amount, privateKey, unspentTxOuts, txPool) { console.log('txPool: %s', JSON.stringify(txPool)); - const myAddress = transaction_1.getPublicKey(privateKey); - const myUnspentTxOutsA = unspentTxOuts.filter((uTxO) => uTxO.address === myAddress); - const myUnspentTxOuts = filterTxPoolTxs(myUnspentTxOutsA, txPool); + var myAddress = transaction_1.getPublicKey(privateKey); + var myUnspentTxOutsA = unspentTxOuts.filter(function (uTxO) { return uTxO.address === myAddress; }); + var myUnspentTxOuts = filterTxPoolTxs(myUnspentTxOutsA, txPool); // filter from unspentOutputs such inputs that are referenced in pool - const { includedUnspentTxOuts, leftOverAmount } = findTxOutsForAmount(amount, myUnspentTxOuts); - const toUnsignedTxIn = (unspentTxOut) => { - const txIn = new transaction_1.TxIn(); + var _a = findTxOutsForAmount(amount, myUnspentTxOuts), includedUnspentTxOuts = _a.includedUnspentTxOuts, leftOverAmount = _a.leftOverAmount; + var toUnsignedTxIn = function (unspentTxOut) { + var txIn = new transaction_1.TxIn(); txIn.txOutId = unspentTxOut.txOutId; txIn.txOutIndex = unspentTxOut.txOutIndex; return txIn; }; - const unsignedTxIns = includedUnspentTxOuts.map(toUnsignedTxIn); - const tx = new transaction_1.Transaction(); + var unsignedTxIns = includedUnspentTxOuts.map(toUnsignedTxIn); + var tx = new transaction_1.Transaction(); tx.txIns = unsignedTxIns; tx.txOuts = createTxOuts(receiverAddress, myAddress, amount, leftOverAmount); tx.id = transaction_1.getTransactionId(tx); - tx.txIns = tx.txIns.map((txIn, index) => { + tx.txIns = tx.txIns.map(function (txIn, index) { txIn.signature = transaction_1.signTxIn(tx, index, privateKey, unspentTxOuts); return txIn; }); return tx; }; exports.createTransaction = createTransaction; -//# sourceMappingURL=wallet.js.map \ No newline at end of file From 195b317f2d1a24ceea99bf8bb00cfb60682bb602 Mon Sep 17 00:00:00 2001 From: ywang Date: Sun, 5 Aug 2018 11:23:59 -0400 Subject: [PATCH 11/36] change transactionPool.ts --- dew/src/transactionPool.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/dew/src/transactionPool.ts b/dew/src/transactionPool.ts index 87d2522..f3cbcae 100644 --- a/dew/src/transactionPool.ts +++ b/dew/src/transactionPool.ts @@ -63,6 +63,30 @@ const updateTransactionPool = (unspentTxOuts: UnspentTxOut[]) => { }; */ const updateTransactionPool = (accounts: Account[]) => { + const txIds: number[] = _(transactionPool) + .map((tx) => tx.id) + .value(); + + if (hasDuplicates(txIds)) { + console.log('Transactions in block are duplicated.'); + return false; + } + + for(var i=0; i < accounts.length; i++){ + accounts[i].available = accounts[i].balance; + } + for(var j=0; j < aTransactions.length; j++){ + accSender = findAccount(aTransactions[j].sender); + if (aTransactions[j].amount > accSender.available) { + console.log('The sender does not have enough coins. tx: ' + aTransactions[j].id); + return false; + } + accSender.available -=aTransactions[j].amount; + } + // all but coinbase transactions + const normalTransactions: Transaction[] = aTransactions.slice(1); + return normalTransactions.map((tx) => validateTransaction(tx, accounts)) + .reduce((a, b) => (a && b), true); transactionPool = _(transactionPool).filter(tx => validateTransaction(tx, accounts)); }; From 1ecfa468d7c7b9ab408e48726440cb7be25d8ba7 Mon Sep 17 00:00:00 2001 From: ywang Date: Mon, 6 Aug 2018 23:04:03 -0400 Subject: [PATCH 12/36] first working code tested all major functions except p2p. wrote read me, including Windows command. --- dew/README.md | 88 +++++++++++++++++++++++++++------- dew/src/blockchain.ts | 52 +++++++++++--------- dew/src/main.ts | 39 +++++++++------ dew/src/transaction.ts | 50 +++++++++++++++----- dew/src/transactionPool.ts | 97 ++++++++++++++++++++++++-------------- dew/src/wallet.ts | 53 ++++++++++++++++++++- 6 files changed, 275 insertions(+), 104 deletions(-) diff --git a/dew/README.md b/dew/README.md index 839b976..2951e42 100644 --- a/dew/README.md +++ b/dew/README.md @@ -10,46 +10,98 @@ npm install npm start ``` -##### Get blockchain -``` + +##### Query the whole blockchain curl http://localhost:3001/blocks + + + +##### Query all accounts + +curl http://localhost:3001/accounts + + +##### Query the transaction pool +``` +curl http://localhost:3001/transactionPool ``` + +#### Query all connected peers +``` +curl http://localhost:3001/peers +``` + + +##### Query my account + +curl http://localhost:3001/myaccount + + +##### Query my account balance +``` +curl http://localhost:3001/mybalance +``` + + +##### Query my account address + +curl http://localhost:3001/myaddress + + + +##### Query a block with block hash + +curl http://localhost:3001/block/:hash + + + +##### Query a transaction with transaction id + +curl http://localhost:3001/transaction/:id + + + +##### Query an account with account address + +curl http://localhost:3001/account/:address + + + ##### Mine a block ``` curl -X POST http://localhost:3001/mineBlock ``` + ##### Send transaction ``` curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction ``` +For Windows: +curl -H "Content-type: application/json" --data "{\"address\": \"04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a\", \"amount\" : 35}" http://localhost:3001/sendTransaction + -##### Query transaction pool -``` -curl http://localhost:3001/transactionPool -``` ##### Mine transaction ``` curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction ``` +For Windows: +curl -H "Content-type: application/json" --data "{\"address\": \"04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a\", \"amount\" : 20}" http://localhost:3001/mineTransaction -##### Get balance -``` -curl http://localhost:3001/balance -``` - -#### Query information about a specific address -``` -curl http://localhost:3001/address/04f72a4541275aeb4344a8b049bfe2734b49fe25c08d56918f033507b96a61f9e3c330c4fcd46d0854a712dc878b9c280abe90c788c47497e06df78b25bf60ae64 -``` ##### Add peer ``` -curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addPeer +curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addpeer ``` -#### Query connected peers +For Windows: +curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:6001\"}" http://localhost:3001/addpeer ``` -curl http://localhost:3001/peers + + +#### Stop the server +``` +curl http://localhost:3001/stop ``` + diff --git a/dew/src/blockchain.ts b/dew/src/blockchain.ts index a92dec7..558ef33 100644 --- a/dew/src/blockchain.ts +++ b/dew/src/blockchain.ts @@ -8,12 +8,13 @@ import { } from './transaction'; */ import { - getCoinbaseTransaction, isValidAddress, processTransactions, Transaction, Account, findAccount + getCoinbaseTransaction, isValidAddress, processTransactions, Transaction, Account, findAccount, getTransactionId } from './transaction'; -import {addToTransactionPool, getTransactionPool, updateTransactionPool} from './transactionPool'; +import {addToTransactionPool, getTransactionPool, updateTransactionPool, updateTransactionPoolReplace} from './transactionPool'; import {hexToBinary} from './util'; -import {createTransaction, findUnspentTxOuts, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; +//import {createTransaction, findUnspentTxOuts, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; +import {createTransaction, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; class Block { @@ -37,6 +38,8 @@ class Block { } } +const getCurrentTimestamp = (): number => Math.round(new Date().getTime() / 1000); + /* const genesisTransaction = { 'txIns': [{'signature': '', 'txOutId': '', 'txOutIndex': 0}], @@ -47,14 +50,11 @@ const genesisTransaction = { 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3' }; */ -var stamp: number = getCurrentTimestamp(); -const genesisTransaction = { - 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3', - 'sender': 'coinbase', - 'receiver': '04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a', - 'amount': 50, - 'timestamp': stamp -}; +const genesisTransaction = new Transaction('coinbase', + '04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a', 50); +genesisTransaction.timestamp = getCurrentTimestamp(); +genesisTransaction.id = getTransactionId(genesisTransaction); +genesisTransaction.signature = ''; const genesisBlock: Block = new Block( 0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1465154705, [genesisTransaction], 0, 0 @@ -64,12 +64,15 @@ let blockchain: Block[] = [genesisBlock]; // the unspent txOut of genesis block is set to unspentTxOuts on startup //let unspentTxOuts: UnspentTxOut[] = processTransactions(blockchain[0].data, []); -let accounts: Account[] = processTransactions(blockchain[0].data); +let accounts: Account[] = processTransactions(blockchain[0].data, []); const getBlockchain = (): Block[] => blockchain; //const getUnspentTxOuts = (): UnspentTxOut[] => _.cloneDeep(unspentTxOuts); -const getAccounts = (): Account[] => _.cloneDeep(accounts); +//const getAccounts = (): Account[] => _.cloneDeep(accounts); +const getAccounts = (): Account[] => accounts; + + // and txPool should be only updated at the same time /* @@ -79,7 +82,7 @@ const setUnspentTxOuts = (newUnspentTxOut: UnspentTxOut[]) => { }; */ const setAccounts = (newAccount: Account[]) => { - console.log('replacing accounts with: %s', newAccount); + //console.log('replacing accounts with: %s', newAccount); accounts = newAccount; }; @@ -113,8 +116,7 @@ const getAdjustedDifficulty = (latestBlock: Block, aBlockchain: Block[]) => { } }; -const getCurrentTimestamp = (): number => Math.round(new Date().getTime() / 1000); - +//// const generateRawNextBlock = (blockData: Transaction[]) => { const previousBlock: Block = getLatestBlock(); const difficulty: number = getDifficulty(getBlockchain()); @@ -210,9 +212,14 @@ const sendTransaction = (address: string, amount: number): Transaction => { */ const sendTransaction = (address: string, amount: number): Transaction => { const tx: Transaction = createTransaction(address, amount, getPrivateFromWallet(), getAccounts(), getTransactionPool()); - addToTransactionPool(tx, getAccounts()); - broadCastTransactionPool(); - return tx; + if(tx == undefined){ + console.log('This transaction cannot be created.'); + return undefined; + }else{ + addToTransactionPool(tx, getAccounts()); + broadCastTransactionPool(); + return tx; + } }; const calculateHashForBlock = (block: Block): string => @@ -378,7 +385,8 @@ const addBlockToChain = (newBlock: Block): boolean => { } else { blockchain.push(newBlock); setAccounts(retVal); - updateTransactionPool(accounts); + //updateTransactionPool(accounts); + updateTransactionPool(newBlock.data); return true; } } @@ -409,7 +417,7 @@ const replaceChain = (newBlocks: Block[]) => { console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); blockchain = newBlocks; setAccounts(accts); - updateTransactionPool(accounts); + updateTransactionPoolReplace(accounts); broadcastLatest(); } else { console.log('Received blockchain invalid'); @@ -437,7 +445,7 @@ export { Block, getBlockchain, getAccounts, getLatestBlock, sendTransaction, generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, handleReceivedTransaction, getMyAccount, - getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain + getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain, getCurrentTimestamp }; /* diff --git a/dew/src/main.ts b/dew/src/main.ts index 8c513d5..b00f9ae 100644 --- a/dew/src/main.ts +++ b/dew/src/main.ts @@ -10,13 +10,13 @@ import { */ import { Block, generateNextBlock, generatenextBlockWithTransaction, generateRawNextBlock, getAccountBalance, - getBlockchain, getAccounts, getMyAccount, sendTransaction + getBlockchain, getMyAccount, getAccounts, sendTransaction } from './blockchain'; import {connectToPeers, getSockets, initP2PServer} from './p2p'; //import {UnspentTxOut} from './transaction'; -import {Account} from './transaction'; +import {Account, findAccount} from './transaction'; import {getTransactionPool} from './transactionPool'; import {getPublicFromWallet, initWallet} from './wallet'; @@ -58,13 +58,12 @@ const initHttpServer = (myHttpPort: number) => { res.send({'unspentTxOuts': unspentTxOuts}); }); */ - //redefined: obtain transaction history. - app.get('/address/:address', (req, res) => { - var acc: Account = findAccount(req.params.address, getAccounts); - if(acc==[]){ + app.get('/account/:address', (req, res) => { + var acc: Account = findAccount(req.params.address, getAccounts()); + if(acc == undefined){ res.send({'Error:': "address is wrong"}); } - res.send({'accountTxHistory': acc.txHistory}); + res.send({'Account': acc}); }); /* @@ -72,6 +71,7 @@ const initHttpServer = (myHttpPort: number) => { res.send(getUnspentTxOuts()); }); */ + //display all accounts app.get('/accounts', (req, res) => { res.send(getAccounts()); }); @@ -81,8 +81,13 @@ const initHttpServer = (myHttpPort: number) => { res.send(getMyUnspentTransactionOutputs()); }); */ - app.get('/myAccount', (req, res) => { - res.send(getMyAccount()); + app.get('/myaccount', (req, res) => { + var acc: Account = findAccount(getPublicFromWallet(), getAccounts()); + if(acc == undefined){ + res.send({'Error': 'No account was found.'}) + }else{ + res.send({'My Account': acc}); + } }); app.post('/mineRawBlock', (req, res) => { @@ -107,12 +112,16 @@ const initHttpServer = (myHttpPort: number) => { } }); - app.get('/balance', (req, res) => { - const balance: number = getAccountBalance(); - res.send({'balance': balance}); + app.get('/mybalance', (req, res) => { + var acc: Account = findAccount(getPublicFromWallet(), getAccounts()); + if(acc == undefined){ + res.send({'Error:': "No such account."}); + }else{ + res.send({'Balance': acc.balance}); + } }); - app.get('/address', (req, res) => { + app.get('/myaddress', (req, res) => { const address: string = getPublicFromWallet(); res.send({'address': address}); }); @@ -145,14 +154,14 @@ const initHttpServer = (myHttpPort: number) => { } }); - app.get('/transactionPool', (req, res) => { + app.get('/transactionpool', (req, res) => { res.send(getTransactionPool()); }); app.get('/peers', (req, res) => { res.send(getSockets().map((s: any) => s._socket.remoteAddress + ':' + s._socket.remotePort)); }); - app.post('/addPeer', (req, res) => { + app.post('/addpeer', (req, res) => { connectToPeers(req.body.peer); res.send(); }); diff --git a/dew/src/transaction.ts b/dew/src/transaction.ts index 296c561..b807cc9 100644 --- a/dew/src/transaction.ts +++ b/dew/src/transaction.ts @@ -4,6 +4,7 @@ import * as _ from 'lodash'; //dewcoin import {getCurrentTimestamp} from './blockchain'; +import {getTransactionPool} from './transactionPool';//debug const ec = new ecdsa.ec('secp256k1'); const COINBASE_AMOUNT: number = 50; @@ -169,7 +170,8 @@ const validateTransaction = (transaction: Transaction, accounts: Account[]): boo } if (getTransactionId(transaction) !== transaction.id) { - console.log('invalid tx id: ' + transaction.id); + console.log('validateTransaction: invalid tx id: ' + transaction.id); + console.log(getTransactionId(transaction)); return false; } @@ -182,9 +184,15 @@ const validateTransaction = (transaction: Transaction, accounts: Account[]): boo console.log('The transaction is too old. tx: ' + transaction.id); return false; } - accSender = _.find(accounts, (acc: Account) => {return acc.address == transaction.sender}); - if (_(accSender.txHistory).map((th: TxHistory) => th.id).includes(transaction.id)){ - console.log('The transaction is duplicated with the chain. tx: ' + transaction.id); + var accSender: Account = findAccount(transaction.sender, accounts); + if(accSender == undefined){ + console.log('validateTransaction: no account found.'); + return false; + } + if (_(accSender.txHistory).map((th: TxHistory) => {return th.id}).includes(transaction.id)){ + console.log(JSON.stringify(getTransactionPool())); + console.log('validateTransaction: The transaction is duplicated with the chain. tx: ' + transaction.id); + console.log(JSON.stringify(accSender.txHistory)); return false; } @@ -218,6 +226,8 @@ const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: }; */ const validateBlockTransactions = (aTransactions: Transaction[], accounts: Account[]): boolean => { + var accSender: Account; + const coinbaseTx = aTransactions[0]; if (!validateCoinbaseTx(coinbaseTx)) { console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); @@ -235,8 +245,12 @@ const validateBlockTransactions = (aTransactions: Transaction[], accounts: Accou for(var i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } - for(var j=0; j < aTransactions.length; j++){ - accSender = findAccount(aTransactions[j].sender); + for(var j=1; j < aTransactions.length; j++){ + accSender = findAccount(aTransactions[j].sender, accounts); + if(accSender == undefined){ + console.log('validateBlockTransactions: no account found.'); + return false; + } if (aTransactions[j].amount > accSender.available) { console.log('The sender does not have enough coins. tx: ' + aTransactions[j].id); return false; @@ -390,6 +404,7 @@ const getCoinbaseTransaction = (miner: string): Transaction => { const t = new Transaction("coinbase", miner, COINBASE_AMOUNT); t.timestamp = getCurrentTimestamp(); t.id = getTransactionId(t); + t.signature = ''; return t; }; @@ -464,30 +479,38 @@ const updateAccounts = (aTransactions: Transaction[], accounts: Account[]): Acco amt = aTransactions[i].amount; now = getCurrentTimestamp(); if(aTransactions[i].sender !== "coinbase"){ - if (!exsitAccount(aTransactions[i].sender, accounts)) { + if (!existAccount(aTransactions[i].sender, accounts)) { createAccount(aTransactions[i].sender, accounts); } accSender = findAccount(aTransactions[i].sender, accounts); + if(accSender == undefined){ + console.log('updateAccounts: no account found.'); + return undefined; + } thSender = new TxHistory(aTransactions[i].receiver, -amt); thSender.id = aTransactions[i].id; thSender.timestamp = aTransactions[i].timestamp; thSender.prevBalance = accSender.balance; accSender.balance -= amt; thSender.afterBalance = accSender.balance; - accSender.txHistory = _(accSender.txHistory).filter((th: TxHistory) => {th.timsstamp < (now + ACCOUNT_PURGE_PERIOD)}).push(thSender); + accSender.txHistory = _(accSender.txHistory).filter((th: TxHistory) => {return (th.timestamp < (now + ACCOUNT_PURGE_PERIOD))}).push(thSender).value(); //clean txHistory at the same time. } - if (!exsitAccount(aTransactions[i].receiver, accounts)) { + if (!existAccount(aTransactions[i].receiver, accounts)) { createAccount(aTransactions[i].receiver, accounts); } accReceiver = findAccount(aTransactions[i].receiver, accounts); + if(accReceiver == undefined){ + console.log('validateTransaction: no account found.'); + return undefined; + } thReceiver = new TxHistory(aTransactions[i].sender, amt); thReceiver.id = aTransactions[i].id; thReceiver.timestamp = aTransactions[i].timestamp; thReceiver.prevBalance = accReceiver.balance; accReceiver.balance += amt; - thReceiver.afterBalance = accSender.balance; - accReceiver.txHistory = _(accReceiver.txHistory).filter((th: TxHistory) => {th.timsstamp < (now + ACCOUNT_PURGE_PERIOD)}).push(thReceiver); + thReceiver.afterBalance = accReceiver.balance; + accReceiver.txHistory = _(accReceiver.txHistory).filter((th: TxHistory) => {return (th.timestamp < (now + ACCOUNT_PURGE_PERIOD))}).push(thReceiver).value(); //clean txHistory at the same time. } return accounts;//check again @@ -612,7 +635,7 @@ const isValidTransactionStructure = (transaction: Transaction) => { console.log('transaction amount missing'); return false; } - if (typeof transaction.timsstamp !== 'number') { + if (typeof transaction.timestamp !== 'number') { console.log('transaction timestamp missing'); return false; } @@ -650,7 +673,7 @@ export { */ export { processTransactions, signTransaction, getTransactionId, isValidAddress, validateTransaction, - Account, getCoinbaseTransaction, getPublicKey, hasDuplicates, + Account, findAccount, createAccount, getCoinbaseTransaction, getPublicKey, hasDuplicates, Transaction }; // @@ -661,6 +684,7 @@ export { //-TxOut // //signTxIn = (transaction: Transaction, txInIndex: number, +// privateKey: string, aUnspentTxOuts: UnspentTxOut[]): string => { //signTransaction = (transaction: Transaction, privateKey: string): string => { // //processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number) diff --git a/dew/src/transactionPool.ts b/dew/src/transactionPool.ts index f3cbcae..cbc82b9 100644 --- a/dew/src/transactionPool.ts +++ b/dew/src/transactionPool.ts @@ -1,7 +1,7 @@ import * as _ from 'lodash'; //import {Transaction, TxIn, UnspentTxOut, validateTransaction} from './transaction'; -import {Transaction, Account, validateTransaction} from './transaction'; +import {Transaction, Account, findAccount, validateTransaction} from './transaction'; let transactionPool: Transaction[] = []; @@ -26,13 +26,13 @@ const addToTransactionPool = (tx: Transaction, unspentTxOuts: UnspentTxOut[]) => const addToTransactionPool = (tx: Transaction, accounts: Account[]) => { if (!validateTransaction(tx, accounts)) { - throw Error('Trying to add invalid tx to pool'); + throw Error('Trying to add invalid tx to pool. Tx: ' + tx.id); } if (!isValidTxForPool(tx, transactionPool, accounts)) { - throw Error('Trying to add invalid tx to pool'); + throw Error('Tx is not valid for the pool, Tx: ' + tx.id); } - console.log('adding to txPool: %s', JSON.stringify(tx)); + //console.log('adding to txPool: %s', JSON.stringify(tx)); transactionPool.push(tx); }; @@ -62,32 +62,41 @@ const updateTransactionPool = (unspentTxOuts: UnspentTxOut[]) => { } }; */ -const updateTransactionPool = (accounts: Account[]) => { - const txIds: number[] = _(transactionPool) - .map((tx) => tx.id) - .value(); +const updateTransactionPoolReplace = (accounts: Account[]) => { + var accSender; - if (hasDuplicates(txIds)) { - console.log('Transactions in block are duplicated.'); - return false; - } + transactionPool = _(transactionPool).uniqBy('id').filter(tx => validateTransaction(tx, accounts)).value(); for(var i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } - for(var j=0; j < aTransactions.length; j++){ - accSender = findAccount(aTransactions[j].sender); - if (aTransactions[j].amount > accSender.available) { - console.log('The sender does not have enough coins. tx: ' + aTransactions[j].id); - return false; + const invalidTxs = []; + for (const tx of transactionPool) { + accSender = findAccount(tx.sender, accounts); + if(accSender == undefined){ + console.log('updateTransactionPool: no account found.'); + return false; } - accSender.available -=aTransactions[j].amount; + if (tx.amount > accSender.available) { + console.log('The sender does not have enough coins. Transaction be removed from pool. tx: ' + tx.id); + invalidTxs.push(tx); + }else{ + accSender.available -=tx.amount; + } + } + if (invalidTxs.length > 0) { + console.log('removing the following transactions from txPool: %s', JSON.stringify(invalidTxs)); + transactionPool = _.without(transactionPool, ...invalidTxs); } - // all but coinbase transactions - const normalTransactions: Transaction[] = aTransactions.slice(1); - return normalTransactions.map((tx) => validateTransaction(tx, accounts)) - .reduce((a, b) => (a && b), true); - transactionPool = _(transactionPool).filter(tx => validateTransaction(tx, accounts)); +}; +const updateTransactionPool = (transactions: Transaction[]) => { + //console.log('tansactionPool: '+JSON.stringify(transactionPool)); + if (transactions.length > 0) { + //console.log('removing the following transactions from txPool: %s', JSON.stringify(transactions)); + var txIDs: string[] = _.map(transactions, (tx: Transaction) => tx.id); + transactionPool = _.filter(transactionPool, (tx: Transaction) => !_.includes(txIDs, tx.id)); + } + //console.log('tansactionPool: '+JSON.stringify(transactionPool)); }; /* @@ -118,22 +127,40 @@ const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): bo return true; }; */ -const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): boolean => { - const txPoolIns: TxIn[] = getTxPoolIns(aTtransactionPool); +// This transaction tx has been validated in another function. id duplicate was checked in validation. +const isValidTxForPool = (tx: Transaction, aTransactionPool: Transaction[], accounts: Account[]): boolean => { + var accSender: Account; - const containsTxIn = (txIns: TxIn[], txIn: TxIn) => { - return _.find(txPoolIns, ((txPoolIn) => { - return txIn.txOutIndex === txPoolIn.txOutIndex && txIn.txOutId === txPoolIn.txOutId; - })); - }; - - for (const txIn of tx.txIns) { - if (containsTxIn(txPoolIns, txIn)) { - console.log('txIn already found in the txPool'); + for(var i=0; i < accounts.length; i++){ + accounts[i].available = accounts[i].balance; + } + for (const trx of aTransactionPool) { + if(tx.id == trx.id){ + console.log('The transaction is duplicated with the existing transaction pool. trx: ' + trx.id); + return false; + } + accSender = findAccount(trx.sender, accounts); + if(accSender == undefined){ + console.log('isValideTxFor Pool: no account found.'); + return false; + } + if (trx.amount > accSender.available) { + console.log('The sender does not have enough coins. The existing transaction pool has problems. trx: ' + trx.id); return false; + }else{ + accSender.available -= trx.amount; } } + accSender = findAccount(tx.sender, accounts); + if(accSender == undefined){ + console.log('isValidTxForPool: no account found.'); + return false; + } + if (tx.amount > accSender.available) { + console.log('The transaction is not valid for the pool. tx: ' + tx.id); + return false; + } return true; }; -export {addToTransactionPool, getTransactionPool, updateTransactionPool}; +export {addToTransactionPool, getTransactionPool, updateTransactionPool, updateTransactionPoolReplace}; diff --git a/dew/src/wallet.ts b/dew/src/wallet.ts index 315a939..e0ed913 100644 --- a/dew/src/wallet.ts +++ b/dew/src/wallet.ts @@ -1,7 +1,11 @@ import {ec} from 'elliptic'; import {existsSync, readFileSync, unlinkSync, writeFileSync} from 'fs'; import * as _ from 'lodash'; -import {getPublicKey, getTransactionId, signTxIn, Transaction, TxIn, TxOut, UnspentTxOut} from './transaction'; +//import {getPublicKey, getTransactionId, signTxIn, Transaction, TxIn, TxOut, UnspentTxOut} from './transaction'; +import {getPublicKey, getTransactionId, signTransaction, Transaction, Account, findAccount, createAccount} from './transaction'; + +//dewcoin +import {getCurrentTimestamp, getAccounts} from './blockchain'; const EC = new ec('secp256k1'); const privateKeyLocation = process.env.PRIVATE_KEY || 'node/wallet/private_key'; @@ -24,6 +28,8 @@ const generatePrivateKey = (): string => { }; const initWallet = () => { + createAccount(getPublicFromWallet(), getAccounts()); + console.log('an account was created.'); // let's not override existing private keys if (existsSync(privateKeyLocation)) { return; @@ -40,16 +46,29 @@ const deleteWallet = () => { } }; +/* const getBalance = (address: string, unspentTxOuts: UnspentTxOut[]): number => { return _(findUnspentTxOuts(address, unspentTxOuts)) .map((uTxO: UnspentTxOut) => uTxO.amount) .sum(); }; +*/ +const getBalance = (address: string, accounts: Account[]): number => { + var acct: Account = findAccount(address, accounts); + if(acct == undefined){ + console.log('getBalance: no account found.'); + return 0; + } + return acct.balance; +}; +/* const findUnspentTxOuts = (ownerAddress: string, unspentTxOuts: UnspentTxOut[]) => { return _.filter(unspentTxOuts, (uTxO: UnspentTxOut) => uTxO.address === ownerAddress); }; +*/ +/* const findTxOutsForAmount = (amount: number, myUnspentTxOuts: UnspentTxOut[]) => { let currentAmount = 0; const includedUnspentTxOuts = []; @@ -66,7 +85,9 @@ const findTxOutsForAmount = (amount: number, myUnspentTxOuts: UnspentTxOut[]) => ' Required amount:' + amount + '. Available unspentTxOuts:' + JSON.stringify(myUnspentTxOuts); throw Error(eMsg); }; +*/ +/* const createTxOuts = (receiverAddress: string, myAddress: string, amount, leftOverAmount: number) => { const txOut1: TxOut = new TxOut(receiverAddress, amount); if (leftOverAmount === 0) { @@ -76,7 +97,9 @@ const createTxOuts = (receiverAddress: string, myAddress: string, amount, leftOv return [txOut1, leftOverTx]; } }; +*/ +/* const filterTxPoolTxs = (unspentTxOuts: UnspentTxOut[], transactionPool: Transaction[]): UnspentTxOut[] => { const txIns: TxIn[] = _(transactionPool) .map((tx: Transaction) => tx.txIns) @@ -97,7 +120,9 @@ const filterTxPoolTxs = (unspentTxOuts: UnspentTxOut[], transactionPool: Transac return _.without(unspentTxOuts, ...removable); }; +*/ +/* const createTransaction = (receiverAddress: string, amount: number, privateKey: string, unspentTxOuts: UnspentTxOut[], txPool: Transaction[]): Transaction => { @@ -131,6 +156,32 @@ const createTransaction = (receiverAddress: string, amount: number, privateKey: return tx; }; +*/ +const createTransaction = (receiverAddress: string, amount: number, privateKey: string, + accounts: Account[], txPool: Transaction[]): Transaction => { + //console.log('txPool: %s', JSON.stringify(txPool)); + const myAddress: string = getPublicKey(privateKey); + + const myAccount: Account = findAccount(myAddress, accounts); + + if(amount > myAccount.balance){ + console.log('No enough coins.'); + return undefined; + } + + const tx: Transaction = new Transaction(myAddress, receiverAddress, amount); + tx.timestamp = getCurrentTimestamp(); + tx.id = getTransactionId(tx); + tx.signature = signTransaction(tx, privateKey); + //what is the role of transaction pool? + return tx; +}; + +/* export {createTransaction, getPublicFromWallet, getPrivateFromWallet, getBalance, generatePrivateKey, initWallet, deleteWallet, findUnspentTxOuts}; + +*/ +export {createTransaction, getPublicFromWallet, + getPrivateFromWallet, getBalance, generatePrivateKey, initWallet, deleteWallet}; From 2153ff4550722b137df1622ef6e0200f89daf261 Mon Sep 17 00:00:00 2001 From: ywang Date: Tue, 7 Aug 2018 06:25:21 -0400 Subject: [PATCH 13/36] licenses and ignore --- cloud/.gitignore | 5 + License.txt => cloud/License.txt | 0 dew/.gitignore | 5 + dew/License.txt | 201 +++++++++++++++++++++++++++++++ 4 files changed, 211 insertions(+) create mode 100644 cloud/.gitignore rename License.txt => cloud/License.txt (100%) create mode 100644 dew/.gitignore create mode 100644 dew/License.txt diff --git a/cloud/.gitignore b/cloud/.gitignore new file mode 100644 index 0000000..e5d4fe4 --- /dev/null +++ b/cloud/.gitignore @@ -0,0 +1,5 @@ +node_modules +npm-debug.log +.idea +src/*.js +src/*.map diff --git a/License.txt b/cloud/License.txt similarity index 100% rename from License.txt rename to cloud/License.txt diff --git a/dew/.gitignore b/dew/.gitignore new file mode 100644 index 0000000..e5d4fe4 --- /dev/null +++ b/dew/.gitignore @@ -0,0 +1,5 @@ +node_modules +npm-debug.log +.idea +src/*.js +src/*.map diff --git a/dew/License.txt b/dew/License.txt new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/dew/License.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 160d9c047bd1e72bd8d3b4aa3c926001a7a532cf Mon Sep 17 00:00:00 2001 From: ywang Date: Tue, 7 Aug 2018 07:20:41 -0400 Subject: [PATCH 14/36] invalid tx dealt with --- dew/src/blockchain.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dew/src/blockchain.ts b/dew/src/blockchain.ts index 558ef33..c6dac16 100644 --- a/dew/src/blockchain.ts +++ b/dew/src/blockchain.ts @@ -170,6 +170,8 @@ const generatenextBlockWithTransaction = (receiverAddress: string, amount: numbe }; */ const generatenextBlockWithTransaction = (receiverAddress: string, amount: number) => { + var blockData: Transaction[]; + if (!isValidAddress(receiverAddress)) { throw Error('invalid address'); } @@ -178,7 +180,12 @@ const generatenextBlockWithTransaction = (receiverAddress: string, amount: numbe } const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet()); const tx: Transaction = createTransaction(receiverAddress, amount, getPrivateFromWallet(), getAccounts(), getTransactionPool()); - const blockData: Transaction[] = [coinbaseTx, tx]; + if(tx == undefined){ + blockData = [coinbaseTx]; + console.log('The transaction is invalid. The block was mined.'); + }else{ + blockData = [coinbaseTx, tx]; + } return generateRawNextBlock(blockData); }; From 718146f907b11b3481828403b24221327a569da9 Mon Sep 17 00:00:00 2001 From: ywang Date: Tue, 7 Aug 2018 07:21:48 -0400 Subject: [PATCH 15/36] update readme --- dew/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dew/README.md b/dew/README.md index 2951e42..acb7fd0 100644 --- a/dew/README.md +++ b/dew/README.md @@ -69,12 +69,13 @@ curl http://localhost:3001/account/:address ##### Mine a block +The block will contain the transactions in the pool. ``` curl -X POST http://localhost:3001/mineBlock ``` -##### Send transaction +##### Send a transaction to the pool ``` curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction ``` @@ -83,7 +84,8 @@ curl -H "Content-type: application/json" --data "{\"address\": \"04bfcab8722991a -##### Mine transaction +##### Mine a block with a transaction +If the transaction is invalid, the block will still be mined. ``` curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction ``` @@ -102,6 +104,6 @@ curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:600 #### Stop the server ``` -curl http://localhost:3001/stop +curl -X POST http://localhost:3001/stop ``` From 514e16b632065afde4ea40947169863b7c172e7d Mon Sep 17 00:00:00 2001 From: ywang Date: Tue, 7 Aug 2018 07:23:49 -0400 Subject: [PATCH 16/36] ignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 577f66e..c39b80a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ dew/.idea dew/src/*.js dew/src/*.map +*.js +*.map +*.js +*.map From 19fabf4adb666266e3ae9a871fc1351a119cbe65 Mon Sep 17 00:00:00 2001 From: ywang Date: Tue, 7 Aug 2018 13:58:14 -0400 Subject: [PATCH 17/36] fully working, similar to original. cloud-dew arechitecture account-oriented transactions account history within a period --- cloud/src/blockchain.ts | 191 +++++++++++++++++- cloud/src/main.ts | 54 ++++- cloud/src/p2p.ts | 3 +- cloud/src/transaction.ts | 368 ++++++++++++++++++++++++++++++++++- cloud/src/transactionPool.ts | 101 +++++++++- cloud/src/wallet.ts | 55 +++++- dew/README.md | 6 +- dew/src/blockchain.ts | 10 +- dew/src/p2p.ts | 3 +- dew/src/transaction.ts | 4 +- dew/src/transactionPool.ts | 2 + dew/src/wallet.ts | 6 +- 12 files changed, 768 insertions(+), 35 deletions(-) diff --git a/cloud/src/blockchain.ts b/cloud/src/blockchain.ts index 85aedc3..bd1e016 100644 --- a/cloud/src/blockchain.ts +++ b/cloud/src/blockchain.ts @@ -1,12 +1,20 @@ import * as CryptoJS from 'crypto-js'; import * as _ from 'lodash'; import {broadcastLatest, broadCastTransactionPool} from './p2p'; + +/* import { getCoinbaseTransaction, isValidAddress, processTransactions, Transaction, UnspentTxOut } from './transaction'; -import {addToTransactionPool, getTransactionPool, updateTransactionPool} from './transactionPool'; +*/ +import { + getCoinbaseTransaction, isValidAddress, processTransactions, Transaction, Account, findAccount, getTransactionId +} from './transaction'; + +import {addToTransactionPool, getTransactionPool, updateTransactionPool, updateTransactionPoolReplace} from './transactionPool'; import {hexToBinary} from './util'; -import {createTransaction, findUnspentTxOuts, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; +//import {createTransaction, findUnspentTxOuts, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; +import {createTransaction, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; class Block { @@ -30,6 +38,9 @@ class Block { } } +const getCurrentTimestamp = (): number => Math.round(new Date().getTime() / 1000); + +/* const genesisTransaction = { 'txIns': [{'signature': '', 'txOutId': '', 'txOutIndex': 0}], 'txOuts': [{ @@ -38,25 +49,47 @@ const genesisTransaction = { }], 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3' }; +*/ +const genesisTransaction = new Transaction('coinbase', + '04c0a0903203a721fa43581cc53c9361862e2e5522310909fbfbf14203371c464f5bdbba42e16349e237e1adf65952d8301e071a40a76b1709954c8f0e3f253b2c', 50); +genesisTransaction.timestamp = 1533641911; +genesisTransaction.id = getTransactionId(genesisTransaction); +genesisTransaction.signature = ''; +/* const genesisBlock: Block = new Block( 0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1465154705, [genesisTransaction], 0, 0 ); +*/ +const genesisBlock: Block = new Block( + 0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1533641911, [genesisTransaction], 0, 0 +); let blockchain: Block[] = [genesisBlock]; // the unspent txOut of genesis block is set to unspentTxOuts on startup -let unspentTxOuts: UnspentTxOut[] = processTransactions(blockchain[0].data, [], 0); +//let unspentTxOuts: UnspentTxOut[] = processTransactions(blockchain[0].data, []); +let accounts: Account[] = processTransactions(blockchain[0].data, []); const getBlockchain = (): Block[] => blockchain; -const getUnspentTxOuts = (): UnspentTxOut[] => _.cloneDeep(unspentTxOuts); +//const getUnspentTxOuts = (): UnspentTxOut[] => _.cloneDeep(unspentTxOuts); +//const getAccounts = (): Account[] => _.cloneDeep(accounts); +const getAccounts = (): Account[] => accounts; + + // and txPool should be only updated at the same time +/* const setUnspentTxOuts = (newUnspentTxOut: UnspentTxOut[]) => { console.log('replacing unspentTxouts with: %s', newUnspentTxOut); unspentTxOuts = newUnspentTxOut; }; +*/ +const setAccounts = (newAccount: Account[]) => { + //console.log('replacing accounts with: %s', newAccount); + accounts = newAccount; +}; const getLatestBlock = (): Block => blockchain[blockchain.length - 1]; @@ -88,8 +121,7 @@ const getAdjustedDifficulty = (latestBlock: Block, aBlockchain: Block[]) => { } }; -const getCurrentTimestamp = (): number => Math.round(new Date().getTime() / 1000); - +//// const generateRawNextBlock = (blockData: Transaction[]) => { const previousBlock: Block = getLatestBlock(); const difficulty: number = getDifficulty(getBlockchain()); @@ -106,16 +138,29 @@ const generateRawNextBlock = (blockData: Transaction[]) => { }; // gets the unspent transaction outputs owned by the wallet +/* const getMyUnspentTransactionOutputs = () => { return findUnspentTxOuts(getPublicFromWallet(), getUnspentTxOuts()); }; +*/ +const getMyAccount = () => { + return findAccount(getPublicFromWallet(), getAccounts()); +}; +/* const generateNextBlock = () => { const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet(), getLatestBlock().index + 1); const blockData: Transaction[] = [coinbaseTx].concat(getTransactionPool()); return generateRawNextBlock(blockData); }; +*/ +const generateNextBlock = () => { + const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet()); + const blockData: Transaction[] = [coinbaseTx].concat(getTransactionPool()); + return generateRawNextBlock(blockData); +}; +/* const generatenextBlockWithTransaction = (receiverAddress: string, amount: number) => { if (!isValidAddress(receiverAddress)) { throw Error('invalid address'); @@ -128,6 +173,26 @@ const generatenextBlockWithTransaction = (receiverAddress: string, amount: numbe const blockData: Transaction[] = [coinbaseTx, tx]; return generateRawNextBlock(blockData); }; +*/ +const generatenextBlockWithTransaction = (receiverAddress: string, amount: number) => { + var blockData: Transaction[]; + + if (!isValidAddress(receiverAddress)) { + throw Error('invalid address'); + } + if (typeof amount !== 'number') { + throw Error('invalid amount'); + } + const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet()); + const tx: Transaction = createTransaction(receiverAddress, amount, getPrivateFromWallet(), getAccounts(), getTransactionPool()); + if(tx == undefined){ + blockData = [coinbaseTx]; + console.log('The transaction is invalid. The block was mined.'); + }else{ + blockData = [coinbaseTx, tx]; + } + return generateRawNextBlock(blockData); +}; const findBlock = (index: number, previousHash: string, timestamp: number, data: Transaction[], difficulty: number): Block => { let nonce = 0; @@ -140,16 +205,34 @@ const findBlock = (index: number, previousHash: string, timestamp: number, data: } }; +/* const getAccountBalance = (): number => { return getBalance(getPublicFromWallet(), getUnspentTxOuts()); }; +*/ +const getAccountBalance = (): number => { + return getBalance(getPublicFromWallet(), getAccounts()); +}; +/* const sendTransaction = (address: string, amount: number): Transaction => { const tx: Transaction = createTransaction(address, amount, getPrivateFromWallet(), getUnspentTxOuts(), getTransactionPool()); addToTransactionPool(tx, getUnspentTxOuts()); broadCastTransactionPool(); return tx; }; +*/ +const sendTransaction = (address: string, amount: number): Transaction => { + const tx: Transaction = createTransaction(address, amount, getPrivateFromWallet(), getAccounts(), getTransactionPool()); + if(tx == undefined){ + console.log('This transaction cannot be created.'); + return undefined; + }else{ + addToTransactionPool(tx, getAccounts()); + broadCastTransactionPool(); + return tx; + } +}; const calculateHashForBlock = (block: Block): string => calculateHash(block.index, block.previousHash, block.timestamp, block.data, block.difficulty, block.nonce); @@ -225,6 +308,7 @@ const hashMatchesDifficulty = (hash: string, difficulty: number): boolean => { /* Checks if the given blockchain is valid. Return the unspent txOuts if the chain is valid */ +/* const isValidChain = (blockchainToValidate: Block[]): UnspentTxOut[] => { console.log('isValidChain:'); console.log(JSON.stringify(blockchainToValidate)); @@ -235,10 +319,10 @@ const isValidChain = (blockchainToValidate: Block[]): UnspentTxOut[] => { if (!isValidGenesis(blockchainToValidate[0])) { return null; } - /* - Validate each block in the chain. The block is valid if the block structure is valid - and the transaction are valid - */ + + //Validate each block in the chain. The block is valid if the block structure is valid + // and the transaction are valid + let aUnspentTxOuts: UnspentTxOut[] = []; for (let i = 0; i < blockchainToValidate.length; i++) { @@ -255,7 +339,39 @@ const isValidChain = (blockchainToValidate: Block[]): UnspentTxOut[] => { } return aUnspentTxOuts; }; +*/ +const isValidChain = (blockchainToValidate: Block[]): Account[] => { + console.log('isValidChain:'); + console.log(JSON.stringify(blockchainToValidate)); + const isValidGenesis = (block: Block): boolean => { + return JSON.stringify(block) === JSON.stringify(genesisBlock); + }; + + if (!isValidGenesis(blockchainToValidate[0])) { + return null; + } + /* + Validate each block in the chain. The block is valid if the block structure is valid + and the transaction are valid + */ + let accts: Account[] = []; + + for (let i = 0; i < blockchainToValidate.length; i++) { + const currentBlock: Block = blockchainToValidate[i]; + if (i !== 0 && !isValidNewBlock(blockchainToValidate[i], blockchainToValidate[i - 1])) { + return null; + } + + accts = processTransactions(currentBlock.data, accts); + if (accts === null) { + console.log('invalid transactions in blockchain'); + return null; + } + } + return accts; +}; +/* const addBlockToChain = (newBlock: Block): boolean => { if (isValidNewBlock(newBlock, getLatestBlock())) { const retVal: UnspentTxOut[] = processTransactions(newBlock.data, getUnspentTxOuts(), newBlock.index); @@ -271,7 +387,25 @@ const addBlockToChain = (newBlock: Block): boolean => { } return false; }; +*/ +const addBlockToChain = (newBlock: Block): boolean => { + if (isValidNewBlock(newBlock, getLatestBlock())) { + const retVal: Account[] = processTransactions(newBlock.data, getAccounts()); + if (retVal === null) { + console.log('block is not valid in terms of transactions'); + return false; + } else { + blockchain.push(newBlock); + setAccounts(retVal); + //updateTransactionPool(accounts); + updateTransactionPool(newBlock.data); + return true; + } + } + return false; +}; +/* const replaceChain = (newBlocks: Block[]) => { const aUnspentTxOuts = isValidChain(newBlocks); const validChain: boolean = aUnspentTxOuts !== null; @@ -286,14 +420,51 @@ const replaceChain = (newBlocks: Block[]) => { console.log('Received blockchain invalid'); } }; +*/ +const replaceChain = (newBlocks: Block[]) => { + const accts = isValidChain(newBlocks); + const validChain: boolean = accts !== null; + if (validChain && + getAccumulatedDifficulty(newBlocks) > getAccumulatedDifficulty(getBlockchain())) { + console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); + blockchain = newBlocks; + setAccounts(accts); + updateTransactionPoolReplace(accounts); + broadcastLatest(); + } else { + console.log('Received blockchain invalid'); + } +}; +/* const handleReceivedTransaction = (transaction: Transaction) => { addToTransactionPool(transaction, getUnspentTxOuts()); }; +*/ +const handleReceivedTransaction = (transaction: Transaction) => { +//console.log('***handleReceivedTransacton:***'); + addToTransactionPool(transaction, getAccounts()); +}; +/* export { Block, getBlockchain, getUnspentTxOuts, getLatestBlock, sendTransaction, generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, handleReceivedTransaction, getMyUnspentTransactionOutputs, getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain }; +*/ +export { + Block, getBlockchain, getAccounts, getLatestBlock, sendTransaction, + generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, + handleReceivedTransaction, getMyAccount, + getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain, getCurrentTimestamp +}; + +/* +getUnspentTxOuts = (): UnspentTxOut[] +getAccounts = (): Account[] + +getMyUnspentTransactionOutputs() +getMyAccount() +*/ diff --git a/cloud/src/main.ts b/cloud/src/main.ts index 75f5ae7..3be1e4d 100644 --- a/cloud/src/main.ts +++ b/cloud/src/main.ts @@ -1,12 +1,23 @@ import * as bodyParser from 'body-parser'; import * as express from 'express'; import * as _ from 'lodash'; + +/* import { Block, generateNextBlock, generatenextBlockWithTransaction, generateRawNextBlock, getAccountBalance, getBlockchain, getMyUnspentTransactionOutputs, getUnspentTxOuts, sendTransaction } from './blockchain'; +*/ +import { + Block, generateNextBlock, generatenextBlockWithTransaction, generateRawNextBlock, getAccountBalance, + getBlockchain, getMyAccount, getAccounts, sendTransaction +} from './blockchain'; + import {connectToPeers, getSockets, initP2PServer} from './p2p'; -import {UnspentTxOut} from './transaction'; + +//import {UnspentTxOut} from './transaction'; +import {Account, findAccount} from './transaction'; + import {getTransactionPool} from './transactionPool'; import {getPublicFromWallet, initWallet} from './wallet'; @@ -40,19 +51,44 @@ const initHttpServer = (myHttpPort: number) => { res.send(tx); }); + /* app.get('/address/:address', (req, res) => { const unspentTxOuts: UnspentTxOut[] = _.filter(getUnspentTxOuts(), (uTxO) => uTxO.address === req.params.address); res.send({'unspentTxOuts': unspentTxOuts}); }); + */ + app.get('/account/:address', (req, res) => { + var acc: Account = findAccount(req.params.address, getAccounts()); + if(acc == undefined){ + res.send({'Error:': "address is wrong"}); + } + res.send({'Account': acc}); + }); + /* app.get('/unspentTransactionOutputs', (req, res) => { res.send(getUnspentTxOuts()); }); + */ + //display all accounts + app.get('/accounts', (req, res) => { + res.send(getAccounts()); + }); + /* app.get('/myUnspentTransactionOutputs', (req, res) => { res.send(getMyUnspentTransactionOutputs()); }); + */ + app.get('/myaccount', (req, res) => { + var acc: Account = findAccount(getPublicFromWallet(), getAccounts()); + if(acc == undefined){ + res.send({'Error': 'No account was found.'}) + }else{ + res.send({'My Account': acc}); + } + }); app.post('/mineRawBlock', (req, res) => { if (req.body.data == null) { @@ -76,12 +112,16 @@ const initHttpServer = (myHttpPort: number) => { } }); - app.get('/balance', (req, res) => { - const balance: number = getAccountBalance(); - res.send({'balance': balance}); + app.get('/mybalance', (req, res) => { + var acc: Account = findAccount(getPublicFromWallet(), getAccounts()); + if(acc == undefined){ + res.send({'Error:': "No such account."}); + }else{ + res.send({'Balance': acc.balance}); + } }); - app.get('/address', (req, res) => { + app.get('/myaddress', (req, res) => { const address: string = getPublicFromWallet(); res.send({'address': address}); }); @@ -114,14 +154,14 @@ const initHttpServer = (myHttpPort: number) => { } }); - app.get('/transactionPool', (req, res) => { + app.get('/transactionpool', (req, res) => { res.send(getTransactionPool()); }); app.get('/peers', (req, res) => { res.send(getSockets().map((s: any) => s._socket.remoteAddress + ':' + s._socket.remotePort)); }); - app.post('/addPeer', (req, res) => { + app.post('/addpeer', (req, res) => { connectToPeers(req.body.peer); res.send(); }); diff --git a/cloud/src/p2p.ts b/cloud/src/p2p.ts index d15c8de..4ed3a68 100644 --- a/cloud/src/p2p.ts +++ b/cloud/src/p2p.ts @@ -62,7 +62,7 @@ const initMessageHandler = (ws: WebSocket) => { console.log('could not parse received JSON message: ' + data); return; } - console.log('Received message: %s', JSON.stringify(message)); + console.log('[Received message: %s', JSON.stringify(message)); switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -102,6 +102,7 @@ const initMessageHandler = (ws: WebSocket) => { } catch (e) { console.log(e); } + console.log('message processing]'); }); }; diff --git a/cloud/src/transaction.ts b/cloud/src/transaction.ts index 277c287..6d73843 100644 --- a/cloud/src/transaction.ts +++ b/cloud/src/transaction.ts @@ -2,10 +2,18 @@ import * as CryptoJS from 'crypto-js'; import * as ecdsa from 'elliptic'; import * as _ from 'lodash'; -const ec = new ecdsa.ec('secp256k1'); +//dewcoin +import {getCurrentTimestamp} from './blockchain'; +import {getTransactionPool} from './transactionPool';//debug +const ec = new ecdsa.ec('secp256k1'); const COINBASE_AMOUNT: number = 50; +//dewcoin +const ACCOUNT_ACTIVE_PERIOD: number = 60*60*24*31; //31 days. +const ACCOUNT_PURGE_PERIOD: number = 60*60*24*32; //32 days. + +/* class UnspentTxOut { public readonly txOutId: string; public readonly txOutIndex: number; @@ -19,7 +27,24 @@ class UnspentTxOut { this.amount = amount; } } +*/ +class Account { + public readonly address: string; + public balance: number; + public available: number; + public txHistory: TxHistory[]; + + constructor(address: string) { + this.address = address; + this.balance = 0; + this.available = 0; + this.txHistory = []; + } +} + + +/* class TxIn { public txOutId: string; public txOutIndex: number; @@ -35,7 +60,6 @@ class TxOut { this.amount = amount; } } - class Transaction { public id: string; @@ -43,7 +67,36 @@ class Transaction { public txIns: TxIn[]; public txOuts: TxOut[]; } +*/ +class Transaction { + public id: string; + public sender: string; + public receiver: string; + public amount: number; + public timestamp: number; + public signature: string; + + constructor(sender: string, receiver: string, amount: number) { + this.sender = sender; + this.receiver = receiver; + this.amount = amount; + } +} +class TxHistory { + public id: string; + public txAccount: string; //the account that this transaction involvs. + public prevBalance: number; + public amount: number; // plus or minus. reflect the change of the balance. + public afterBalance: number; + public timestamp: number; + + constructor(txAccount: string, amount: number) { + this.txAccount = txAccount; + this.amount = amount; + } +} +/* const getTransactionId = (transaction: Transaction): string => { const txInContent: string = transaction.txIns .map((txIn: TxIn) => txIn.txOutId + txIn.txOutIndex) @@ -55,7 +108,14 @@ const getTransactionId = (transaction: Transaction): string => { return CryptoJS.SHA256(txInContent + txOutContent).toString(); }; +*/ +const getTransactionId = (transaction: Transaction): string => { + return CryptoJS.SHA256(transaction.sender + transaction.receiver + transaction.amount + transaction.timestamp).toString(); +}; + + +/* const validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean => { if (!isValidTransactionStructure(transaction)) { @@ -90,7 +150,60 @@ const validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTx return true; }; +*/ +const existAccount = (address: string, accounts: Account[]): boolean => { + //console.log('address: ' + address); + //console.log('accounts: '+ JSON.stringify(accounts)); + return _(accounts).map((acc: Account) => acc.address).includes(address); +} +const createAccount = (address: string, accounts: Account[]): boolean => { + var acc: Account = new Account(address); + accounts.push(acc); + return true; +} +const findAccount = (address: string, accounts: Account[]): Account => { + var account: Account = _.find(accounts, (acc: Account) => {return acc.address == address}); + return account; +} +const validateTransaction = (transaction: Transaction, accounts: Account[]): boolean => { + + if (!isValidTransactionStructure(transaction)) { + return false; + } + if (getTransactionId(transaction) !== transaction.id) { + console.log('validateTransaction: invalid tx id: ' + transaction.id); + console.log(getTransactionId(transaction)); + return false; + } + + const hasValidSignature: boolean = validateSignature(transaction); + if (!hasValidSignature) { + console.log('The signature is invalid in tx: ' + transaction.id); + return false; + } + if (transaction.timestamp < (getCurrentTimestamp() - ACCOUNT_ACTIVE_PERIOD)){ + console.log('The transaction is too old. tx: ' + transaction.id); + return false; + } + var accSender: Account = findAccount(transaction.sender, accounts); + if(accSender == undefined){ + console.log('validateTransaction: no account found.'); + return false; + } + if (_(accSender.txHistory).map((th: TxHistory) => {return th.id}).includes(transaction.id)){ + console.log(JSON.stringify(getTransactionPool())); + console.log('validateTransaction: The transaction is duplicated with the chain. tx: ' + transaction.id); + console.log(JSON.stringify(accSender.txHistory)); + return false; + } + + return true; +}; + + + +/* const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number): boolean => { const coinbaseTx = aTransactions[0]; if (!validateCoinbaseTx(coinbaseTx, blockIndex)) { @@ -98,7 +211,6 @@ const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: return false; } - // check for duplicate txIns. Each txIn can be included only once const txIns: TxIn[] = _(aTransactions) .map((tx) => tx.txIns) .flatten() @@ -114,7 +226,47 @@ const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: .reduce((a, b) => (a && b), true); }; +*/ +const validateBlockTransactions = (aTransactions: Transaction[], accounts: Account[]): boolean => { + var accSender: Account; + + const coinbaseTx = aTransactions[0]; + if (!validateCoinbaseTx(coinbaseTx)) { + console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); + return false; + } + const txIds: string[] = _(aTransactions) + .map((tx) => tx.id) + .value(); + if (hasDuplicates(txIds)) { + console.log('Transactions in block are duplicated.'); + return false; + } + + for(var i=0; i < accounts.length; i++){ + accounts[i].available = accounts[i].balance; + } + for(var j=1; j < aTransactions.length; j++){ + accSender = findAccount(aTransactions[j].sender, accounts); + if(accSender == undefined){ + console.log('validateBlockTransactions: no account found.'); + return false; + } + if (aTransactions[j].amount > accSender.available) { + console.log('The sender does not have enough coins. tx: ' + aTransactions[j].id); + return false; + } + accSender.available -=aTransactions[j].amount; + } + // all but coinbase transactions + const normalTransactions: Transaction[] = aTransactions.slice(1); + return normalTransactions.map((tx) => validateTransaction(tx, accounts)) + .reduce((a, b) => (a && b), true); +}; + + +/* const hasDuplicates = (txIns: TxIn[]): boolean => { const groups = _.countBy(txIns, (txIn: TxIn) => txIn.txOutId + txIn.txOutIndex); return _(groups) @@ -128,7 +280,23 @@ const hasDuplicates = (txIns: TxIn[]): boolean => { }) .includes(true); }; +*/ +const hasDuplicates = (names: string[]): boolean => { + const groups = _.countBy(names); + return _(groups) + .map((value, key) => { + if (value > 1) { + console.log('duplicate string: ' + key); + return true; + } else { + return false; + } + }) + .includes(true); +}; + +/* const validateCoinbaseTx = (transaction: Transaction, blockIndex: number): boolean => { if (transaction == null) { console.log('the first transaction in the block must be coinbase transaction'); @@ -156,7 +324,30 @@ const validateCoinbaseTx = (transaction: Transaction, blockIndex: number): boole } return true; }; +*/ +const validateCoinbaseTx = (transaction: Transaction): boolean => { + if (transaction == null) { + console.log('the first transaction in the block must be coinbase transaction'); + return false; + } + if (getTransactionId(transaction) !== transaction.id) { + console.log('invalid coinbase tx id: ' + transaction.id); + return false; + } + if (transaction.sender !== "coinbase") { + console.log('It is not a coinbase transaction'); + return; + } + if (transaction.amount !== COINBASE_AMOUNT) { + console.log('invalid coinbase amount in coinbase transaction'); + return false; + } + return true; +}; + + +/* const validateTxIn = (txIn: TxIn, transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean => { const referencedUTxOut: UnspentTxOut = aUnspentTxOuts.find((uTxO) => uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex); @@ -174,15 +365,30 @@ const validateTxIn = (txIn: TxIn, transaction: Transaction, aUnspentTxOuts: Unsp } return true; }; +*/ +const validateSignature = (transaction: Transaction): boolean => { + const key = ec.keyFromPublic(transaction.sender, 'hex'); + const validSignature: boolean = key.verify(transaction.id, transaction.signature); + if (!validSignature) { + console.log('invalid tx signature: %s txId: %s address: %s', transaction.signature, transaction.id, transaction.sender); + return false; + } + return true; +}; + + +/* const getTxInAmount = (txIn: TxIn, aUnspentTxOuts: UnspentTxOut[]): number => { return findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts).amount; }; - const findUnspentTxOut = (transactionId: string, index: number, aUnspentTxOuts: UnspentTxOut[]): UnspentTxOut => { return aUnspentTxOuts.find((uTxO) => uTxO.txOutId === transactionId && uTxO.txOutIndex === index); }; +*/ + +/* const getCoinbaseTransaction = (address: string, blockIndex: number): Transaction => { const t = new Transaction(); const txIn: TxIn = new TxIn(); @@ -195,7 +401,17 @@ const getCoinbaseTransaction = (address: string, blockIndex: number): Transactio t.id = getTransactionId(t); return t; }; +*/ +const getCoinbaseTransaction = (miner: string): Transaction => { + const t = new Transaction("coinbase", miner, COINBASE_AMOUNT); + t.timestamp = getCurrentTimestamp(); + t.id = getTransactionId(t); + t.signature = ''; + return t; +}; + +/* const signTxIn = (transaction: Transaction, txInIndex: number, privateKey: string, aUnspentTxOuts: UnspentTxOut[]): string => { const txIn: TxIn = transaction.txIns[txInIndex]; @@ -218,7 +434,22 @@ const signTxIn = (transaction: Transaction, txInIndex: number, return signature; }; +*/ +const signTransaction = (transaction: Transaction, privateKey: string): string => { + const dataToSign = transaction.id; + if (getPublicKey(privateKey) !== transaction.sender) { + console.log('trying to sign an input with private' + + ' key that does not match the address'); + throw Error(); + } + const key = ec.keyFromPrivate(privateKey, 'hex'); + const signature: string = toHexString(key.sign(dataToSign).toDER()); + + return signature; +}; + +/* const updateUnspentTxOuts = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[]): UnspentTxOut[] => { const newUnspentTxOuts: UnspentTxOut[] = aTransactions .map((t) => { @@ -237,7 +468,58 @@ const updateUnspentTxOuts = (aTransactions: Transaction[], aUnspentTxOuts: Unspe return resultingUnspentTxOuts; }; +*/ +const updateAccounts = (aTransactions: Transaction[], accounts: Account[]): Account[] => { + var amt: number; + var thSender: TxHistory; + var thReceiver: TxHistory; + var accSender: Account; + var accReceiver: Account; + var now: number; + + for(var i=0; i {return (th.timestamp < (now + ACCOUNT_PURGE_PERIOD))}).push(thSender).value(); + //clean txHistory at the same time. + } + if (!existAccount(aTransactions[i].receiver, accounts)) { + createAccount(aTransactions[i].receiver, accounts); + } + accReceiver = findAccount(aTransactions[i].receiver, accounts); + if(accReceiver == undefined){ + console.log('validateTransaction: no account found.'); + return undefined; + } + thReceiver = new TxHistory(aTransactions[i].sender, amt); + thReceiver.id = aTransactions[i].id; + thReceiver.timestamp = aTransactions[i].timestamp; + thReceiver.prevBalance = accReceiver.balance; + accReceiver.balance += amt; + thReceiver.afterBalance = accReceiver.balance; + accReceiver.txHistory = _(accReceiver.txHistory).filter((th: TxHistory) => {return (th.timestamp < (now + ACCOUNT_PURGE_PERIOD))}).push(thReceiver).value(); + //clean txHistory at the same time. + } + return accounts;//check again +}; + +/* const processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number) => { if (!validateBlockTransactions(aTransactions, aUnspentTxOuts, blockIndex)) { @@ -246,6 +528,18 @@ const processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: Unspe } return updateUnspentTxOuts(aTransactions, aUnspentTxOuts); }; +*/ +const processTransactions = (aTransactions: Transaction[], accounts: Account[]) => { + + if (!validateBlockTransactions(aTransactions, accounts)) { + console.log('invalid block transactions'); + return null; + } + return updateAccounts(aTransactions, accounts); +}; + + + const toHexString = (byteArray): string => { return Array.from(byteArray, (byte: any) => { @@ -257,6 +551,8 @@ const getPublicKey = (aPrivateKey: string): string => { return ec.keyFromPrivate(aPrivateKey, 'hex').getPublic().encode('hex'); }; + +/* const isValidTxInStructure = (txIn: TxIn): boolean => { if (txIn == null) { console.log('txIn is null'); @@ -274,7 +570,6 @@ const isValidTxInStructure = (txIn: TxIn): boolean => { return true; } }; - const isValidTxOutStructure = (txOut: TxOut): boolean => { if (txOut == null) { console.log('txOut is null'); @@ -292,7 +587,11 @@ const isValidTxOutStructure = (txOut: TxOut): boolean => { return true; } }; +*/ + + +/* const isValidTransactionStructure = (transaction: Transaction) => { if (typeof transaction.id !== 'string') { console.log('transactionId missing'); @@ -320,6 +619,35 @@ const isValidTransactionStructure = (transaction: Transaction) => { } return true; }; +*/ +const isValidTransactionStructure = (transaction: Transaction) => { + if (typeof transaction.id !== 'string') { + console.log('transactionId missing'); + return false; + } + if (typeof transaction.sender !== 'string') { + console.log('transaction sender missing'); + return false; + } + if (typeof transaction.receiver !== 'string') { + console.log('transaction receiver missing'); + return false; + } + if (typeof transaction.amount !== 'number') { + console.log('transaction amount missing'); + return false; + } + if (typeof transaction.timestamp !== 'number') { + console.log('transaction timestamp missing'); + return false; + } + if (typeof transaction.signature !== 'string') { + console.log('transaction signature missing'); + return false; + } + return true; +}; + // valid address is a valid ecdsa public key in the 04 + X-coordinate + Y-coordinate format const isValidAddress = (address: string): boolean => { @@ -337,8 +665,38 @@ const isValidAddress = (address: string): boolean => { return true; }; + +/* export { processTransactions, signTxIn, getTransactionId, isValidAddress, validateTransaction, UnspentTxOut, TxIn, TxOut, getCoinbaseTransaction, getPublicKey, hasDuplicates, Transaction }; +*/ +export { + processTransactions, signTransaction, getTransactionId, isValidAddress, validateTransaction, + Account, findAccount, existAccount, createAccount, getCoinbaseTransaction, getPublicKey, hasDuplicates, + Transaction +}; +// +// +//Transaction +//UnspentTxOut => Account +//-TxIn +//-TxOut +// +//signTxIn = (transaction: Transaction, txInIndex: number, +// privateKey: string, aUnspentTxOuts: UnspentTxOut[]): string => { +//signTransaction = (transaction: Transaction, privateKey: string): string => { +// +//processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number) +//processTransactions = (aTransactions: Transaction[], accounts: Account[]) +// +//validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean +//validateTransaction = (transaction: Transaction, accounts: Account[]): boolean +// +//getCoinbaseTransaction = (address: string, blockIndex: number): Transaction +//getCoinbaseTransaction = (miner: string): Transaction +// +//hasDuplicates = (txIns: TxIn[]): boolean +//hasDuplicates = (nums: number[]): boolean diff --git a/cloud/src/transactionPool.ts b/cloud/src/transactionPool.ts index 5296b72..3dd6048 100644 --- a/cloud/src/transactionPool.ts +++ b/cloud/src/transactionPool.ts @@ -1,5 +1,7 @@ import * as _ from 'lodash'; -import {Transaction, TxIn, UnspentTxOut, validateTransaction} from './transaction'; + +//import {Transaction, TxIn, UnspentTxOut, validateTransaction} from './transaction'; +import {Transaction, Account, findAccount, validateTransaction} from './transaction'; let transactionPool: Transaction[] = []; @@ -7,6 +9,7 @@ const getTransactionPool = () => { return _.cloneDeep(transactionPool); }; +/* const addToTransactionPool = (tx: Transaction, unspentTxOuts: UnspentTxOut[]) => { if (!validateTransaction(tx, unspentTxOuts)) { @@ -19,14 +22,30 @@ const addToTransactionPool = (tx: Transaction, unspentTxOuts: UnspentTxOut[]) => console.log('adding to txPool: %s', JSON.stringify(tx)); transactionPool.push(tx); }; +*/ +const addToTransactionPool = (tx: Transaction, accounts: Account[]) => { + + if (!validateTransaction(tx, accounts)) { + throw Error('Trying to add invalid tx to pool. Tx: ' + tx.id); + } + if (!isValidTxForPool(tx, transactionPool, accounts)) { + throw Error('Tx is not valid for the pool, Tx: ' + tx.id); + } + //console.log('adding to txPool: %s', JSON.stringify(tx)); + transactionPool.push(tx); +}; + +/* const hasTxIn = (txIn: TxIn, unspentTxOuts: UnspentTxOut[]): boolean => { const foundTxIn = unspentTxOuts.find((uTxO: UnspentTxOut) => { return uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex; }); return foundTxIn !== undefined; }; +*/ +/* const updateTransactionPool = (unspentTxOuts: UnspentTxOut[]) => { const invalidTxs = []; for (const tx of transactionPool) { @@ -42,14 +61,54 @@ const updateTransactionPool = (unspentTxOuts: UnspentTxOut[]) => { transactionPool = _.without(transactionPool, ...invalidTxs); } }; +*/ +const updateTransactionPoolReplace = (accounts: Account[]) => { + var accSender; + transactionPool = _(transactionPool).uniqBy('id').filter(tx => validateTransaction(tx, accounts)).value(); + + for(var i=0; i < accounts.length; i++){ + accounts[i].available = accounts[i].balance; + } + const invalidTxs = []; + for (const tx of transactionPool) { + accSender = findAccount(tx.sender, accounts); + if(accSender == undefined){ + console.log('updateTransactionPool: no account found.'); + return false; + } + if (tx.amount > accSender.available) { + console.log('The sender does not have enough coins. Transaction be removed from pool. tx: ' + tx.id); + invalidTxs.push(tx); + }else{ + accSender.available -=tx.amount; + } + } + if (invalidTxs.length > 0) { + console.log('removing the following transactions from txPool: %s', JSON.stringify(invalidTxs)); + transactionPool = _.without(transactionPool, ...invalidTxs); + } +}; +const updateTransactionPool = (transactions: Transaction[]) => { + //console.log('tansactionPool: '+JSON.stringify(transactionPool)); + if (transactions.length > 0) { + //console.log('removing the following transactions from txPool: %s', JSON.stringify(transactions)); + var txIDs: string[] = _.map(transactions, (tx: Transaction) => tx.id); + transactionPool = _.filter(transactionPool, (tx: Transaction) => !_.includes(txIDs, tx.id)); + } + //console.log('tansactionPool: '+JSON.stringify(transactionPool)); +}; + +/* const getTxPoolIns = (aTransactionPool: Transaction[]): TxIn[] => { return _(aTransactionPool) .map((tx) => tx.txIns) .flatten() .value(); }; +*/ +/* const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): boolean => { const txPoolIns: TxIn[] = getTxPoolIns(aTtransactionPool); @@ -67,5 +126,43 @@ const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): bo } return true; }; +*/ +// This transaction tx has been validated in another function. id duplicate was checked in validation. +const isValidTxForPool = (tx: Transaction, aTransactionPool: Transaction[], accounts: Account[]): boolean => { + var accSender: Account; + +//console.log('isValidForPool: a Pool: ' + JSON.stringify(aTransactionPool)); +//console.log('tx: ' + JSON.stringify(tx)); + for(var i=0; i < accounts.length; i++){ + accounts[i].available = accounts[i].balance; + } + for (const trx of aTransactionPool) { + if(tx.id == trx.id){ + console.log('The transaction is duplicated with the existing transaction pool. trx: ' + trx.id); + return false; + } + accSender = findAccount(trx.sender, accounts); + if(accSender == undefined){ + console.log('isValideTxFor Pool: no account found.'); + return false; + } + if (trx.amount > accSender.available) { + console.log('The sender does not have enough coins. The existing transaction pool has problems. trx: ' + trx.id); + return false; + }else{ + accSender.available -= trx.amount; + } + } + accSender = findAccount(tx.sender, accounts); + if(accSender == undefined){ + console.log('isValidTxForPool: no account found.'); + return false; + } + if (tx.amount > accSender.available) { + console.log('The transaction is not valid for the pool. tx: ' + tx.id); + return false; + } + return true; +}; -export {addToTransactionPool, getTransactionPool, updateTransactionPool}; +export {addToTransactionPool, getTransactionPool, updateTransactionPool, updateTransactionPoolReplace}; diff --git a/cloud/src/wallet.ts b/cloud/src/wallet.ts index 315a939..bb72fc6 100644 --- a/cloud/src/wallet.ts +++ b/cloud/src/wallet.ts @@ -1,7 +1,11 @@ import {ec} from 'elliptic'; import {existsSync, readFileSync, unlinkSync, writeFileSync} from 'fs'; import * as _ from 'lodash'; -import {getPublicKey, getTransactionId, signTxIn, Transaction, TxIn, TxOut, UnspentTxOut} from './transaction'; +//import {getPublicKey, getTransactionId, signTxIn, Transaction, TxIn, TxOut, UnspentTxOut} from './transaction'; +import {getPublicKey, getTransactionId, signTransaction, Transaction, Account, findAccount, existAccount, createAccount} from './transaction'; + +//dewcoin +import {getCurrentTimestamp, getAccounts} from './blockchain'; const EC = new ec('secp256k1'); const privateKeyLocation = process.env.PRIVATE_KEY || 'node/wallet/private_key'; @@ -24,6 +28,10 @@ const generatePrivateKey = (): string => { }; const initWallet = () => { + if (!existAccount(getPublicFromWallet(), getAccounts())) { + createAccount(getPublicFromWallet(), getAccounts()); + } + console.log('an account was created.'); // let's not override existing private keys if (existsSync(privateKeyLocation)) { return; @@ -40,16 +48,29 @@ const deleteWallet = () => { } }; +/* const getBalance = (address: string, unspentTxOuts: UnspentTxOut[]): number => { return _(findUnspentTxOuts(address, unspentTxOuts)) .map((uTxO: UnspentTxOut) => uTxO.amount) .sum(); }; +*/ +const getBalance = (address: string, accounts: Account[]): number => { + var acct: Account = findAccount(address, accounts); + if(acct == undefined){ + console.log('getBalance: no account found.'); + return 0; + } + return acct.balance; +}; +/* const findUnspentTxOuts = (ownerAddress: string, unspentTxOuts: UnspentTxOut[]) => { return _.filter(unspentTxOuts, (uTxO: UnspentTxOut) => uTxO.address === ownerAddress); }; +*/ +/* const findTxOutsForAmount = (amount: number, myUnspentTxOuts: UnspentTxOut[]) => { let currentAmount = 0; const includedUnspentTxOuts = []; @@ -66,7 +87,9 @@ const findTxOutsForAmount = (amount: number, myUnspentTxOuts: UnspentTxOut[]) => ' Required amount:' + amount + '. Available unspentTxOuts:' + JSON.stringify(myUnspentTxOuts); throw Error(eMsg); }; +*/ +/* const createTxOuts = (receiverAddress: string, myAddress: string, amount, leftOverAmount: number) => { const txOut1: TxOut = new TxOut(receiverAddress, amount); if (leftOverAmount === 0) { @@ -76,7 +99,9 @@ const createTxOuts = (receiverAddress: string, myAddress: string, amount, leftOv return [txOut1, leftOverTx]; } }; +*/ +/* const filterTxPoolTxs = (unspentTxOuts: UnspentTxOut[], transactionPool: Transaction[]): UnspentTxOut[] => { const txIns: TxIn[] = _(transactionPool) .map((tx: Transaction) => tx.txIns) @@ -97,7 +122,9 @@ const filterTxPoolTxs = (unspentTxOuts: UnspentTxOut[], transactionPool: Transac return _.without(unspentTxOuts, ...removable); }; +*/ +/* const createTransaction = (receiverAddress: string, amount: number, privateKey: string, unspentTxOuts: UnspentTxOut[], txPool: Transaction[]): Transaction => { @@ -131,6 +158,32 @@ const createTransaction = (receiverAddress: string, amount: number, privateKey: return tx; }; +*/ +const createTransaction = (receiverAddress: string, amount: number, privateKey: string, + accounts: Account[], txPool: Transaction[]): Transaction => { + + //console.log('txPool: %s', JSON.stringify(txPool)); + const myAddress: string = getPublicKey(privateKey); + + const myAccount: Account = findAccount(myAddress, accounts); + + if(amount > myAccount.balance){ + console.log('No enough coins.'); + return undefined; + } + + const tx: Transaction = new Transaction(myAddress, receiverAddress, amount); + tx.timestamp = getCurrentTimestamp(); + tx.id = getTransactionId(tx); + tx.signature = signTransaction(tx, privateKey); + //what is the role of transaction pool? + return tx; +}; +/* export {createTransaction, getPublicFromWallet, getPrivateFromWallet, getBalance, generatePrivateKey, initWallet, deleteWallet, findUnspentTxOuts}; + +*/ +export {createTransaction, getPublicFromWallet, + getPrivateFromWallet, getBalance, generatePrivateKey, initWallet, deleteWallet}; diff --git a/dew/README.md b/dew/README.md index acb7fd0..6b9c875 100644 --- a/dew/README.md +++ b/dew/README.md @@ -80,7 +80,7 @@ curl -X POST http://localhost:3001/mineBlock curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction ``` For Windows: -curl -H "Content-type: application/json" --data "{\"address\": \"04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a\", \"amount\" : 35}" http://localhost:3001/sendTransaction +curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7cf8216982cf85f1b8edd51de012f1222bd2b37bb1217a42d31f8feda18be34aa09a759d2a70c5d6d0cc6cdd67e4e8c1761beb27e680bddd89b6\", \"amount\" : 25}" http://localhost:3001/sendTransaction @@ -90,7 +90,7 @@ If the transaction is invalid, the block will still be mined. curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction ``` For Windows: -curl -H "Content-type: application/json" --data "{\"address\": \"04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a\", \"amount\" : 20}" http://localhost:3001/mineTransaction +curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7cf8216982cf85f1b8edd51de012f1222bd2b37bb1217a42d31f8feda18be34aa09a759d2a70c5d6d0cc6cdd67e4e8c1761beb27e680bddd89b6\", \"amount\" : 20}" http://localhost:3001/mineTransaction ##### Add peer @@ -98,7 +98,7 @@ curl -H "Content-type: application/json" --data "{\"address\": \"04bfcab8722991a curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addpeer ``` For Windows: -curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:6001\"}" http://localhost:3001/addpeer +curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:7001\"}" http://localhost:3001/addpeer ``` diff --git a/dew/src/blockchain.ts b/dew/src/blockchain.ts index c6dac16..bd1e016 100644 --- a/dew/src/blockchain.ts +++ b/dew/src/blockchain.ts @@ -51,14 +51,19 @@ const genesisTransaction = { }; */ const genesisTransaction = new Transaction('coinbase', - '04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a', 50); -genesisTransaction.timestamp = getCurrentTimestamp(); + '04c0a0903203a721fa43581cc53c9361862e2e5522310909fbfbf14203371c464f5bdbba42e16349e237e1adf65952d8301e071a40a76b1709954c8f0e3f253b2c', 50); +genesisTransaction.timestamp = 1533641911; genesisTransaction.id = getTransactionId(genesisTransaction); genesisTransaction.signature = ''; +/* const genesisBlock: Block = new Block( 0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1465154705, [genesisTransaction], 0, 0 ); +*/ +const genesisBlock: Block = new Block( + 0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1533641911, [genesisTransaction], 0, 0 +); let blockchain: Block[] = [genesisBlock]; @@ -437,6 +442,7 @@ const handleReceivedTransaction = (transaction: Transaction) => { }; */ const handleReceivedTransaction = (transaction: Transaction) => { +//console.log('***handleReceivedTransacton:***'); addToTransactionPool(transaction, getAccounts()); }; diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts index d15c8de..4ed3a68 100644 --- a/dew/src/p2p.ts +++ b/dew/src/p2p.ts @@ -62,7 +62,7 @@ const initMessageHandler = (ws: WebSocket) => { console.log('could not parse received JSON message: ' + data); return; } - console.log('Received message: %s', JSON.stringify(message)); + console.log('[Received message: %s', JSON.stringify(message)); switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -102,6 +102,7 @@ const initMessageHandler = (ws: WebSocket) => { } catch (e) { console.log(e); } + console.log('message processing]'); }); }; diff --git a/dew/src/transaction.ts b/dew/src/transaction.ts index b807cc9..6d73843 100644 --- a/dew/src/transaction.ts +++ b/dew/src/transaction.ts @@ -152,6 +152,8 @@ const validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTx }; */ const existAccount = (address: string, accounts: Account[]): boolean => { + //console.log('address: ' + address); + //console.log('accounts: '+ JSON.stringify(accounts)); return _(accounts).map((acc: Account) => acc.address).includes(address); } const createAccount = (address: string, accounts: Account[]): boolean => { @@ -673,7 +675,7 @@ export { */ export { processTransactions, signTransaction, getTransactionId, isValidAddress, validateTransaction, - Account, findAccount, createAccount, getCoinbaseTransaction, getPublicKey, hasDuplicates, + Account, findAccount, existAccount, createAccount, getCoinbaseTransaction, getPublicKey, hasDuplicates, Transaction }; // diff --git a/dew/src/transactionPool.ts b/dew/src/transactionPool.ts index cbc82b9..3dd6048 100644 --- a/dew/src/transactionPool.ts +++ b/dew/src/transactionPool.ts @@ -131,6 +131,8 @@ const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): bo const isValidTxForPool = (tx: Transaction, aTransactionPool: Transaction[], accounts: Account[]): boolean => { var accSender: Account; +//console.log('isValidForPool: a Pool: ' + JSON.stringify(aTransactionPool)); +//console.log('tx: ' + JSON.stringify(tx)); for(var i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } diff --git a/dew/src/wallet.ts b/dew/src/wallet.ts index e0ed913..bb72fc6 100644 --- a/dew/src/wallet.ts +++ b/dew/src/wallet.ts @@ -2,7 +2,7 @@ import {ec} from 'elliptic'; import {existsSync, readFileSync, unlinkSync, writeFileSync} from 'fs'; import * as _ from 'lodash'; //import {getPublicKey, getTransactionId, signTxIn, Transaction, TxIn, TxOut, UnspentTxOut} from './transaction'; -import {getPublicKey, getTransactionId, signTransaction, Transaction, Account, findAccount, createAccount} from './transaction'; +import {getPublicKey, getTransactionId, signTransaction, Transaction, Account, findAccount, existAccount, createAccount} from './transaction'; //dewcoin import {getCurrentTimestamp, getAccounts} from './blockchain'; @@ -28,7 +28,9 @@ const generatePrivateKey = (): string => { }; const initWallet = () => { - createAccount(getPublicFromWallet(), getAccounts()); + if (!existAccount(getPublicFromWallet(), getAccounts())) { + createAccount(getPublicFromWallet(), getAccounts()); + } console.log('an account was created.'); // let's not override existing private keys if (existsSync(privateKeyLocation)) { From 0310807c4532b24776530fc22b9b07769fa4bc49 Mon Sep 17 00:00:00 2001 From: ywang Date: Tue, 7 Aug 2018 14:04:04 -0400 Subject: [PATCH 18/36] ignore --- cloud/src/.gitignore | 2 ++ dew/src/.gitignore | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 cloud/src/.gitignore create mode 100644 dew/src/.gitignore diff --git a/cloud/src/.gitignore b/cloud/src/.gitignore new file mode 100644 index 0000000..086f4e2 --- /dev/null +++ b/cloud/src/.gitignore @@ -0,0 +1,2 @@ +*.js +*.map diff --git a/dew/src/.gitignore b/dew/src/.gitignore new file mode 100644 index 0000000..086f4e2 --- /dev/null +++ b/dew/src/.gitignore @@ -0,0 +1,2 @@ +*.js +*.map From a9b79e82c3608879258a4be408e249d70b54adbd Mon Sep 17 00:00:00 2001 From: ywang Date: Tue, 7 Aug 2018 14:35:39 -0400 Subject: [PATCH 19/36] cleanup --- cloud/.gitignore | 5 - cloud/src/.gitignore | 2 - cloud/src/blockchain.js | 261 --------------------------- cloud/src/blockchain.js.map | 1 - cloud/src/main.js | 122 ------------- cloud/src/main.js.map | 1 - cloud/src/p2p.js | 175 ------------------ cloud/src/p2p.js.map | 1 - cloud/src/transaction.js | 298 ------------------------------- cloud/src/transaction.js.map | 1 - cloud/src/transactionPool.js | 64 ------- cloud/src/transactionPool.js.map | 1 - cloud/src/util.js | 22 --- cloud/src/util.js.map | 1 - cloud/src/wallet.js | 120 ------------- cloud/src/wallet.js.map | 1 - dew/.gitignore | 5 - dew/src/.gitignore | 2 - dew/src/blockchain.js | 261 --------------------------- dew/src/blockchain.js.map | 1 - dew/src/main.js | 122 ------------- dew/src/main.js.map | 1 - dew/src/p2p.js | 175 ------------------ dew/src/p2p.js.map | 1 - dew/src/transaction.js | 298 ------------------------------- dew/src/transaction.js.map | 1 - dew/src/transactionPool.js | 64 ------- dew/src/transactionPool.js.map | 1 - dew/src/util.js | 21 --- dew/src/util.js.map | 1 - dew/src/wallet.js | 124 ------------- dew/src/wallet.js.map | 1 - 32 files changed, 2155 deletions(-) delete mode 100644 cloud/.gitignore delete mode 100644 cloud/src/.gitignore delete mode 100644 cloud/src/blockchain.js delete mode 100644 cloud/src/blockchain.js.map delete mode 100644 cloud/src/main.js delete mode 100644 cloud/src/main.js.map delete mode 100644 cloud/src/p2p.js delete mode 100644 cloud/src/p2p.js.map delete mode 100644 cloud/src/transaction.js delete mode 100644 cloud/src/transaction.js.map delete mode 100644 cloud/src/transactionPool.js delete mode 100644 cloud/src/transactionPool.js.map delete mode 100644 cloud/src/util.js delete mode 100644 cloud/src/util.js.map delete mode 100644 cloud/src/wallet.js delete mode 100644 cloud/src/wallet.js.map delete mode 100644 dew/.gitignore delete mode 100644 dew/src/.gitignore delete mode 100644 dew/src/blockchain.js delete mode 100644 dew/src/blockchain.js.map delete mode 100644 dew/src/main.js delete mode 100644 dew/src/main.js.map delete mode 100644 dew/src/p2p.js delete mode 100644 dew/src/p2p.js.map delete mode 100644 dew/src/transaction.js delete mode 100644 dew/src/transaction.js.map delete mode 100644 dew/src/transactionPool.js delete mode 100644 dew/src/transactionPool.js.map delete mode 100644 dew/src/util.js delete mode 100644 dew/src/util.js.map delete mode 100644 dew/src/wallet.js delete mode 100644 dew/src/wallet.js.map diff --git a/cloud/.gitignore b/cloud/.gitignore deleted file mode 100644 index e5d4fe4..0000000 --- a/cloud/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -npm-debug.log -.idea -src/*.js -src/*.map diff --git a/cloud/src/.gitignore b/cloud/src/.gitignore deleted file mode 100644 index 086f4e2..0000000 --- a/cloud/src/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.js -*.map diff --git a/cloud/src/blockchain.js b/cloud/src/blockchain.js deleted file mode 100644 index 1b51687..0000000 --- a/cloud/src/blockchain.js +++ /dev/null @@ -1,261 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const CryptoJS = require("crypto-js"); -const _ = require("lodash"); -const p2p_1 = require("./p2p"); -const transaction_1 = require("./transaction"); -const transactionPool_1 = require("./transactionPool"); -const util_1 = require("./util"); -const wallet_1 = require("./wallet"); -class Block { - constructor(index, hash, previousHash, timestamp, data, difficulty, nonce) { - this.index = index; - this.previousHash = previousHash; - this.timestamp = timestamp; - this.data = data; - this.hash = hash; - this.difficulty = difficulty; - this.nonce = nonce; - } -} -exports.Block = Block; -const genesisTransaction = { - 'txIns': [{ 'signature': '', 'txOutId': '', 'txOutIndex': 0 }], - 'txOuts': [{ - 'address': '04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a', - 'amount': 50 - }], - 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3' -}; -const genesisBlock = new Block(0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1465154705, [genesisTransaction], 0, 0); -let blockchain = [genesisBlock]; -// the unspent txOut of genesis block is set to unspentTxOuts on startup -let unspentTxOuts = transaction_1.processTransactions(blockchain[0].data, [], 0); -const getBlockchain = () => blockchain; -exports.getBlockchain = getBlockchain; -const getUnspentTxOuts = () => _.cloneDeep(unspentTxOuts); -exports.getUnspentTxOuts = getUnspentTxOuts; -// and txPool should be only updated at the same time -const setUnspentTxOuts = (newUnspentTxOut) => { - console.log('replacing unspentTxouts with: %s', newUnspentTxOut); - unspentTxOuts = newUnspentTxOut; -}; -const getLatestBlock = () => blockchain[blockchain.length - 1]; -exports.getLatestBlock = getLatestBlock; -// in seconds -const BLOCK_GENERATION_INTERVAL = 10; -// in blocks -const DIFFICULTY_ADJUSTMENT_INTERVAL = 10; -const getDifficulty = (aBlockchain) => { - const latestBlock = aBlockchain[blockchain.length - 1]; - if (latestBlock.index % DIFFICULTY_ADJUSTMENT_INTERVAL === 0 && latestBlock.index !== 0) { - return getAdjustedDifficulty(latestBlock, aBlockchain); - } - else { - return latestBlock.difficulty; - } -}; -const getAdjustedDifficulty = (latestBlock, aBlockchain) => { - const prevAdjustmentBlock = aBlockchain[blockchain.length - DIFFICULTY_ADJUSTMENT_INTERVAL]; - const timeExpected = BLOCK_GENERATION_INTERVAL * DIFFICULTY_ADJUSTMENT_INTERVAL; - const timeTaken = latestBlock.timestamp - prevAdjustmentBlock.timestamp; - if (timeTaken < timeExpected / 2) { - return prevAdjustmentBlock.difficulty + 1; - } - else if (timeTaken > timeExpected * 2) { - return prevAdjustmentBlock.difficulty - 1; - } - else { - return prevAdjustmentBlock.difficulty; - } -}; -const getCurrentTimestamp = () => Math.round(new Date().getTime() / 1000); -const generateRawNextBlock = (blockData) => { - const previousBlock = getLatestBlock(); - const difficulty = getDifficulty(getBlockchain()); - const nextIndex = previousBlock.index + 1; - const nextTimestamp = getCurrentTimestamp(); - const newBlock = findBlock(nextIndex, previousBlock.hash, nextTimestamp, blockData, difficulty); - if (addBlockToChain(newBlock)) { - p2p_1.broadcastLatest(); - return newBlock; - } - else { - return null; - } -}; -exports.generateRawNextBlock = generateRawNextBlock; -// gets the unspent transaction outputs owned by the wallet -const getMyUnspentTransactionOutputs = () => { - return wallet_1.findUnspentTxOuts(wallet_1.getPublicFromWallet(), getUnspentTxOuts()); -}; -exports.getMyUnspentTransactionOutputs = getMyUnspentTransactionOutputs; -const generateNextBlock = () => { - const coinbaseTx = transaction_1.getCoinbaseTransaction(wallet_1.getPublicFromWallet(), getLatestBlock().index + 1); - const blockData = [coinbaseTx].concat(transactionPool_1.getTransactionPool()); - return generateRawNextBlock(blockData); -}; -exports.generateNextBlock = generateNextBlock; -const generatenextBlockWithTransaction = (receiverAddress, amount) => { - if (!transaction_1.isValidAddress(receiverAddress)) { - throw Error('invalid address'); - } - if (typeof amount !== 'number') { - throw Error('invalid amount'); - } - const coinbaseTx = transaction_1.getCoinbaseTransaction(wallet_1.getPublicFromWallet(), getLatestBlock().index + 1); - const tx = wallet_1.createTransaction(receiverAddress, amount, wallet_1.getPrivateFromWallet(), getUnspentTxOuts(), transactionPool_1.getTransactionPool()); - const blockData = [coinbaseTx, tx]; - return generateRawNextBlock(blockData); -}; -exports.generatenextBlockWithTransaction = generatenextBlockWithTransaction; -const findBlock = (index, previousHash, timestamp, data, difficulty) => { - let nonce = 0; - while (true) { - const hash = calculateHash(index, previousHash, timestamp, data, difficulty, nonce); - if (hashMatchesDifficulty(hash, difficulty)) { - return new Block(index, hash, previousHash, timestamp, data, difficulty, nonce); - } - nonce++; - } -}; -const getAccountBalance = () => { - return wallet_1.getBalance(wallet_1.getPublicFromWallet(), getUnspentTxOuts()); -}; -exports.getAccountBalance = getAccountBalance; -const sendTransaction = (address, amount) => { - const tx = wallet_1.createTransaction(address, amount, wallet_1.getPrivateFromWallet(), getUnspentTxOuts(), transactionPool_1.getTransactionPool()); - transactionPool_1.addToTransactionPool(tx, getUnspentTxOuts()); - p2p_1.broadCastTransactionPool(); - return tx; -}; -exports.sendTransaction = sendTransaction; -const calculateHashForBlock = (block) => calculateHash(block.index, block.previousHash, block.timestamp, block.data, block.difficulty, block.nonce); -const calculateHash = (index, previousHash, timestamp, data, difficulty, nonce) => CryptoJS.SHA256(index + previousHash + timestamp + data + difficulty + nonce).toString(); -const isValidBlockStructure = (block) => { - return typeof block.index === 'number' - && typeof block.hash === 'string' - && typeof block.previousHash === 'string' - && typeof block.timestamp === 'number' - && typeof block.data === 'object'; -}; -exports.isValidBlockStructure = isValidBlockStructure; -const isValidNewBlock = (newBlock, previousBlock) => { - if (!isValidBlockStructure(newBlock)) { - console.log('invalid block structure: %s', JSON.stringify(newBlock)); - return false; - } - if (previousBlock.index + 1 !== newBlock.index) { - console.log('invalid index'); - return false; - } - else if (previousBlock.hash !== newBlock.previousHash) { - console.log('invalid previoushash'); - return false; - } - else if (!isValidTimestamp(newBlock, previousBlock)) { - console.log('invalid timestamp'); - return false; - } - else if (!hasValidHash(newBlock)) { - return false; - } - return true; -}; -const getAccumulatedDifficulty = (aBlockchain) => { - return aBlockchain - .map((block) => block.difficulty) - .map((difficulty) => Math.pow(2, difficulty)) - .reduce((a, b) => a + b); -}; -const isValidTimestamp = (newBlock, previousBlock) => { - return (previousBlock.timestamp - 60 < newBlock.timestamp) - && newBlock.timestamp - 60 < getCurrentTimestamp(); -}; -const hasValidHash = (block) => { - if (!hashMatchesBlockContent(block)) { - console.log('invalid hash, got:' + block.hash); - return false; - } - if (!hashMatchesDifficulty(block.hash, block.difficulty)) { - console.log('block difficulty not satisfied. Expected: ' + block.difficulty + 'got: ' + block.hash); - } - return true; -}; -const hashMatchesBlockContent = (block) => { - const blockHash = calculateHashForBlock(block); - return blockHash === block.hash; -}; -const hashMatchesDifficulty = (hash, difficulty) => { - const hashInBinary = util_1.hexToBinary(hash); - const requiredPrefix = '0'.repeat(difficulty); - return hashInBinary.startsWith(requiredPrefix); -}; -/* - Checks if the given blockchain is valid. Return the unspent txOuts if the chain is valid - */ -const isValidChain = (blockchainToValidate) => { - console.log('isValidChain:'); - console.log(JSON.stringify(blockchainToValidate)); - const isValidGenesis = (block) => { - return JSON.stringify(block) === JSON.stringify(genesisBlock); - }; - if (!isValidGenesis(blockchainToValidate[0])) { - return null; - } - /* - Validate each block in the chain. The block is valid if the block structure is valid - and the transaction are valid - */ - let aUnspentTxOuts = []; - for (let i = 0; i < blockchainToValidate.length; i++) { - const currentBlock = blockchainToValidate[i]; - if (i !== 0 && !isValidNewBlock(blockchainToValidate[i], blockchainToValidate[i - 1])) { - return null; - } - aUnspentTxOuts = transaction_1.processTransactions(currentBlock.data, aUnspentTxOuts, currentBlock.index); - if (aUnspentTxOuts === null) { - console.log('invalid transactions in blockchain'); - return null; - } - } - return aUnspentTxOuts; -}; -const addBlockToChain = (newBlock) => { - if (isValidNewBlock(newBlock, getLatestBlock())) { - const retVal = transaction_1.processTransactions(newBlock.data, getUnspentTxOuts(), newBlock.index); - if (retVal === null) { - console.log('block is not valid in terms of transactions'); - return false; - } - else { - blockchain.push(newBlock); - setUnspentTxOuts(retVal); - transactionPool_1.updateTransactionPool(unspentTxOuts); - return true; - } - } - return false; -}; -exports.addBlockToChain = addBlockToChain; -const replaceChain = (newBlocks) => { - const aUnspentTxOuts = isValidChain(newBlocks); - const validChain = aUnspentTxOuts !== null; - if (validChain && - getAccumulatedDifficulty(newBlocks) > getAccumulatedDifficulty(getBlockchain())) { - console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); - blockchain = newBlocks; - setUnspentTxOuts(aUnspentTxOuts); - transactionPool_1.updateTransactionPool(unspentTxOuts); - p2p_1.broadcastLatest(); - } - else { - console.log('Received blockchain invalid'); - } -}; -exports.replaceChain = replaceChain; -const handleReceivedTransaction = (transaction) => { - transactionPool_1.addToTransactionPool(transaction, getUnspentTxOuts()); -}; -exports.handleReceivedTransaction = handleReceivedTransaction; -//# sourceMappingURL=blockchain.js.map \ No newline at end of file diff --git a/cloud/src/blockchain.js.map b/cloud/src/blockchain.js.map deleted file mode 100644 index 94bd3e2..0000000 --- a/cloud/src/blockchain.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"blockchain.js","sourceRoot":"","sources":["blockchain.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/cloud/src/main.js b/cloud/src/main.js deleted file mode 100644 index ed3bdfb..0000000 --- a/cloud/src/main.js +++ /dev/null @@ -1,122 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const bodyParser = require("body-parser"); -const express = require("express"); -const _ = require("lodash"); -const blockchain_1 = require("./blockchain"); -const p2p_1 = require("./p2p"); -const transactionPool_1 = require("./transactionPool"); -const wallet_1 = require("./wallet"); -const httpPort = parseInt(process.env.HTTP_PORT) || 4001; -const p2pPort = parseInt(process.env.P2P_PORT) || 7001; -const initHttpServer = (myHttpPort) => { - const app = express(); - app.use(bodyParser.json()); - app.use((err, req, res, next) => { - if (err) { - res.status(400).send(err.message); - } - }); - app.get('/blocks', (req, res) => { - res.send(blockchain_1.getBlockchain()); - }); - app.get('/block/:hash', (req, res) => { - const block = _.find(blockchain_1.getBlockchain(), { 'hash': req.params.hash }); - res.send(block); - }); - app.get('/transaction/:id', (req, res) => { - const tx = _(blockchain_1.getBlockchain()) - .map((blocks) => blocks.data) - .flatten() - .find({ 'id': req.params.id }); - res.send(tx); - }); - app.get('/address/:address', (req, res) => { - const unspentTxOuts = _.filter(blockchain_1.getUnspentTxOuts(), (uTxO) => uTxO.address === req.params.address); - res.send({ 'unspentTxOuts': unspentTxOuts }); - }); - app.get('/unspentTransactionOutputs', (req, res) => { - res.send(blockchain_1.getUnspentTxOuts()); - }); - app.get('/myUnspentTransactionOutputs', (req, res) => { - res.send(blockchain_1.getMyUnspentTransactionOutputs()); - }); - app.post('/mineRawBlock', (req, res) => { - if (req.body.data == null) { - res.send('data parameter is missing'); - return; - } - const newBlock = blockchain_1.generateRawNextBlock(req.body.data); - if (newBlock === null) { - res.status(400).send('could not generate block'); - } - else { - res.send(newBlock); - } - }); - app.post('/mineBlock', (req, res) => { - const newBlock = blockchain_1.generateNextBlock(); - if (newBlock === null) { - res.status(400).send('could not generate block'); - } - else { - res.send(newBlock); - } - }); - app.get('/balance', (req, res) => { - const balance = blockchain_1.getAccountBalance(); - res.send({ 'balance': balance }); - }); - app.get('/address', (req, res) => { - const address = wallet_1.getPublicFromWallet(); - res.send({ 'address': address }); - }); - app.post('/mineTransaction', (req, res) => { - const address = req.body.address; - const amount = req.body.amount; - try { - const resp = blockchain_1.generatenextBlockWithTransaction(address, amount); - res.send(resp); - } - catch (e) { - console.log(e.message); - res.status(400).send(e.message); - } - }); - app.post('/sendTransaction', (req, res) => { - try { - const address = req.body.address; - const amount = req.body.amount; - if (address === undefined || amount === undefined) { - throw Error('invalid address or amount'); - } - const resp = blockchain_1.sendTransaction(address, amount); - res.send(resp); - } - catch (e) { - console.log(e.message); - res.status(400).send(e.message); - } - }); - app.get('/transactionPool', (req, res) => { - res.send(transactionPool_1.getTransactionPool()); - }); - app.get('/peers', (req, res) => { - res.send(p2p_1.getSockets().map((s) => s._socket.remoteAddress + ':' + s._socket.remotePort)); - }); - app.post('/addPeer', (req, res) => { - p2p_1.connectToPeers(req.body.peer); - res.send(); - }); - app.post('/stop', (req, res) => { - res.send({ 'msg': 'stopping server' }); - process.exit(); - }); - app.listen(myHttpPort, () => { - console.log('Listening http on port: ' + myHttpPort); - }); -}; -initHttpServer(httpPort); -p2p_1.initP2PServer(p2pPort); -wallet_1.initWallet(); -//# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/cloud/src/main.js.map b/cloud/src/main.js.map deleted file mode 100644 index b723beb..0000000 --- a/cloud/src/main.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":";;AAAA,0CAA2C;AAC3C,mCAAmC;AACnC,4BAA4B;AAC5B,6CAGsB;AACtB,+BAAgE;AAEhE,uDAAqD;AACrD,qCAAyD;AAEzD,MAAM,QAAQ,GAAW,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AACjE,MAAM,OAAO,GAAW,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;AAE/D,MAAM,cAAc,GAAG,CAAC,UAAkB;IACtC,MAAM,GAAG,GAAG,OAAO,EAAE,CAAC;IACtB,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;IAE3B,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI;QACxB,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG;QACxB,GAAG,CAAC,IAAI,CAAC,0BAAa,EAAE,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,GAAG;QAC7B,MAAM,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC,0BAAa,EAAE,EAAE,EAAC,MAAM,EAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAC,CAAC,CAAC;QAClE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG;QACjC,MAAM,EAAE,GAAG,CAAC,CAAC,0BAAa,EAAE,CAAC;aACxB,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC;aAC5B,OAAO,EAAE;aACT,IAAI,CAAC,EAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAC,CAAC,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC,GAAG,EAAE,GAAG;QAClC,MAAM,aAAa,GACf,CAAC,CAAC,MAAM,CAAC,6BAAgB,EAAE,EAAE,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,KAAK,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChF,GAAG,CAAC,IAAI,CAAC,EAAC,eAAe,EAAE,aAAa,EAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,4BAA4B,EAAE,CAAC,GAAG,EAAE,GAAG;QAC3C,GAAG,CAAC,IAAI,CAAC,6BAAgB,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,8BAA8B,EAAE,CAAC,GAAG,EAAE,GAAG;QAC7C,GAAG,CAAC,IAAI,CAAC,2CAA8B,EAAE,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,GAAG,EAAE,GAAG;QAC/B,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC;YACxB,GAAG,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YACtC,MAAM,CAAC;QACX,CAAC;QACD,MAAM,QAAQ,GAAU,iCAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,EAAE,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC;YACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACrD,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,GAAG;QAC5B,MAAM,QAAQ,GAAU,8BAAiB,EAAE,CAAC;QAC5C,EAAE,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC;YACpB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACrD,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG;QACzB,MAAM,OAAO,GAAW,8BAAiB,EAAE,CAAC;QAC5C,GAAG,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,OAAO,EAAC,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG;QACzB,MAAM,OAAO,GAAW,4BAAmB,EAAE,CAAC;QAC9C,GAAG,CAAC,IAAI,CAAC,EAAC,SAAS,EAAE,OAAO,EAAC,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG;QAClC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;QACjC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;QAC/B,IAAI,CAAC;YACD,MAAM,IAAI,GAAG,6CAAgC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC/D,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;QAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACT,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACvB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG;QAClC,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;YACjC,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;YAE/B,EAAE,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC;gBAChD,MAAM,KAAK,CAAC,2BAA2B,CAAC,CAAC;YAC7C,CAAC;YACD,MAAM,IAAI,GAAG,4BAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC9C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnB,CAAC;QAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACT,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YACvB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;QACpC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG;QACjC,GAAG,CAAC,IAAI,CAAC,oCAAkB,EAAE,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,GAAG;QACvB,GAAG,CAAC,IAAI,CAAC,gBAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAM,KAAK,CAAC,CAAC,OAAO,CAAC,aAAa,GAAG,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC;IACjG,CAAC,CAAC,CAAC;IACH,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG;QAC1B,oBAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC9B,GAAG,CAAC,IAAI,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG;QACvB,GAAG,CAAC,IAAI,CAAC,EAAC,KAAK,EAAG,iBAAiB,EAAC,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE;QACnB,OAAO,CAAC,GAAG,CAAC,0BAA0B,GAAG,UAAU,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACP,CAAC,CAAC;AAEF,cAAc,CAAC,QAAQ,CAAC,CAAC;AACzB,mBAAa,CAAC,OAAO,CAAC,CAAC;AACvB,mBAAU,EAAE,CAAC"} \ No newline at end of file diff --git a/cloud/src/p2p.js b/cloud/src/p2p.js deleted file mode 100644 index db14e7e..0000000 --- a/cloud/src/p2p.js +++ /dev/null @@ -1,175 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const WebSocket = require("ws"); -const blockchain_1 = require("./blockchain"); -const transactionPool_1 = require("./transactionPool"); -const sockets = []; -var MessageType; -(function (MessageType) { - MessageType[MessageType["QUERY_LATEST"] = 0] = "QUERY_LATEST"; - MessageType[MessageType["QUERY_ALL"] = 1] = "QUERY_ALL"; - MessageType[MessageType["RESPONSE_BLOCKCHAIN"] = 2] = "RESPONSE_BLOCKCHAIN"; - MessageType[MessageType["QUERY_TRANSACTION_POOL"] = 3] = "QUERY_TRANSACTION_POOL"; - MessageType[MessageType["RESPONSE_TRANSACTION_POOL"] = 4] = "RESPONSE_TRANSACTION_POOL"; -})(MessageType || (MessageType = {})); -class Message { -} -const initP2PServer = (p2pPort) => { - const server = new WebSocket.Server({ port: p2pPort }); - server.on('connection', (ws) => { - initConnection(ws); - }); - console.log('listening websocket p2p port on: ' + p2pPort); -}; -exports.initP2PServer = initP2PServer; -const getSockets = () => sockets; -exports.getSockets = getSockets; -const initConnection = (ws) => { - sockets.push(ws); - initMessageHandler(ws); - initErrorHandler(ws); - write(ws, queryChainLengthMsg()); - // query transactions pool only some time after chain query - setTimeout(() => { - broadcast(queryTransactionPoolMsg()); - }, 500); -}; -const JSONToObject = (data) => { - try { - return JSON.parse(data); - } - catch (e) { - console.log(e); - return null; - } -}; -const initMessageHandler = (ws) => { - ws.on('message', (data) => { - try { - const message = JSONToObject(data); - if (message === null) { - console.log('could not parse received JSON message: ' + data); - return; - } - console.log('Received message: %s', JSON.stringify(message)); - switch (message.type) { - case MessageType.QUERY_LATEST: - write(ws, responseLatestMsg()); - break; - case MessageType.QUERY_ALL: - write(ws, responseChainMsg()); - break; - case MessageType.RESPONSE_BLOCKCHAIN: - const receivedBlocks = JSONToObject(message.data); - if (receivedBlocks === null) { - console.log('invalid blocks received: %s', JSON.stringify(message.data)); - break; - } - handleBlockchainResponse(receivedBlocks); - break; - case MessageType.QUERY_TRANSACTION_POOL: - write(ws, responseTransactionPoolMsg()); - break; - case MessageType.RESPONSE_TRANSACTION_POOL: - const receivedTransactions = JSONToObject(message.data); - if (receivedTransactions === null) { - console.log('invalid transaction received: %s', JSON.stringify(message.data)); - break; - } - receivedTransactions.forEach((transaction) => { - try { - blockchain_1.handleReceivedTransaction(transaction); - // if no error is thrown, transaction was indeed added to the pool - // let's broadcast transaction pool - broadCastTransactionPool(); - } - catch (e) { - console.log(e.message); - } - }); - break; - } - } - catch (e) { - console.log(e); - } - }); -}; -const write = (ws, message) => ws.send(JSON.stringify(message)); -const broadcast = (message) => sockets.forEach((socket) => write(socket, message)); -const queryChainLengthMsg = () => ({ 'type': MessageType.QUERY_LATEST, 'data': null }); -const queryAllMsg = () => ({ 'type': MessageType.QUERY_ALL, 'data': null }); -const responseChainMsg = () => ({ - 'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify(blockchain_1.getBlockchain()) -}); -const responseLatestMsg = () => ({ - 'type': MessageType.RESPONSE_BLOCKCHAIN, - 'data': JSON.stringify([blockchain_1.getLatestBlock()]) -}); -const queryTransactionPoolMsg = () => ({ - 'type': MessageType.QUERY_TRANSACTION_POOL, - 'data': null -}); -const responseTransactionPoolMsg = () => ({ - 'type': MessageType.RESPONSE_TRANSACTION_POOL, - 'data': JSON.stringify(transactionPool_1.getTransactionPool()) -}); -const initErrorHandler = (ws) => { - const closeConnection = (myWs) => { - console.log('connection failed to peer: ' + myWs.url); - sockets.splice(sockets.indexOf(myWs), 1); - }; - ws.on('close', () => closeConnection(ws)); - ws.on('error', () => closeConnection(ws)); -}; -const handleBlockchainResponse = (receivedBlocks) => { - if (receivedBlocks.length === 0) { - console.log('received block chain size of 0'); - return; - } - const latestBlockReceived = receivedBlocks[receivedBlocks.length - 1]; - if (!blockchain_1.isValidBlockStructure(latestBlockReceived)) { - console.log('block structuture not valid'); - return; - } - const latestBlockHeld = blockchain_1.getLatestBlock(); - if (latestBlockReceived.index > latestBlockHeld.index) { - console.log('blockchain possibly behind. We got: ' - + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index); - if (latestBlockHeld.hash === latestBlockReceived.previousHash) { - if (blockchain_1.addBlockToChain(latestBlockReceived)) { - broadcast(responseLatestMsg()); - } - } - else if (receivedBlocks.length === 1) { - console.log('We have to query the chain from our peer'); - broadcast(queryAllMsg()); - } - else { - console.log('Received blockchain is longer than current blockchain'); - blockchain_1.replaceChain(receivedBlocks); - } - } - else { - console.log('received blockchain is not longer than received blockchain. Do nothing'); - } -}; -const broadcastLatest = () => { - broadcast(responseLatestMsg()); -}; -exports.broadcastLatest = broadcastLatest; -const connectToPeers = (newPeer) => { - const ws = new WebSocket(newPeer); - ws.on('open', () => { - initConnection(ws); - }); - ws.on('error', () => { - console.log('connection failed'); - }); -}; -exports.connectToPeers = connectToPeers; -const broadCastTransactionPool = () => { - broadcast(responseTransactionPoolMsg()); -}; -exports.broadCastTransactionPool = broadCastTransactionPool; -//# sourceMappingURL=p2p.js.map \ No newline at end of file diff --git a/cloud/src/p2p.js.map b/cloud/src/p2p.js.map deleted file mode 100644 index c86c349..0000000 --- a/cloud/src/p2p.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"p2p.js","sourceRoot":"","sources":["p2p.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/cloud/src/transaction.js b/cloud/src/transaction.js deleted file mode 100644 index bb1a059..0000000 --- a/cloud/src/transaction.js +++ /dev/null @@ -1,298 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const CryptoJS = require("crypto-js"); -const ecdsa = require("elliptic"); -const _ = require("lodash"); -const ec = new ecdsa.ec('secp256k1'); -const COINBASE_AMOUNT = 50; -class UnspentTxOut { - constructor(txOutId, txOutIndex, address, amount) { - this.txOutId = txOutId; - this.txOutIndex = txOutIndex; - this.address = address; - this.amount = amount; - } -} -exports.UnspentTxOut = UnspentTxOut; -class TxIn { -} -exports.TxIn = TxIn; -class TxOut { - constructor(address, amount) { - this.address = address; - this.amount = amount; - } -} -exports.TxOut = TxOut; -class Transaction { -} -exports.Transaction = Transaction; -const getTransactionId = (transaction) => { - const txInContent = transaction.txIns - .map((txIn) => txIn.txOutId + txIn.txOutIndex) - .reduce((a, b) => a + b, ''); - const txOutContent = transaction.txOuts - .map((txOut) => txOut.address + txOut.amount) - .reduce((a, b) => a + b, ''); - return CryptoJS.SHA256(txInContent + txOutContent).toString(); -}; -exports.getTransactionId = getTransactionId; -const validateTransaction = (transaction, aUnspentTxOuts) => { - if (!isValidTransactionStructure(transaction)) { - return false; - } - if (getTransactionId(transaction) !== transaction.id) { - console.log('invalid tx id: ' + transaction.id); - return false; - } - const hasValidTxIns = transaction.txIns - .map((txIn) => validateTxIn(txIn, transaction, aUnspentTxOuts)) - .reduce((a, b) => a && b, true); - if (!hasValidTxIns) { - console.log('some of the txIns are invalid in tx: ' + transaction.id); - return false; - } - const totalTxInValues = transaction.txIns - .map((txIn) => getTxInAmount(txIn, aUnspentTxOuts)) - .reduce((a, b) => (a + b), 0); - const totalTxOutValues = transaction.txOuts - .map((txOut) => txOut.amount) - .reduce((a, b) => (a + b), 0); - if (totalTxOutValues !== totalTxInValues) { - console.log('totalTxOutValues !== totalTxInValues in tx: ' + transaction.id); - return false; - } - return true; -}; -exports.validateTransaction = validateTransaction; -const validateBlockTransactions = (aTransactions, aUnspentTxOuts, blockIndex) => { - const coinbaseTx = aTransactions[0]; - if (!validateCoinbaseTx(coinbaseTx, blockIndex)) { - console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); - return false; - } - // check for duplicate txIns. Each txIn can be included only once - const txIns = _(aTransactions) - .map((tx) => tx.txIns) - .flatten() - .value(); - if (hasDuplicates(txIns)) { - return false; - } - // all but coinbase transactions - const normalTransactions = aTransactions.slice(1); - return normalTransactions.map((tx) => validateTransaction(tx, aUnspentTxOuts)) - .reduce((a, b) => (a && b), true); -}; -const hasDuplicates = (txIns) => { - const groups = _.countBy(txIns, (txIn) => txIn.txOutId + txIn.txOutIndex); - return _(groups) - .map((value, key) => { - if (value > 1) { - console.log('duplicate txIn: ' + key); - return true; - } - else { - return false; - } - }) - .includes(true); -}; -exports.hasDuplicates = hasDuplicates; -const validateCoinbaseTx = (transaction, blockIndex) => { - if (transaction == null) { - console.log('the first transaction in the block must be coinbase transaction'); - return false; - } - if (getTransactionId(transaction) !== transaction.id) { - console.log('invalid coinbase tx id: ' + transaction.id); - return false; - } - if (transaction.txIns.length !== 1) { - console.log('one txIn must be specified in the coinbase transaction'); - return; - } - if (transaction.txIns[0].txOutIndex !== blockIndex) { - console.log('the txIn signature in coinbase tx must be the block height'); - return false; - } - if (transaction.txOuts.length !== 1) { - console.log('invalid number of txOuts in coinbase transaction'); - return false; - } - if (transaction.txOuts[0].amount !== COINBASE_AMOUNT) { - console.log('invalid coinbase amount in coinbase transaction'); - return false; - } - return true; -}; -const validateTxIn = (txIn, transaction, aUnspentTxOuts) => { - const referencedUTxOut = aUnspentTxOuts.find((uTxO) => uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex); - if (referencedUTxOut == null) { - console.log('referenced txOut not found: ' + JSON.stringify(txIn)); - return false; - } - const address = referencedUTxOut.address; - const key = ec.keyFromPublic(address, 'hex'); - const validSignature = key.verify(transaction.id, txIn.signature); - if (!validSignature) { - console.log('invalid txIn signature: %s txId: %s address: %s', txIn.signature, transaction.id, referencedUTxOut.address); - return false; - } - return true; -}; -const getTxInAmount = (txIn, aUnspentTxOuts) => { - return findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts).amount; -}; -const findUnspentTxOut = (transactionId, index, aUnspentTxOuts) => { - return aUnspentTxOuts.find((uTxO) => uTxO.txOutId === transactionId && uTxO.txOutIndex === index); -}; -const getCoinbaseTransaction = (address, blockIndex) => { - const t = new Transaction(); - const txIn = new TxIn(); - txIn.signature = ''; - txIn.txOutId = ''; - txIn.txOutIndex = blockIndex; - t.txIns = [txIn]; - t.txOuts = [new TxOut(address, COINBASE_AMOUNT)]; - t.id = getTransactionId(t); - return t; -}; -exports.getCoinbaseTransaction = getCoinbaseTransaction; -const signTxIn = (transaction, txInIndex, privateKey, aUnspentTxOuts) => { - const txIn = transaction.txIns[txInIndex]; - const dataToSign = transaction.id; - const referencedUnspentTxOut = findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts); - if (referencedUnspentTxOut == null) { - console.log('could not find referenced txOut'); - throw Error(); - } - const referencedAddress = referencedUnspentTxOut.address; - if (getPublicKey(privateKey) !== referencedAddress) { - console.log('trying to sign an input with private' + - ' key that does not match the address that is referenced in txIn'); - throw Error(); - } - const key = ec.keyFromPrivate(privateKey, 'hex'); - const signature = toHexString(key.sign(dataToSign).toDER()); - return signature; -}; -exports.signTxIn = signTxIn; -const updateUnspentTxOuts = (aTransactions, aUnspentTxOuts) => { - const newUnspentTxOuts = aTransactions - .map((t) => { - return t.txOuts.map((txOut, index) => new UnspentTxOut(t.id, index, txOut.address, txOut.amount)); - }) - .reduce((a, b) => a.concat(b), []); - const consumedTxOuts = aTransactions - .map((t) => t.txIns) - .reduce((a, b) => a.concat(b), []) - .map((txIn) => new UnspentTxOut(txIn.txOutId, txIn.txOutIndex, '', 0)); - const resultingUnspentTxOuts = aUnspentTxOuts - .filter(((uTxO) => !findUnspentTxOut(uTxO.txOutId, uTxO.txOutIndex, consumedTxOuts))) - .concat(newUnspentTxOuts); - return resultingUnspentTxOuts; -}; -const processTransactions = (aTransactions, aUnspentTxOuts, blockIndex) => { - if (!validateBlockTransactions(aTransactions, aUnspentTxOuts, blockIndex)) { - console.log('invalid block transactions'); - return null; - } - return updateUnspentTxOuts(aTransactions, aUnspentTxOuts); -}; -exports.processTransactions = processTransactions; -const toHexString = (byteArray) => { - return Array.from(byteArray, (byte) => { - return ('0' + (byte & 0xFF).toString(16)).slice(-2); - }).join(''); -}; -const getPublicKey = (aPrivateKey) => { - return ec.keyFromPrivate(aPrivateKey, 'hex').getPublic().encode('hex'); -}; -exports.getPublicKey = getPublicKey; -const isValidTxInStructure = (txIn) => { - if (txIn == null) { - console.log('txIn is null'); - return false; - } - else if (typeof txIn.signature !== 'string') { - console.log('invalid signature type in txIn'); - return false; - } - else if (typeof txIn.txOutId !== 'string') { - console.log('invalid txOutId type in txIn'); - return false; - } - else if (typeof txIn.txOutIndex !== 'number') { - console.log('invalid txOutIndex type in txIn'); - return false; - } - else { - return true; - } -}; -const isValidTxOutStructure = (txOut) => { - if (txOut == null) { - console.log('txOut is null'); - return false; - } - else if (typeof txOut.address !== 'string') { - console.log('invalid address type in txOut'); - return false; - } - else if (!isValidAddress(txOut.address)) { - console.log('invalid TxOut address'); - return false; - } - else if (typeof txOut.amount !== 'number') { - console.log('invalid amount type in txOut'); - return false; - } - else { - return true; - } -}; -const isValidTransactionStructure = (transaction) => { - if (typeof transaction.id !== 'string') { - console.log('transactionId missing'); - return false; - } - if (!(transaction.txIns instanceof Array)) { - console.log('invalid txIns type in transaction'); - return false; - } - if (!transaction.txIns - .map(isValidTxInStructure) - .reduce((a, b) => (a && b), true)) { - return false; - } - if (!(transaction.txOuts instanceof Array)) { - console.log('invalid txIns type in transaction'); - return false; - } - if (!transaction.txOuts - .map(isValidTxOutStructure) - .reduce((a, b) => (a && b), true)) { - return false; - } - return true; -}; -// valid address is a valid ecdsa public key in the 04 + X-coordinate + Y-coordinate format -const isValidAddress = (address) => { - if (address.length !== 130) { - console.log(address); - console.log('invalid public key length'); - return false; - } - else if (address.match('^[a-fA-F0-9]+$') === null) { - console.log('public key must contain only hex characters'); - return false; - } - else if (!address.startsWith('04')) { - console.log('public key must start with 04'); - return false; - } - return true; -}; -exports.isValidAddress = isValidAddress; -//# sourceMappingURL=transaction.js.map \ No newline at end of file diff --git a/cloud/src/transaction.js.map b/cloud/src/transaction.js.map deleted file mode 100644 index fd33576..0000000 --- a/cloud/src/transaction.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"transaction.js","sourceRoot":"","sources":["transaction.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/cloud/src/transactionPool.js b/cloud/src/transactionPool.js deleted file mode 100644 index c7a53d3..0000000 --- a/cloud/src/transactionPool.js +++ /dev/null @@ -1,64 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const _ = require("lodash"); -const transaction_1 = require("./transaction"); -let transactionPool = []; -const getTransactionPool = () => { - return _.cloneDeep(transactionPool); -}; -exports.getTransactionPool = getTransactionPool; -const addToTransactionPool = (tx, unspentTxOuts) => { - if (!transaction_1.validateTransaction(tx, unspentTxOuts)) { - throw Error('Trying to add invalid tx to pool'); - } - if (!isValidTxForPool(tx, transactionPool)) { - throw Error('Trying to add invalid tx to pool'); - } - console.log('adding to txPool: %s', JSON.stringify(tx)); - transactionPool.push(tx); -}; -exports.addToTransactionPool = addToTransactionPool; -const hasTxIn = (txIn, unspentTxOuts) => { - const foundTxIn = unspentTxOuts.find((uTxO) => { - return uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex; - }); - return foundTxIn !== undefined; -}; -const updateTransactionPool = (unspentTxOuts) => { - const invalidTxs = []; - for (const tx of transactionPool) { - for (const txIn of tx.txIns) { - if (!hasTxIn(txIn, unspentTxOuts)) { - invalidTxs.push(tx); - break; - } - } - } - if (invalidTxs.length > 0) { - console.log('removing the following transactions from txPool: %s', JSON.stringify(invalidTxs)); - transactionPool = _.without(transactionPool, ...invalidTxs); - } -}; -exports.updateTransactionPool = updateTransactionPool; -const getTxPoolIns = (aTransactionPool) => { - return _(aTransactionPool) - .map((tx) => tx.txIns) - .flatten() - .value(); -}; -const isValidTxForPool = (tx, aTtransactionPool) => { - const txPoolIns = getTxPoolIns(aTtransactionPool); - const containsTxIn = (txIns, txIn) => { - return _.find(txPoolIns, ((txPoolIn) => { - return txIn.txOutIndex === txPoolIn.txOutIndex && txIn.txOutId === txPoolIn.txOutId; - })); - }; - for (const txIn of tx.txIns) { - if (containsTxIn(txPoolIns, txIn)) { - console.log('txIn already found in the txPool'); - return false; - } - } - return true; -}; -//# sourceMappingURL=transactionPool.js.map \ No newline at end of file diff --git a/cloud/src/transactionPool.js.map b/cloud/src/transactionPool.js.map deleted file mode 100644 index 50a6e7c..0000000 --- a/cloud/src/transactionPool.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"transactionPool.js","sourceRoot":"","sources":["transactionPool.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/cloud/src/util.js b/cloud/src/util.js deleted file mode 100644 index 9ccd8be..0000000 --- a/cloud/src/util.js +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const hexToBinary = (s) => { - let ret = ''; - const lookupTable = { - '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', - '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', - 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', - 'e': '1110', 'f': '1111' - }; - for (let i = 0; i < s.length; i = i + 1) { - if (lookupTable[s[i]]) { - ret += lookupTable[s[i]]; - } - else { - return null; - } - } - return ret; -}; -exports.hexToBinary = hexToBinary; -//# sourceMappingURL=util.js.map \ No newline at end of file diff --git a/cloud/src/util.js.map b/cloud/src/util.js.map deleted file mode 100644 index c8d4f6c..0000000 --- a/cloud/src/util.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"util.js","sourceRoot":"","sources":["util.ts"],"names":[],"mappings":";;AAAA,MAAM,WAAW,GAAG,CAAC,CAAS;IAC1B,IAAI,GAAG,GAAW,EAAE,CAAC;IACrB,MAAM,WAAW,GAAG;QAChB,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAC/D,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAC/D,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAClD,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;KAC3B,CAAC;IACF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpB,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,MAAM,CAAC,GAAG,CAAC;AACf,CAAC,CAAC;AAEM,kCAAW"} \ No newline at end of file diff --git a/cloud/src/wallet.js b/cloud/src/wallet.js deleted file mode 100644 index 0501bf4..0000000 --- a/cloud/src/wallet.js +++ /dev/null @@ -1,120 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const elliptic_1 = require("elliptic"); -const fs_1 = require("fs"); -const _ = require("lodash"); -const transaction_1 = require("./transaction"); -const EC = new elliptic_1.ec('secp256k1'); -const privateKeyLocation = process.env.PRIVATE_KEY || 'node/wallet/private_key'; -const getPrivateFromWallet = () => { - const buffer = fs_1.readFileSync(privateKeyLocation, 'utf8'); - return buffer.toString(); -}; -exports.getPrivateFromWallet = getPrivateFromWallet; -const getPublicFromWallet = () => { - const privateKey = getPrivateFromWallet(); - const key = EC.keyFromPrivate(privateKey, 'hex'); - return key.getPublic().encode('hex'); -}; -exports.getPublicFromWallet = getPublicFromWallet; -const generatePrivateKey = () => { - const keyPair = EC.genKeyPair(); - const privateKey = keyPair.getPrivate(); - return privateKey.toString(16); -}; -exports.generatePrivateKey = generatePrivateKey; -const initWallet = () => { - // let's not override existing private keys - if (fs_1.existsSync(privateKeyLocation)) { - return; - } - const newPrivateKey = generatePrivateKey(); - fs_1.writeFileSync(privateKeyLocation, newPrivateKey); - console.log('new wallet with private key created to : %s', privateKeyLocation); -}; -exports.initWallet = initWallet; -const deleteWallet = () => { - if (fs_1.existsSync(privateKeyLocation)) { - fs_1.unlinkSync(privateKeyLocation); - } -}; -exports.deleteWallet = deleteWallet; -const getBalance = (address, unspentTxOuts) => { - return _(findUnspentTxOuts(address, unspentTxOuts)) - .map((uTxO) => uTxO.amount) - .sum(); -}; -exports.getBalance = getBalance; -const findUnspentTxOuts = (ownerAddress, unspentTxOuts) => { - return _.filter(unspentTxOuts, (uTxO) => uTxO.address === ownerAddress); -}; -exports.findUnspentTxOuts = findUnspentTxOuts; -const findTxOutsForAmount = (amount, myUnspentTxOuts) => { - let currentAmount = 0; - const includedUnspentTxOuts = []; - for (const myUnspentTxOut of myUnspentTxOuts) { - includedUnspentTxOuts.push(myUnspentTxOut); - currentAmount = currentAmount + myUnspentTxOut.amount; - if (currentAmount >= amount) { - const leftOverAmount = currentAmount - amount; - return { includedUnspentTxOuts, leftOverAmount }; - } - } - const eMsg = 'Cannot create transaction from the available unspent transaction outputs.' + - ' Required amount:' + amount + '. Available unspentTxOuts:' + JSON.stringify(myUnspentTxOuts); - throw Error(eMsg); -}; -const createTxOuts = (receiverAddress, myAddress, amount, leftOverAmount) => { - const txOut1 = new transaction_1.TxOut(receiverAddress, amount); - if (leftOverAmount === 0) { - return [txOut1]; - } - else { - const leftOverTx = new transaction_1.TxOut(myAddress, leftOverAmount); - return [txOut1, leftOverTx]; - } -}; -const filterTxPoolTxs = (unspentTxOuts, transactionPool) => { - const txIns = _(transactionPool) - .map((tx) => tx.txIns) - .flatten() - .value(); - const removable = []; - for (const unspentTxOut of unspentTxOuts) { - const txIn = _.find(txIns, (aTxIn) => { - return aTxIn.txOutIndex === unspentTxOut.txOutIndex && aTxIn.txOutId === unspentTxOut.txOutId; - }); - if (txIn === undefined) { - } - else { - removable.push(unspentTxOut); - } - } - return _.without(unspentTxOuts, ...removable); -}; -const createTransaction = (receiverAddress, amount, privateKey, unspentTxOuts, txPool) => { - console.log('txPool: %s', JSON.stringify(txPool)); - const myAddress = transaction_1.getPublicKey(privateKey); - const myUnspentTxOutsA = unspentTxOuts.filter((uTxO) => uTxO.address === myAddress); - const myUnspentTxOuts = filterTxPoolTxs(myUnspentTxOutsA, txPool); - // filter from unspentOutputs such inputs that are referenced in pool - const { includedUnspentTxOuts, leftOverAmount } = findTxOutsForAmount(amount, myUnspentTxOuts); - const toUnsignedTxIn = (unspentTxOut) => { - const txIn = new transaction_1.TxIn(); - txIn.txOutId = unspentTxOut.txOutId; - txIn.txOutIndex = unspentTxOut.txOutIndex; - return txIn; - }; - const unsignedTxIns = includedUnspentTxOuts.map(toUnsignedTxIn); - const tx = new transaction_1.Transaction(); - tx.txIns = unsignedTxIns; - tx.txOuts = createTxOuts(receiverAddress, myAddress, amount, leftOverAmount); - tx.id = transaction_1.getTransactionId(tx); - tx.txIns = tx.txIns.map((txIn, index) => { - txIn.signature = transaction_1.signTxIn(tx, index, privateKey, unspentTxOuts); - return txIn; - }); - return tx; -}; -exports.createTransaction = createTransaction; -//# sourceMappingURL=wallet.js.map \ No newline at end of file diff --git a/cloud/src/wallet.js.map b/cloud/src/wallet.js.map deleted file mode 100644 index 5895928..0000000 --- a/cloud/src/wallet.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"wallet.js","sourceRoot":"","sources":["wallet.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dew/.gitignore b/dew/.gitignore deleted file mode 100644 index e5d4fe4..0000000 --- a/dew/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -npm-debug.log -.idea -src/*.js -src/*.map diff --git a/dew/src/.gitignore b/dew/src/.gitignore deleted file mode 100644 index 086f4e2..0000000 --- a/dew/src/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.js -*.map diff --git a/dew/src/blockchain.js b/dew/src/blockchain.js deleted file mode 100644 index 1b51687..0000000 --- a/dew/src/blockchain.js +++ /dev/null @@ -1,261 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const CryptoJS = require("crypto-js"); -const _ = require("lodash"); -const p2p_1 = require("./p2p"); -const transaction_1 = require("./transaction"); -const transactionPool_1 = require("./transactionPool"); -const util_1 = require("./util"); -const wallet_1 = require("./wallet"); -class Block { - constructor(index, hash, previousHash, timestamp, data, difficulty, nonce) { - this.index = index; - this.previousHash = previousHash; - this.timestamp = timestamp; - this.data = data; - this.hash = hash; - this.difficulty = difficulty; - this.nonce = nonce; - } -} -exports.Block = Block; -const genesisTransaction = { - 'txIns': [{ 'signature': '', 'txOutId': '', 'txOutIndex': 0 }], - 'txOuts': [{ - 'address': '04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534a', - 'amount': 50 - }], - 'id': 'e655f6a5f26dc9b4cac6e46f52336428287759cf81ef5ff10854f69d68f43fa3' -}; -const genesisBlock = new Block(0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1465154705, [genesisTransaction], 0, 0); -let blockchain = [genesisBlock]; -// the unspent txOut of genesis block is set to unspentTxOuts on startup -let unspentTxOuts = transaction_1.processTransactions(blockchain[0].data, [], 0); -const getBlockchain = () => blockchain; -exports.getBlockchain = getBlockchain; -const getUnspentTxOuts = () => _.cloneDeep(unspentTxOuts); -exports.getUnspentTxOuts = getUnspentTxOuts; -// and txPool should be only updated at the same time -const setUnspentTxOuts = (newUnspentTxOut) => { - console.log('replacing unspentTxouts with: %s', newUnspentTxOut); - unspentTxOuts = newUnspentTxOut; -}; -const getLatestBlock = () => blockchain[blockchain.length - 1]; -exports.getLatestBlock = getLatestBlock; -// in seconds -const BLOCK_GENERATION_INTERVAL = 10; -// in blocks -const DIFFICULTY_ADJUSTMENT_INTERVAL = 10; -const getDifficulty = (aBlockchain) => { - const latestBlock = aBlockchain[blockchain.length - 1]; - if (latestBlock.index % DIFFICULTY_ADJUSTMENT_INTERVAL === 0 && latestBlock.index !== 0) { - return getAdjustedDifficulty(latestBlock, aBlockchain); - } - else { - return latestBlock.difficulty; - } -}; -const getAdjustedDifficulty = (latestBlock, aBlockchain) => { - const prevAdjustmentBlock = aBlockchain[blockchain.length - DIFFICULTY_ADJUSTMENT_INTERVAL]; - const timeExpected = BLOCK_GENERATION_INTERVAL * DIFFICULTY_ADJUSTMENT_INTERVAL; - const timeTaken = latestBlock.timestamp - prevAdjustmentBlock.timestamp; - if (timeTaken < timeExpected / 2) { - return prevAdjustmentBlock.difficulty + 1; - } - else if (timeTaken > timeExpected * 2) { - return prevAdjustmentBlock.difficulty - 1; - } - else { - return prevAdjustmentBlock.difficulty; - } -}; -const getCurrentTimestamp = () => Math.round(new Date().getTime() / 1000); -const generateRawNextBlock = (blockData) => { - const previousBlock = getLatestBlock(); - const difficulty = getDifficulty(getBlockchain()); - const nextIndex = previousBlock.index + 1; - const nextTimestamp = getCurrentTimestamp(); - const newBlock = findBlock(nextIndex, previousBlock.hash, nextTimestamp, blockData, difficulty); - if (addBlockToChain(newBlock)) { - p2p_1.broadcastLatest(); - return newBlock; - } - else { - return null; - } -}; -exports.generateRawNextBlock = generateRawNextBlock; -// gets the unspent transaction outputs owned by the wallet -const getMyUnspentTransactionOutputs = () => { - return wallet_1.findUnspentTxOuts(wallet_1.getPublicFromWallet(), getUnspentTxOuts()); -}; -exports.getMyUnspentTransactionOutputs = getMyUnspentTransactionOutputs; -const generateNextBlock = () => { - const coinbaseTx = transaction_1.getCoinbaseTransaction(wallet_1.getPublicFromWallet(), getLatestBlock().index + 1); - const blockData = [coinbaseTx].concat(transactionPool_1.getTransactionPool()); - return generateRawNextBlock(blockData); -}; -exports.generateNextBlock = generateNextBlock; -const generatenextBlockWithTransaction = (receiverAddress, amount) => { - if (!transaction_1.isValidAddress(receiverAddress)) { - throw Error('invalid address'); - } - if (typeof amount !== 'number') { - throw Error('invalid amount'); - } - const coinbaseTx = transaction_1.getCoinbaseTransaction(wallet_1.getPublicFromWallet(), getLatestBlock().index + 1); - const tx = wallet_1.createTransaction(receiverAddress, amount, wallet_1.getPrivateFromWallet(), getUnspentTxOuts(), transactionPool_1.getTransactionPool()); - const blockData = [coinbaseTx, tx]; - return generateRawNextBlock(blockData); -}; -exports.generatenextBlockWithTransaction = generatenextBlockWithTransaction; -const findBlock = (index, previousHash, timestamp, data, difficulty) => { - let nonce = 0; - while (true) { - const hash = calculateHash(index, previousHash, timestamp, data, difficulty, nonce); - if (hashMatchesDifficulty(hash, difficulty)) { - return new Block(index, hash, previousHash, timestamp, data, difficulty, nonce); - } - nonce++; - } -}; -const getAccountBalance = () => { - return wallet_1.getBalance(wallet_1.getPublicFromWallet(), getUnspentTxOuts()); -}; -exports.getAccountBalance = getAccountBalance; -const sendTransaction = (address, amount) => { - const tx = wallet_1.createTransaction(address, amount, wallet_1.getPrivateFromWallet(), getUnspentTxOuts(), transactionPool_1.getTransactionPool()); - transactionPool_1.addToTransactionPool(tx, getUnspentTxOuts()); - p2p_1.broadCastTransactionPool(); - return tx; -}; -exports.sendTransaction = sendTransaction; -const calculateHashForBlock = (block) => calculateHash(block.index, block.previousHash, block.timestamp, block.data, block.difficulty, block.nonce); -const calculateHash = (index, previousHash, timestamp, data, difficulty, nonce) => CryptoJS.SHA256(index + previousHash + timestamp + data + difficulty + nonce).toString(); -const isValidBlockStructure = (block) => { - return typeof block.index === 'number' - && typeof block.hash === 'string' - && typeof block.previousHash === 'string' - && typeof block.timestamp === 'number' - && typeof block.data === 'object'; -}; -exports.isValidBlockStructure = isValidBlockStructure; -const isValidNewBlock = (newBlock, previousBlock) => { - if (!isValidBlockStructure(newBlock)) { - console.log('invalid block structure: %s', JSON.stringify(newBlock)); - return false; - } - if (previousBlock.index + 1 !== newBlock.index) { - console.log('invalid index'); - return false; - } - else if (previousBlock.hash !== newBlock.previousHash) { - console.log('invalid previoushash'); - return false; - } - else if (!isValidTimestamp(newBlock, previousBlock)) { - console.log('invalid timestamp'); - return false; - } - else if (!hasValidHash(newBlock)) { - return false; - } - return true; -}; -const getAccumulatedDifficulty = (aBlockchain) => { - return aBlockchain - .map((block) => block.difficulty) - .map((difficulty) => Math.pow(2, difficulty)) - .reduce((a, b) => a + b); -}; -const isValidTimestamp = (newBlock, previousBlock) => { - return (previousBlock.timestamp - 60 < newBlock.timestamp) - && newBlock.timestamp - 60 < getCurrentTimestamp(); -}; -const hasValidHash = (block) => { - if (!hashMatchesBlockContent(block)) { - console.log('invalid hash, got:' + block.hash); - return false; - } - if (!hashMatchesDifficulty(block.hash, block.difficulty)) { - console.log('block difficulty not satisfied. Expected: ' + block.difficulty + 'got: ' + block.hash); - } - return true; -}; -const hashMatchesBlockContent = (block) => { - const blockHash = calculateHashForBlock(block); - return blockHash === block.hash; -}; -const hashMatchesDifficulty = (hash, difficulty) => { - const hashInBinary = util_1.hexToBinary(hash); - const requiredPrefix = '0'.repeat(difficulty); - return hashInBinary.startsWith(requiredPrefix); -}; -/* - Checks if the given blockchain is valid. Return the unspent txOuts if the chain is valid - */ -const isValidChain = (blockchainToValidate) => { - console.log('isValidChain:'); - console.log(JSON.stringify(blockchainToValidate)); - const isValidGenesis = (block) => { - return JSON.stringify(block) === JSON.stringify(genesisBlock); - }; - if (!isValidGenesis(blockchainToValidate[0])) { - return null; - } - /* - Validate each block in the chain. The block is valid if the block structure is valid - and the transaction are valid - */ - let aUnspentTxOuts = []; - for (let i = 0; i < blockchainToValidate.length; i++) { - const currentBlock = blockchainToValidate[i]; - if (i !== 0 && !isValidNewBlock(blockchainToValidate[i], blockchainToValidate[i - 1])) { - return null; - } - aUnspentTxOuts = transaction_1.processTransactions(currentBlock.data, aUnspentTxOuts, currentBlock.index); - if (aUnspentTxOuts === null) { - console.log('invalid transactions in blockchain'); - return null; - } - } - return aUnspentTxOuts; -}; -const addBlockToChain = (newBlock) => { - if (isValidNewBlock(newBlock, getLatestBlock())) { - const retVal = transaction_1.processTransactions(newBlock.data, getUnspentTxOuts(), newBlock.index); - if (retVal === null) { - console.log('block is not valid in terms of transactions'); - return false; - } - else { - blockchain.push(newBlock); - setUnspentTxOuts(retVal); - transactionPool_1.updateTransactionPool(unspentTxOuts); - return true; - } - } - return false; -}; -exports.addBlockToChain = addBlockToChain; -const replaceChain = (newBlocks) => { - const aUnspentTxOuts = isValidChain(newBlocks); - const validChain = aUnspentTxOuts !== null; - if (validChain && - getAccumulatedDifficulty(newBlocks) > getAccumulatedDifficulty(getBlockchain())) { - console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); - blockchain = newBlocks; - setUnspentTxOuts(aUnspentTxOuts); - transactionPool_1.updateTransactionPool(unspentTxOuts); - p2p_1.broadcastLatest(); - } - else { - console.log('Received blockchain invalid'); - } -}; -exports.replaceChain = replaceChain; -const handleReceivedTransaction = (transaction) => { - transactionPool_1.addToTransactionPool(transaction, getUnspentTxOuts()); -}; -exports.handleReceivedTransaction = handleReceivedTransaction; -//# sourceMappingURL=blockchain.js.map \ No newline at end of file diff --git a/dew/src/blockchain.js.map b/dew/src/blockchain.js.map deleted file mode 100644 index 94bd3e2..0000000 --- a/dew/src/blockchain.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"blockchain.js","sourceRoot":"","sources":["blockchain.ts"],"names":[],"mappings":";;AAAA,sCAAsC;AACtC,4BAA4B;AAC5B,+BAAgE;AAChE,+CAEuB;AACvB,uDAAkG;AAClG,iCAAmC;AACnC,qCAAqH;AAErH;IAUI,YAAY,KAAa,EAAE,IAAY,EAAE,YAAoB,EACjD,SAAiB,EAAE,IAAmB,EAAE,UAAkB,EAAE,KAAa;QACjF,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;CACJ;AAwQG,sBAAK;AAtQT,MAAM,kBAAkB,GAAG;IACvB,OAAO,EAAE,CAAC,EAAC,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,EAAC,CAAC;IAC5D,QAAQ,EAAE,CAAC;YACP,SAAS,EAAE,oIAAoI;YAC/I,QAAQ,EAAE,EAAE;SACf,CAAC;IACF,IAAI,EAAE,kEAAkE;CAC3E,CAAC;AAEF,MAAM,YAAY,GAAU,IAAI,KAAK,CACjC,CAAC,EAAE,kEAAkE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,EAAE,CAAC,CACpH,CAAC;AAEF,IAAI,UAAU,GAAY,CAAC,YAAY,CAAC,CAAC;AAEzC,wEAAwE;AACxE,IAAI,aAAa,GAAmB,iCAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAEnF,MAAM,aAAa,GAAG,MAAe,UAAU,CAAC;AAoPrC,sCAAa;AAlPxB,MAAM,gBAAgB,GAAG,MAAsB,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;AAkPhD,4CAAgB;AAhP1C,qDAAqD;AACrD,MAAM,gBAAgB,GAAG,CAAC,eAA+B;IACrD,OAAO,CAAC,GAAG,CAAC,kCAAkC,EAAE,eAAe,CAAC,CAAC;IACjE,aAAa,GAAG,eAAe,CAAC;AACpC,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,MAAa,UAAU,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AA0O1B,wCAAc;AAxO1D,aAAa;AACb,MAAM,yBAAyB,GAAW,EAAE,CAAC;AAE7C,YAAY;AACZ,MAAM,8BAA8B,GAAW,EAAE,CAAC;AAElD,MAAM,aAAa,GAAG,CAAC,WAAoB;IACvC,MAAM,WAAW,GAAU,WAAW,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9D,EAAE,CAAC,CAAC,WAAW,CAAC,KAAK,GAAG,8BAA8B,KAAK,CAAC,IAAI,WAAW,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC;QACtF,MAAM,CAAC,qBAAqB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC3D,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC;IAClC,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,WAAkB,EAAE,WAAoB;IACnE,MAAM,mBAAmB,GAAU,WAAW,CAAC,UAAU,CAAC,MAAM,GAAG,8BAA8B,CAAC,CAAC;IACnG,MAAM,YAAY,GAAW,yBAAyB,GAAG,8BAA8B,CAAC;IACxF,MAAM,SAAS,GAAW,WAAW,CAAC,SAAS,GAAG,mBAAmB,CAAC,SAAS,CAAC;IAChF,EAAE,CAAC,CAAC,SAAS,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,mBAAmB,CAAC,UAAU,GAAG,CAAC,CAAC;IAC9C,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC,SAAS,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC;QACtC,MAAM,CAAC,mBAAmB,CAAC,UAAU,GAAG,CAAC,CAAC;IAC9C,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,mBAAmB,CAAC,UAAU,CAAC;IAC1C,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,MAAc,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,CAAC;AAElF,MAAM,oBAAoB,GAAG,CAAC,SAAwB;IAClD,MAAM,aAAa,GAAU,cAAc,EAAE,CAAC;IAC9C,MAAM,UAAU,GAAW,aAAa,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAW,aAAa,CAAC,KAAK,GAAG,CAAC,CAAC;IAClD,MAAM,aAAa,GAAW,mBAAmB,EAAE,CAAC;IACpD,MAAM,QAAQ,GAAU,SAAS,CAAC,SAAS,EAAE,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IACvG,EAAE,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC5B,qBAAe,EAAE,CAAC;QAClB,MAAM,CAAC,QAAQ,CAAC;IACpB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,MAAM,CAAC,IAAI,CAAC;IAChB,CAAC;AAEL,CAAC,CAAC;AA8LE,oDAAoB;AA5LxB,2DAA2D;AAC3D,MAAM,8BAA8B,GAAG;IACnC,MAAM,CAAC,0BAAiB,CAAC,4BAAmB,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;AACxE,CAAC,CAAC;AA0L6B,wEAA8B;AAxL7D,MAAM,iBAAiB,GAAG;IACtB,MAAM,UAAU,GAAgB,oCAAsB,CAAC,4BAAmB,EAAE,EAAE,cAAc,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC1G,MAAM,SAAS,GAAkB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,oCAAkB,EAAE,CAAC,CAAC;IAC3E,MAAM,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC,CAAC;AAmLwB,8CAAiB;AAjL3C,MAAM,gCAAgC,GAAG,CAAC,eAAuB,EAAE,MAAc;IAC7E,EAAE,CAAC,CAAC,CAAC,4BAAc,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,KAAK,CAAC,iBAAiB,CAAC,CAAC;IACnC,CAAC;IACD,EAAE,CAAC,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC;QAC7B,MAAM,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,UAAU,GAAgB,oCAAsB,CAAC,4BAAmB,EAAE,EAAE,cAAc,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC1G,MAAM,EAAE,GAAgB,0BAAiB,CAAC,eAAe,EAAE,MAAM,EAAE,6BAAoB,EAAE,EAAE,gBAAgB,EAAE,EAAE,oCAAkB,EAAE,CAAC,CAAC;IACrI,MAAM,SAAS,GAAkB,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAClD,MAAM,CAAC,oBAAoB,CAAC,SAAS,CAAC,CAAC;AAC3C,CAAC,CAAC;AAsK2C,4EAAgC;AApK7E,MAAM,SAAS,GAAG,CAAC,KAAa,EAAE,YAAoB,EAAE,SAAiB,EAAE,IAAmB,EAAE,UAAkB;IAC9G,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,GAAW,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAC5F,EAAE,CAAC,CAAC,qBAAqB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;YAC1C,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QACpF,CAAC;QACD,KAAK,EAAE,CAAC;IACZ,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG;IACtB,MAAM,CAAC,mBAAU,CAAC,4BAAmB,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;AACjE,CAAC,CAAC;AAyJE,8CAAiB;AAvJrB,MAAM,eAAe,GAAG,CAAC,OAAe,EAAE,MAAc;IACpD,MAAM,EAAE,GAAgB,0BAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,6BAAoB,EAAE,EAAE,gBAAgB,EAAE,EAAE,oCAAkB,EAAE,CAAC,CAAC;IAC7H,sCAAoB,CAAC,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC7C,8BAAwB,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,CAAC;AACd,CAAC,CAAC;AA+I0D,0CAAe;AA7I3E,MAAM,qBAAqB,GAAG,CAAC,KAAY,KACvC,aAAa,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;AAE/G,MAAM,aAAa,GAAG,CAAC,KAAa,EAAE,YAAoB,EAAE,SAAiB,EAAE,IAAmB,EAC3E,UAAkB,EAAE,KAAa,KACpD,QAAQ,CAAC,MAAM,CAAC,KAAK,GAAG,YAAY,GAAG,SAAS,GAAG,IAAI,GAAG,UAAU,GAAG,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;AAE7F,MAAM,qBAAqB,GAAG,CAAC,KAAY;IACvC,MAAM,CAAC,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;WAC/B,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;WAC9B,OAAO,KAAK,CAAC,YAAY,KAAK,QAAQ;WACtC,OAAO,KAAK,CAAC,SAAS,KAAK,QAAQ;WACnC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC1C,CAAC,CAAC;AAmIqB,sDAAqB;AAjI5C,MAAM,eAAe,GAAG,CAAC,QAAe,EAAE,aAAoB;IAC1D,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QACrE,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;IACD,EAAE,CAAC,CAAC,aAAa,CAAC,KAAK,GAAG,CAAC,KAAK,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC7B,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC,aAAa,CAAC,IAAI,KAAK,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;IAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,wBAAwB,GAAG,CAAC,WAAoB;IAClD,MAAM,CAAC,WAAW;SACb,GAAG,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,UAAU,CAAC;SAChC,GAAG,CAAC,CAAC,UAAU,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;SAC5C,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,QAAe,EAAE,aAAoB;IAC3D,MAAM,CAAC,CAAE,aAAa,CAAC,SAAS,GAAG,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAE;WACrD,QAAQ,CAAC,SAAS,GAAG,EAAE,GAAG,mBAAmB,EAAE,CAAC;AAC3D,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,KAAY;IAE9B,EAAE,CAAC,CAAC,CAAC,uBAAuB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/C,MAAM,CAAC,KAAK,CAAC;IACjB,CAAC;IAED,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,4CAA4C,GAAG,KAAK,CAAC,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IACxG,CAAC;IACD,MAAM,CAAC,IAAI,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,uBAAuB,GAAG,CAAC,KAAY;IACzC,MAAM,SAAS,GAAW,qBAAqB,CAAC,KAAK,CAAC,CAAC;IACvD,MAAM,CAAC,SAAS,KAAK,KAAK,CAAC,IAAI,CAAC;AACpC,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAE,UAAkB;IAC3D,MAAM,YAAY,GAAW,kBAAW,CAAC,IAAI,CAAC,CAAC;IAC/C,MAAM,cAAc,GAAW,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,CAAC,YAAY,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;AACnD,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,YAAY,GAAG,CAAC,oBAA6B;IAC/C,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAC7B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,CAAC,KAAY;QAChC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAClE,CAAC,CAAC;IAEF,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,IAAI,CAAC;IAChB,CAAC;IACD;;;OAGG;IACH,IAAI,cAAc,GAAmB,EAAE,CAAC;IAExC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,oBAAoB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnD,MAAM,YAAY,GAAU,oBAAoB,CAAC,CAAC,CAAC,CAAC;QACpD,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,oBAAoB,CAAC,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpF,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC;QAED,cAAc,GAAG,iCAAmB,CAAC,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QAC5F,EAAE,CAAC,CAAC,cAAc,KAAK,IAAI,CAAC,CAAC,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;YAClD,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,MAAM,CAAC,cAAc,CAAC;AAC1B,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CAAC,QAAe;IACpC,EAAE,CAAC,CAAC,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAmB,iCAAmB,CAAC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,EAAE,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;QACtG,EAAE,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;YAC3D,MAAM,CAAC,KAAK,CAAC;QACjB,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC1B,gBAAgB,CAAC,MAAM,CAAC,CAAC;YACzB,uCAAqB,CAAC,aAAa,CAAC,CAAC;YACrC,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,MAAM,CAAC,KAAK,CAAC;AACjB,CAAC,CAAC;AAyB0D,0CAAe;AAvB3E,MAAM,YAAY,GAAG,CAAC,SAAkB;IACpC,MAAM,cAAc,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAY,cAAc,KAAK,IAAI,CAAC;IACpD,EAAE,CAAC,CAAC,UAAU;QACV,wBAAwB,CAAC,SAAS,CAAC,GAAG,wBAAwB,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC;QAClF,OAAO,CAAC,GAAG,CAAC,qFAAqF,CAAC,CAAC;QACnG,UAAU,GAAG,SAAS,CAAC;QACvB,gBAAgB,CAAC,cAAc,CAAC,CAAC;QACjC,uCAAqB,CAAC,aAAa,CAAC,CAAC;QACrC,qBAAe,EAAE,CAAC;IACtB,CAAC;IAAC,IAAI,CAAC,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;IAC/C,CAAC;AACL,CAAC,CAAC;AAU4C,oCAAY;AAR1D,MAAM,yBAAyB,GAAG,CAAC,WAAwB;IACvD,sCAAoB,CAAC,WAAW,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAC1D,CAAC,CAAC;AAKE,8DAAyB"} \ No newline at end of file diff --git a/dew/src/main.js b/dew/src/main.js deleted file mode 100644 index 2bb1a93..0000000 --- a/dew/src/main.js +++ /dev/null @@ -1,122 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const bodyParser = require("body-parser"); -const express = require("express"); -const _ = require("lodash"); -const blockchain_1 = require("./blockchain"); -const p2p_1 = require("./p2p"); -const transactionPool_1 = require("./transactionPool"); -const wallet_1 = require("./wallet"); -const httpPort = parseInt(process.env.HTTP_PORT) || 3001; -const p2pPort = parseInt(process.env.P2P_PORT) || 6001; -const initHttpServer = (myHttpPort) => { - const app = express(); - app.use(bodyParser.json()); - app.use((err, req, res, next) => { - if (err) { - res.status(400).send(err.message); - } - }); - app.get('/blocks', (req, res) => { - res.send(blockchain_1.getBlockchain()); - }); - app.get('/block/:hash', (req, res) => { - const block = _.find(blockchain_1.getBlockchain(), { 'hash': req.params.hash }); - res.send(block); - }); - app.get('/transaction/:id', (req, res) => { - const tx = _(blockchain_1.getBlockchain()) - .map((blocks) => blocks.data) - .flatten() - .find({ 'id': req.params.id }); - res.send(tx); - }); - app.get('/address/:address', (req, res) => { - const unspentTxOuts = _.filter(blockchain_1.getUnspentTxOuts(), (uTxO) => uTxO.address === req.params.address); - res.send({ 'unspentTxOuts': unspentTxOuts }); - }); - app.get('/unspentTransactionOutputs', (req, res) => { - res.send(blockchain_1.getUnspentTxOuts()); - }); - app.get('/myUnspentTransactionOutputs', (req, res) => { - res.send(blockchain_1.getMyUnspentTransactionOutputs()); - }); - app.post('/mineRawBlock', (req, res) => { - if (req.body.data == null) { - res.send('data parameter is missing'); - return; - } - const newBlock = blockchain_1.generateRawNextBlock(req.body.data); - if (newBlock === null) { - res.status(400).send('could not generate block'); - } - else { - res.send(newBlock); - } - }); - app.post('/mineBlock', (req, res) => { - const newBlock = blockchain_1.generateNextBlock(); - if (newBlock === null) { - res.status(400).send('could not generate block'); - } - else { - res.send(newBlock); - } - }); - app.get('/balance', (req, res) => { - const balance = blockchain_1.getAccountBalance(); - res.send({ 'balance': balance }); - }); - app.get('/address', (req, res) => { - const address = wallet_1.getPublicFromWallet(); - res.send({ 'address': address }); - }); - app.post('/mineTransaction', (req, res) => { - const address = req.body.address; - const amount = req.body.amount; - try { - const resp = blockchain_1.generatenextBlockWithTransaction(address, amount); - res.send(resp); - } - catch (e) { - console.log(e.message); - res.status(400).send(e.message); - } - }); - app.post('/sendTransaction', (req, res) => { - try { - const address = req.body.address; - const amount = req.body.amount; - if (address === undefined || amount === undefined) { - throw Error('invalid address or amount'); - } - const resp = blockchain_1.sendTransaction(address, amount); - res.send(resp); - } - catch (e) { - console.log(e.message); - res.status(400).send(e.message); - } - }); - app.get('/transactionPool', (req, res) => { - res.send(transactionPool_1.getTransactionPool()); - }); - app.get('/peers', (req, res) => { - res.send(p2p_1.getSockets().map((s) => s._socket.remoteAddress + ':' + s._socket.remotePort)); - }); - app.post('/addPeer', (req, res) => { - p2p_1.connectToPeers(req.body.peer); - res.send(); - }); - app.post('/stop', (req, res) => { - res.send({ 'msg': 'stopping server' }); - process.exit(); - }); - app.listen(myHttpPort, () => { - console.log('Listening http on port: ' + myHttpPort); - }); -}; -initHttpServer(httpPort); -p2p_1.initP2PServer(p2pPort); -wallet_1.initWallet(); -//# sourceMappingURL=main.js.map \ No newline at end of file diff --git a/dew/src/main.js.map b/dew/src/main.js.map deleted file mode 100644 index b723beb..0000000 --- a/dew/src/main.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dew/src/p2p.js b/dew/src/p2p.js deleted file mode 100644 index db14e7e..0000000 --- a/dew/src/p2p.js +++ /dev/null @@ -1,175 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const WebSocket = require("ws"); -const blockchain_1 = require("./blockchain"); -const transactionPool_1 = require("./transactionPool"); -const sockets = []; -var MessageType; -(function (MessageType) { - MessageType[MessageType["QUERY_LATEST"] = 0] = "QUERY_LATEST"; - MessageType[MessageType["QUERY_ALL"] = 1] = "QUERY_ALL"; - MessageType[MessageType["RESPONSE_BLOCKCHAIN"] = 2] = "RESPONSE_BLOCKCHAIN"; - MessageType[MessageType["QUERY_TRANSACTION_POOL"] = 3] = "QUERY_TRANSACTION_POOL"; - MessageType[MessageType["RESPONSE_TRANSACTION_POOL"] = 4] = "RESPONSE_TRANSACTION_POOL"; -})(MessageType || (MessageType = {})); -class Message { -} -const initP2PServer = (p2pPort) => { - const server = new WebSocket.Server({ port: p2pPort }); - server.on('connection', (ws) => { - initConnection(ws); - }); - console.log('listening websocket p2p port on: ' + p2pPort); -}; -exports.initP2PServer = initP2PServer; -const getSockets = () => sockets; -exports.getSockets = getSockets; -const initConnection = (ws) => { - sockets.push(ws); - initMessageHandler(ws); - initErrorHandler(ws); - write(ws, queryChainLengthMsg()); - // query transactions pool only some time after chain query - setTimeout(() => { - broadcast(queryTransactionPoolMsg()); - }, 500); -}; -const JSONToObject = (data) => { - try { - return JSON.parse(data); - } - catch (e) { - console.log(e); - return null; - } -}; -const initMessageHandler = (ws) => { - ws.on('message', (data) => { - try { - const message = JSONToObject(data); - if (message === null) { - console.log('could not parse received JSON message: ' + data); - return; - } - console.log('Received message: %s', JSON.stringify(message)); - switch (message.type) { - case MessageType.QUERY_LATEST: - write(ws, responseLatestMsg()); - break; - case MessageType.QUERY_ALL: - write(ws, responseChainMsg()); - break; - case MessageType.RESPONSE_BLOCKCHAIN: - const receivedBlocks = JSONToObject(message.data); - if (receivedBlocks === null) { - console.log('invalid blocks received: %s', JSON.stringify(message.data)); - break; - } - handleBlockchainResponse(receivedBlocks); - break; - case MessageType.QUERY_TRANSACTION_POOL: - write(ws, responseTransactionPoolMsg()); - break; - case MessageType.RESPONSE_TRANSACTION_POOL: - const receivedTransactions = JSONToObject(message.data); - if (receivedTransactions === null) { - console.log('invalid transaction received: %s', JSON.stringify(message.data)); - break; - } - receivedTransactions.forEach((transaction) => { - try { - blockchain_1.handleReceivedTransaction(transaction); - // if no error is thrown, transaction was indeed added to the pool - // let's broadcast transaction pool - broadCastTransactionPool(); - } - catch (e) { - console.log(e.message); - } - }); - break; - } - } - catch (e) { - console.log(e); - } - }); -}; -const write = (ws, message) => ws.send(JSON.stringify(message)); -const broadcast = (message) => sockets.forEach((socket) => write(socket, message)); -const queryChainLengthMsg = () => ({ 'type': MessageType.QUERY_LATEST, 'data': null }); -const queryAllMsg = () => ({ 'type': MessageType.QUERY_ALL, 'data': null }); -const responseChainMsg = () => ({ - 'type': MessageType.RESPONSE_BLOCKCHAIN, 'data': JSON.stringify(blockchain_1.getBlockchain()) -}); -const responseLatestMsg = () => ({ - 'type': MessageType.RESPONSE_BLOCKCHAIN, - 'data': JSON.stringify([blockchain_1.getLatestBlock()]) -}); -const queryTransactionPoolMsg = () => ({ - 'type': MessageType.QUERY_TRANSACTION_POOL, - 'data': null -}); -const responseTransactionPoolMsg = () => ({ - 'type': MessageType.RESPONSE_TRANSACTION_POOL, - 'data': JSON.stringify(transactionPool_1.getTransactionPool()) -}); -const initErrorHandler = (ws) => { - const closeConnection = (myWs) => { - console.log('connection failed to peer: ' + myWs.url); - sockets.splice(sockets.indexOf(myWs), 1); - }; - ws.on('close', () => closeConnection(ws)); - ws.on('error', () => closeConnection(ws)); -}; -const handleBlockchainResponse = (receivedBlocks) => { - if (receivedBlocks.length === 0) { - console.log('received block chain size of 0'); - return; - } - const latestBlockReceived = receivedBlocks[receivedBlocks.length - 1]; - if (!blockchain_1.isValidBlockStructure(latestBlockReceived)) { - console.log('block structuture not valid'); - return; - } - const latestBlockHeld = blockchain_1.getLatestBlock(); - if (latestBlockReceived.index > latestBlockHeld.index) { - console.log('blockchain possibly behind. We got: ' - + latestBlockHeld.index + ' Peer got: ' + latestBlockReceived.index); - if (latestBlockHeld.hash === latestBlockReceived.previousHash) { - if (blockchain_1.addBlockToChain(latestBlockReceived)) { - broadcast(responseLatestMsg()); - } - } - else if (receivedBlocks.length === 1) { - console.log('We have to query the chain from our peer'); - broadcast(queryAllMsg()); - } - else { - console.log('Received blockchain is longer than current blockchain'); - blockchain_1.replaceChain(receivedBlocks); - } - } - else { - console.log('received blockchain is not longer than received blockchain. Do nothing'); - } -}; -const broadcastLatest = () => { - broadcast(responseLatestMsg()); -}; -exports.broadcastLatest = broadcastLatest; -const connectToPeers = (newPeer) => { - const ws = new WebSocket(newPeer); - ws.on('open', () => { - initConnection(ws); - }); - ws.on('error', () => { - console.log('connection failed'); - }); -}; -exports.connectToPeers = connectToPeers; -const broadCastTransactionPool = () => { - broadcast(responseTransactionPoolMsg()); -}; -exports.broadCastTransactionPool = broadCastTransactionPool; -//# sourceMappingURL=p2p.js.map \ No newline at end of file diff --git a/dew/src/p2p.js.map b/dew/src/p2p.js.map deleted file mode 100644 index c86c349..0000000 --- a/dew/src/p2p.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"p2p.js","sourceRoot":"","sources":["p2p.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dew/src/transaction.js b/dew/src/transaction.js deleted file mode 100644 index bb1a059..0000000 --- a/dew/src/transaction.js +++ /dev/null @@ -1,298 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const CryptoJS = require("crypto-js"); -const ecdsa = require("elliptic"); -const _ = require("lodash"); -const ec = new ecdsa.ec('secp256k1'); -const COINBASE_AMOUNT = 50; -class UnspentTxOut { - constructor(txOutId, txOutIndex, address, amount) { - this.txOutId = txOutId; - this.txOutIndex = txOutIndex; - this.address = address; - this.amount = amount; - } -} -exports.UnspentTxOut = UnspentTxOut; -class TxIn { -} -exports.TxIn = TxIn; -class TxOut { - constructor(address, amount) { - this.address = address; - this.amount = amount; - } -} -exports.TxOut = TxOut; -class Transaction { -} -exports.Transaction = Transaction; -const getTransactionId = (transaction) => { - const txInContent = transaction.txIns - .map((txIn) => txIn.txOutId + txIn.txOutIndex) - .reduce((a, b) => a + b, ''); - const txOutContent = transaction.txOuts - .map((txOut) => txOut.address + txOut.amount) - .reduce((a, b) => a + b, ''); - return CryptoJS.SHA256(txInContent + txOutContent).toString(); -}; -exports.getTransactionId = getTransactionId; -const validateTransaction = (transaction, aUnspentTxOuts) => { - if (!isValidTransactionStructure(transaction)) { - return false; - } - if (getTransactionId(transaction) !== transaction.id) { - console.log('invalid tx id: ' + transaction.id); - return false; - } - const hasValidTxIns = transaction.txIns - .map((txIn) => validateTxIn(txIn, transaction, aUnspentTxOuts)) - .reduce((a, b) => a && b, true); - if (!hasValidTxIns) { - console.log('some of the txIns are invalid in tx: ' + transaction.id); - return false; - } - const totalTxInValues = transaction.txIns - .map((txIn) => getTxInAmount(txIn, aUnspentTxOuts)) - .reduce((a, b) => (a + b), 0); - const totalTxOutValues = transaction.txOuts - .map((txOut) => txOut.amount) - .reduce((a, b) => (a + b), 0); - if (totalTxOutValues !== totalTxInValues) { - console.log('totalTxOutValues !== totalTxInValues in tx: ' + transaction.id); - return false; - } - return true; -}; -exports.validateTransaction = validateTransaction; -const validateBlockTransactions = (aTransactions, aUnspentTxOuts, blockIndex) => { - const coinbaseTx = aTransactions[0]; - if (!validateCoinbaseTx(coinbaseTx, blockIndex)) { - console.log('invalid coinbase transaction: ' + JSON.stringify(coinbaseTx)); - return false; - } - // check for duplicate txIns. Each txIn can be included only once - const txIns = _(aTransactions) - .map((tx) => tx.txIns) - .flatten() - .value(); - if (hasDuplicates(txIns)) { - return false; - } - // all but coinbase transactions - const normalTransactions = aTransactions.slice(1); - return normalTransactions.map((tx) => validateTransaction(tx, aUnspentTxOuts)) - .reduce((a, b) => (a && b), true); -}; -const hasDuplicates = (txIns) => { - const groups = _.countBy(txIns, (txIn) => txIn.txOutId + txIn.txOutIndex); - return _(groups) - .map((value, key) => { - if (value > 1) { - console.log('duplicate txIn: ' + key); - return true; - } - else { - return false; - } - }) - .includes(true); -}; -exports.hasDuplicates = hasDuplicates; -const validateCoinbaseTx = (transaction, blockIndex) => { - if (transaction == null) { - console.log('the first transaction in the block must be coinbase transaction'); - return false; - } - if (getTransactionId(transaction) !== transaction.id) { - console.log('invalid coinbase tx id: ' + transaction.id); - return false; - } - if (transaction.txIns.length !== 1) { - console.log('one txIn must be specified in the coinbase transaction'); - return; - } - if (transaction.txIns[0].txOutIndex !== blockIndex) { - console.log('the txIn signature in coinbase tx must be the block height'); - return false; - } - if (transaction.txOuts.length !== 1) { - console.log('invalid number of txOuts in coinbase transaction'); - return false; - } - if (transaction.txOuts[0].amount !== COINBASE_AMOUNT) { - console.log('invalid coinbase amount in coinbase transaction'); - return false; - } - return true; -}; -const validateTxIn = (txIn, transaction, aUnspentTxOuts) => { - const referencedUTxOut = aUnspentTxOuts.find((uTxO) => uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex); - if (referencedUTxOut == null) { - console.log('referenced txOut not found: ' + JSON.stringify(txIn)); - return false; - } - const address = referencedUTxOut.address; - const key = ec.keyFromPublic(address, 'hex'); - const validSignature = key.verify(transaction.id, txIn.signature); - if (!validSignature) { - console.log('invalid txIn signature: %s txId: %s address: %s', txIn.signature, transaction.id, referencedUTxOut.address); - return false; - } - return true; -}; -const getTxInAmount = (txIn, aUnspentTxOuts) => { - return findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts).amount; -}; -const findUnspentTxOut = (transactionId, index, aUnspentTxOuts) => { - return aUnspentTxOuts.find((uTxO) => uTxO.txOutId === transactionId && uTxO.txOutIndex === index); -}; -const getCoinbaseTransaction = (address, blockIndex) => { - const t = new Transaction(); - const txIn = new TxIn(); - txIn.signature = ''; - txIn.txOutId = ''; - txIn.txOutIndex = blockIndex; - t.txIns = [txIn]; - t.txOuts = [new TxOut(address, COINBASE_AMOUNT)]; - t.id = getTransactionId(t); - return t; -}; -exports.getCoinbaseTransaction = getCoinbaseTransaction; -const signTxIn = (transaction, txInIndex, privateKey, aUnspentTxOuts) => { - const txIn = transaction.txIns[txInIndex]; - const dataToSign = transaction.id; - const referencedUnspentTxOut = findUnspentTxOut(txIn.txOutId, txIn.txOutIndex, aUnspentTxOuts); - if (referencedUnspentTxOut == null) { - console.log('could not find referenced txOut'); - throw Error(); - } - const referencedAddress = referencedUnspentTxOut.address; - if (getPublicKey(privateKey) !== referencedAddress) { - console.log('trying to sign an input with private' + - ' key that does not match the address that is referenced in txIn'); - throw Error(); - } - const key = ec.keyFromPrivate(privateKey, 'hex'); - const signature = toHexString(key.sign(dataToSign).toDER()); - return signature; -}; -exports.signTxIn = signTxIn; -const updateUnspentTxOuts = (aTransactions, aUnspentTxOuts) => { - const newUnspentTxOuts = aTransactions - .map((t) => { - return t.txOuts.map((txOut, index) => new UnspentTxOut(t.id, index, txOut.address, txOut.amount)); - }) - .reduce((a, b) => a.concat(b), []); - const consumedTxOuts = aTransactions - .map((t) => t.txIns) - .reduce((a, b) => a.concat(b), []) - .map((txIn) => new UnspentTxOut(txIn.txOutId, txIn.txOutIndex, '', 0)); - const resultingUnspentTxOuts = aUnspentTxOuts - .filter(((uTxO) => !findUnspentTxOut(uTxO.txOutId, uTxO.txOutIndex, consumedTxOuts))) - .concat(newUnspentTxOuts); - return resultingUnspentTxOuts; -}; -const processTransactions = (aTransactions, aUnspentTxOuts, blockIndex) => { - if (!validateBlockTransactions(aTransactions, aUnspentTxOuts, blockIndex)) { - console.log('invalid block transactions'); - return null; - } - return updateUnspentTxOuts(aTransactions, aUnspentTxOuts); -}; -exports.processTransactions = processTransactions; -const toHexString = (byteArray) => { - return Array.from(byteArray, (byte) => { - return ('0' + (byte & 0xFF).toString(16)).slice(-2); - }).join(''); -}; -const getPublicKey = (aPrivateKey) => { - return ec.keyFromPrivate(aPrivateKey, 'hex').getPublic().encode('hex'); -}; -exports.getPublicKey = getPublicKey; -const isValidTxInStructure = (txIn) => { - if (txIn == null) { - console.log('txIn is null'); - return false; - } - else if (typeof txIn.signature !== 'string') { - console.log('invalid signature type in txIn'); - return false; - } - else if (typeof txIn.txOutId !== 'string') { - console.log('invalid txOutId type in txIn'); - return false; - } - else if (typeof txIn.txOutIndex !== 'number') { - console.log('invalid txOutIndex type in txIn'); - return false; - } - else { - return true; - } -}; -const isValidTxOutStructure = (txOut) => { - if (txOut == null) { - console.log('txOut is null'); - return false; - } - else if (typeof txOut.address !== 'string') { - console.log('invalid address type in txOut'); - return false; - } - else if (!isValidAddress(txOut.address)) { - console.log('invalid TxOut address'); - return false; - } - else if (typeof txOut.amount !== 'number') { - console.log('invalid amount type in txOut'); - return false; - } - else { - return true; - } -}; -const isValidTransactionStructure = (transaction) => { - if (typeof transaction.id !== 'string') { - console.log('transactionId missing'); - return false; - } - if (!(transaction.txIns instanceof Array)) { - console.log('invalid txIns type in transaction'); - return false; - } - if (!transaction.txIns - .map(isValidTxInStructure) - .reduce((a, b) => (a && b), true)) { - return false; - } - if (!(transaction.txOuts instanceof Array)) { - console.log('invalid txIns type in transaction'); - return false; - } - if (!transaction.txOuts - .map(isValidTxOutStructure) - .reduce((a, b) => (a && b), true)) { - return false; - } - return true; -}; -// valid address is a valid ecdsa public key in the 04 + X-coordinate + Y-coordinate format -const isValidAddress = (address) => { - if (address.length !== 130) { - console.log(address); - console.log('invalid public key length'); - return false; - } - else if (address.match('^[a-fA-F0-9]+$') === null) { - console.log('public key must contain only hex characters'); - return false; - } - else if (!address.startsWith('04')) { - console.log('public key must start with 04'); - return false; - } - return true; -}; -exports.isValidAddress = isValidAddress; -//# sourceMappingURL=transaction.js.map \ No newline at end of file diff --git a/dew/src/transaction.js.map b/dew/src/transaction.js.map deleted file mode 100644 index fd33576..0000000 --- a/dew/src/transaction.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"transaction.js","sourceRoot":"","sources":["transaction.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dew/src/transactionPool.js b/dew/src/transactionPool.js deleted file mode 100644 index c7a53d3..0000000 --- a/dew/src/transactionPool.js +++ /dev/null @@ -1,64 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const _ = require("lodash"); -const transaction_1 = require("./transaction"); -let transactionPool = []; -const getTransactionPool = () => { - return _.cloneDeep(transactionPool); -}; -exports.getTransactionPool = getTransactionPool; -const addToTransactionPool = (tx, unspentTxOuts) => { - if (!transaction_1.validateTransaction(tx, unspentTxOuts)) { - throw Error('Trying to add invalid tx to pool'); - } - if (!isValidTxForPool(tx, transactionPool)) { - throw Error('Trying to add invalid tx to pool'); - } - console.log('adding to txPool: %s', JSON.stringify(tx)); - transactionPool.push(tx); -}; -exports.addToTransactionPool = addToTransactionPool; -const hasTxIn = (txIn, unspentTxOuts) => { - const foundTxIn = unspentTxOuts.find((uTxO) => { - return uTxO.txOutId === txIn.txOutId && uTxO.txOutIndex === txIn.txOutIndex; - }); - return foundTxIn !== undefined; -}; -const updateTransactionPool = (unspentTxOuts) => { - const invalidTxs = []; - for (const tx of transactionPool) { - for (const txIn of tx.txIns) { - if (!hasTxIn(txIn, unspentTxOuts)) { - invalidTxs.push(tx); - break; - } - } - } - if (invalidTxs.length > 0) { - console.log('removing the following transactions from txPool: %s', JSON.stringify(invalidTxs)); - transactionPool = _.without(transactionPool, ...invalidTxs); - } -}; -exports.updateTransactionPool = updateTransactionPool; -const getTxPoolIns = (aTransactionPool) => { - return _(aTransactionPool) - .map((tx) => tx.txIns) - .flatten() - .value(); -}; -const isValidTxForPool = (tx, aTtransactionPool) => { - const txPoolIns = getTxPoolIns(aTtransactionPool); - const containsTxIn = (txIns, txIn) => { - return _.find(txPoolIns, ((txPoolIn) => { - return txIn.txOutIndex === txPoolIn.txOutIndex && txIn.txOutId === txPoolIn.txOutId; - })); - }; - for (const txIn of tx.txIns) { - if (containsTxIn(txPoolIns, txIn)) { - console.log('txIn already found in the txPool'); - return false; - } - } - return true; -}; -//# sourceMappingURL=transactionPool.js.map \ No newline at end of file diff --git a/dew/src/transactionPool.js.map b/dew/src/transactionPool.js.map deleted file mode 100644 index 50a6e7c..0000000 --- a/dew/src/transactionPool.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"transactionPool.js","sourceRoot":"","sources":["transactionPool.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dew/src/util.js b/dew/src/util.js deleted file mode 100644 index 57d0d2e..0000000 --- a/dew/src/util.js +++ /dev/null @@ -1,21 +0,0 @@ -"use strict"; -exports.__esModule = true; -var hexToBinary = function (s) { - var ret = ''; - var lookupTable = { - '0': '0000', '1': '0001', '2': '0010', '3': '0011', '4': '0100', - '5': '0101', '6': '0110', '7': '0111', '8': '1000', '9': '1001', - 'a': '1010', 'b': '1011', 'c': '1100', 'd': '1101', - 'e': '1110', 'f': '1111' - }; - for (var i = 0; i < s.length; i = i + 1) { - if (lookupTable[s[i]]) { - ret += lookupTable[s[i]]; - } - else { - return null; - } - } - return ret; -}; -exports.hexToBinary = hexToBinary; diff --git a/dew/src/util.js.map b/dew/src/util.js.map deleted file mode 100644 index c8d4f6c..0000000 --- a/dew/src/util.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"util.js","sourceRoot":"","sources":["util.ts"],"names":[],"mappings":";;AAAA,MAAM,WAAW,GAAG,CAAC,CAAS;IAC1B,IAAI,GAAG,GAAW,EAAE,CAAC;IACrB,MAAM,WAAW,GAAG;QAChB,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAC/D,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAC/D,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;QAClD,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;KAC3B,CAAC;IACF,GAAG,CAAC,CAAC,IAAI,CAAC,GAAW,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9C,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACpB,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QAAC,IAAI,CAAC,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC;QAChB,CAAC;IACL,CAAC;IACD,MAAM,CAAC,GAAG,CAAC;AACf,CAAC,CAAC;AAEM,kCAAW"} \ No newline at end of file diff --git a/dew/src/wallet.js b/dew/src/wallet.js deleted file mode 100644 index 67ae0c9..0000000 --- a/dew/src/wallet.js +++ /dev/null @@ -1,124 +0,0 @@ -"use strict"; -exports.__esModule = true; -var elliptic_1 = require("elliptic"); -var fs_1 = require("fs"); -var _ = require("lodash"); -var transaction_1 = require("./transaction"); -var EC = new elliptic_1.ec('secp256k1'); -var privateKeyLocation = process.env.PRIVATE_KEY || 'node/wallet/private_key'; -var getPrivateFromWallet = function () { - var buffer = fs_1.readFileSync(privateKeyLocation, 'utf8'); - return buffer.toString(); -}; -exports.getPrivateFromWallet = getPrivateFromWallet; -var getPublicFromWallet = function () { - var privateKey = getPrivateFromWallet(); - var key = EC.keyFromPrivate(privateKey, 'hex'); - return key.getPublic().encode('hex'); -}; -exports.getPublicFromWallet = getPublicFromWallet; -var generatePrivateKey = function () { - var keyPair = EC.genKeyPair(); - var privateKey = keyPair.getPrivate(); - return privateKey.toString(16); -}; -exports.generatePrivateKey = generatePrivateKey; -var initWallet = function () { - // let's not override existing private keys - if (fs_1.existsSync(privateKeyLocation)) { - return; - } - var newPrivateKey = generatePrivateKey(); - fs_1.writeFileSync(privateKeyLocation, newPrivateKey); - console.log('new wallet with private key created to : %s', privateKeyLocation); -}; -exports.initWallet = initWallet; -var deleteWallet = function () { - if (fs_1.existsSync(privateKeyLocation)) { - fs_1.unlinkSync(privateKeyLocation); - } -}; -exports.deleteWallet = deleteWallet; -var getBalance = function (address, unspentTxOuts) { - return _(findUnspentTxOuts(address, unspentTxOuts)) - .map(function (uTxO) { return uTxO.amount; }) - .sum(); -}; -exports.getBalance = getBalance; -var findUnspentTxOuts = function (ownerAddress, unspentTxOuts) { - return _.filter(unspentTxOuts, function (uTxO) { return uTxO.address === ownerAddress; }); -}; -exports.findUnspentTxOuts = findUnspentTxOuts; -var findTxOutsForAmount = function (amount, myUnspentTxOuts) { - var currentAmount = 0; - var includedUnspentTxOuts = []; - for (var _i = 0, myUnspentTxOuts_1 = myUnspentTxOuts; _i < myUnspentTxOuts_1.length; _i++) { - var myUnspentTxOut = myUnspentTxOuts_1[_i]; - includedUnspentTxOuts.push(myUnspentTxOut); - currentAmount = currentAmount + myUnspentTxOut.amount; - if (currentAmount >= amount) { - var leftOverAmount = currentAmount - amount; - return { includedUnspentTxOuts: includedUnspentTxOuts, leftOverAmount: leftOverAmount }; - } - } - var eMsg = 'Cannot create transaction from the available unspent transaction outputs.' + - ' Required amount:' + amount + '. Available unspentTxOuts:' + JSON.stringify(myUnspentTxOuts); - throw Error(eMsg); -}; -var createTxOuts = function (receiverAddress, myAddress, amount, leftOverAmount) { - var txOut1 = new transaction_1.TxOut(receiverAddress, amount); - if (leftOverAmount === 0) { - return [txOut1]; - } - else { - var leftOverTx = new transaction_1.TxOut(myAddress, leftOverAmount); - return [txOut1, leftOverTx]; - } -}; -var filterTxPoolTxs = function (unspentTxOuts, transactionPool) { - var txIns = _(transactionPool) - .map(function (tx) { return tx.txIns; }) - .flatten() - .value(); - var removable = []; - var _loop_1 = function (unspentTxOut) { - var txIn = _.find(txIns, function (aTxIn) { - return aTxIn.txOutIndex === unspentTxOut.txOutIndex && aTxIn.txOutId === unspentTxOut.txOutId; - }); - if (txIn === undefined) { - } - else { - removable.push(unspentTxOut); - } - }; - for (var _i = 0, unspentTxOuts_1 = unspentTxOuts; _i < unspentTxOuts_1.length; _i++) { - var unspentTxOut = unspentTxOuts_1[_i]; - _loop_1(unspentTxOut); - } - return _.without.apply(_, [unspentTxOuts].concat(removable)); -}; -var createTransaction = function (receiverAddress, amount, privateKey, unspentTxOuts, txPool) { - console.log('txPool: %s', JSON.stringify(txPool)); - var myAddress = transaction_1.getPublicKey(privateKey); - var myUnspentTxOutsA = unspentTxOuts.filter(function (uTxO) { return uTxO.address === myAddress; }); - var myUnspentTxOuts = filterTxPoolTxs(myUnspentTxOutsA, txPool); - // filter from unspentOutputs such inputs that are referenced in pool - var _a = findTxOutsForAmount(amount, myUnspentTxOuts), includedUnspentTxOuts = _a.includedUnspentTxOuts, leftOverAmount = _a.leftOverAmount; - var toUnsignedTxIn = function (unspentTxOut) { - var txIn = new transaction_1.TxIn(); - txIn.txOutId = unspentTxOut.txOutId; - txIn.txOutIndex = unspentTxOut.txOutIndex; - return txIn; - }; - var unsignedTxIns = includedUnspentTxOuts.map(toUnsignedTxIn); - var tx = new transaction_1.Transaction(); - tx.txIns = unsignedTxIns; - tx.txOuts = createTxOuts(receiverAddress, myAddress, amount, leftOverAmount); - tx.id = transaction_1.getTransactionId(tx); - tx.txIns = tx.txIns.map(function (txIn, index) { - txIn.signature = transaction_1.signTxIn(tx, index, privateKey, unspentTxOuts); - return txIn; - }); - return tx; -}; -exports.createTransaction = createTransaction; diff --git a/dew/src/wallet.js.map b/dew/src/wallet.js.map deleted file mode 100644 index 5895928..0000000 --- a/dew/src/wallet.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"wallet.js","sourceRoot":"","sources":["wallet.ts"],"names":[],"mappings":"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"} \ No newline at end of file From bde8f7e122847a86a37dbf9b4b4151b8a5bf71f1 Mon Sep 17 00:00:00 2001 From: ywang Date: Tue, 7 Aug 2018 14:36:35 -0400 Subject: [PATCH 20/36] ignore --- .gitignore | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index c39b80a..773ecb3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,10 @@ cloud/node_modules cloud/npm-debug.log -cloud/.idea cloud/src/*.js cloud/src/*.map dew/node_modules dew/npm-debug.log -dew/.idea dew/src/*.js dew/src/*.map -*.js -*.map -*.js -*.map + From 33815506cfff14a43908aa8fc1b992066ff42be8 Mon Sep 17 00:00:00 2001 From: ywang Date: Wed, 8 Aug 2018 18:58:24 -0400 Subject: [PATCH 21/36] connection between cloud and dew. config and web control --- dew/src/config.ts | 11 ++++ dew/src/main.ts | 27 +++++++- dew/src/p2p.ts | 161 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 dew/src/config.ts diff --git a/dew/src/config.ts b/dew/src/config.ts new file mode 100644 index 0000000..36fd2ff --- /dev/null +++ b/dew/src/config.ts @@ -0,0 +1,11 @@ +var mode: string = 'local'; +var cloudServer = 'localhost:7001'; + + + +const getMode = ():string => {return mode;}; +const setMode = (s: string) => {mode = s}; +const getCloud = (): string => {return cloudServer}; +const setCloud = (addressPort: string) => {cloudServer = addressPort}; + +export {setMode, getMode, getCloud, setCloud}; diff --git a/dew/src/main.ts b/dew/src/main.ts index b00f9ae..6f64dd4 100644 --- a/dew/src/main.ts +++ b/dew/src/main.ts @@ -13,14 +13,20 @@ import { getBlockchain, getMyAccount, getAccounts, sendTransaction } from './blockchain'; -import {connectToPeers, getSockets, initP2PServer} from './p2p'; +//import {connectToPeers, getSockets, initP2PServer} from './p2p'; +import {connectToPeers, getSockets, initP2PServer, setModeLocal, setModeDew} from './p2p'; //import {UnspentTxOut} from './transaction'; import {Account, findAccount} from './transaction'; +//dewcoin +import {getMode} from './config'; + import {getTransactionPool} from './transactionPool'; import {getPublicFromWallet, initWallet} from './wallet'; +var mode:string = 'dew'; + const httpPort: number = parseInt(process.env.HTTP_PORT) || 3001; const p2pPort: number = parseInt(process.env.P2P_PORT) || 6001; @@ -34,8 +40,25 @@ const initHttpServer = (myHttpPort: number) => { } }); + app.get('/setmodelocal', (req, res) => { + setModeLocal(); + mode = getMode(); + res.send('The system is in ' + mode + ' mode.'); + }); + + app.get('/setmodedew', (req, res) => { + setModeDew(); + mode = getMode(); + res.send('The system is in ' + mode + ' mode.'); + }); + app.get('/blocks', (req, res) => { - res.send(getBlockchain()); + mode = getMode(); + if(mode == 'local'){ + res.send(getBlockchain()); + }else if(mode == 'dew'){ + res.send('This request is not available in dew mode.'); + } }); app.get('/block/:hash', (req, res) => { diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts index 4ed3a68..cc513cf 100644 --- a/dew/src/p2p.ts +++ b/dew/src/p2p.ts @@ -7,6 +7,10 @@ import { import {Transaction} from './transaction'; import {getTransactionPool} from './transactionPool'; +//dewcoin +import {getMode, setMode, getCloud} from './config'; +var mode:string; + const sockets: WebSocket[] = []; enum MessageType { @@ -22,12 +26,28 @@ class Message { public data: any; } +/* +const initP2PServer = (p2pPort: number) => { + const server: Server = new WebSocket.Server({port: p2pPort}); + server.on('connection', (ws: WebSocket) => { + initConnection(ws); + }); + console.log('listening websocket p2p port on: ' + p2pPort); +}; +*/ const initP2PServer = (p2pPort: number) => { const server: Server = new WebSocket.Server({port: p2pPort}); server.on('connection', (ws: WebSocket) => { initConnection(ws); }); console.log('listening websocket p2p port on: ' + p2pPort); + mode = getMode(); + if(mode == 'dew'){ + setModeDew(); + }else if(mode == 'local'){ + setModeLocal() + }; + console.log('running on ' + mode + ' mode.'); }; const getSockets = () => sockets; @@ -53,9 +73,66 @@ const JSONToObject = (data: string): T => { } }; + const initMessageHandler = (ws: WebSocket) => { ws.on('message', (data: string) => { + + try { + const message: Message = JSONToObject(data); + if (message === null) { + console.log('could not parse received JSON message: ' + data); + return; + } + console.log('[Received message: %s', JSON.stringify(message)); + switch (message.type) { + case MessageType.QUERY_LATEST: + write(ws, responseLatestMsg()); + break; + case MessageType.QUERY_ALL: + write(ws, responseChainMsg()); + break; + case MessageType.RESPONSE_BLOCKCHAIN: + const receivedBlocks: Block[] = JSONToObject(message.data); + if (receivedBlocks === null) { + console.log('invalid blocks received: %s', JSON.stringify(message.data)); + break; + } + handleBlockchainResponse(receivedBlocks); + break; + case MessageType.QUERY_TRANSACTION_POOL: + write(ws, responseTransactionPoolMsg()); + break; + case MessageType.RESPONSE_TRANSACTION_POOL: + const receivedTransactions: Transaction[] = JSONToObject(message.data); + if (receivedTransactions === null) { + console.log('invalid transaction received: %s', JSON.stringify(message.data)); + break; + } + receivedTransactions.forEach((transaction: Transaction) => { + try { + handleReceivedTransaction(transaction); + // if no error is thrown, transaction was indeed added to the pool + // let's broadcast transaction pool + broadCastTransactionPool(); + } catch (e) { + console.log(e.message); + } + }); + break; + } + } catch (e) { + console.log(e); + } + console.log('message processing]'); + }); +}; + + + +const initCloudMessageHandler = (ws: WebSocket) => { + ws.on('message', (data: string) => { + mode = getMode(); try { const message: Message = JSONToObject(data); if (message === null) { @@ -63,6 +140,44 @@ const initMessageHandler = (ws: WebSocket) => { return; } console.log('[Received message: %s', JSON.stringify(message)); + if(mode == 'local'){ + switch (message.type) { + case MessageType.QUERY_LATEST: + write(ws, responseLatestMsg()); + break; + case MessageType.QUERY_ALL: + write(ws, responseChainMsg()); + break; + case MessageType.RESPONSE_BLOCKCHAIN: + const receivedBlocks: Block[] = JSONToObject(message.data); + if (receivedBlocks === null) { + console.log('invalid blocks received: %s', JSON.stringify(message.data)); + break; + } + handleBlockchainResponse(receivedBlocks); + break; + case MessageType.QUERY_TRANSACTION_POOL: + write(ws, responseTransactionPoolMsg()); + break; + case MessageType.RESPONSE_TRANSACTION_POOL: + const receivedTransactions: Transaction[] = JSONToObject(message.data); + if (receivedTransactions === null) { + console.log('invalid transaction received: %s', JSON.stringify(message.data)); + break; + } + receivedTransactions.forEach((transaction: Transaction) => { + try { + handleReceivedTransaction(transaction); + // if no error is thrown, transaction was indeed added to the pool + // let's broadcast transaction pool + broadCastTransactionPool(); + } catch (e) { + console.log(e.message); + } + }); + break; + } + }else if (mode == 'dew'){ switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -99,6 +214,7 @@ const initMessageHandler = (ws: WebSocket) => { }); break; } + } } catch (e) { console.log(e); } @@ -106,6 +222,7 @@ const initMessageHandler = (ws: WebSocket) => { }); }; + const write = (ws: WebSocket, message: Message): void => ws.send(JSON.stringify(message)); const broadcast = (message: Message): void => sockets.forEach((socket) => write(socket, message)); @@ -141,6 +258,7 @@ const initErrorHandler = (ws: WebSocket) => { ws.on('error', () => closeConnection(ws)); }; + const handleBlockchainResponse = (receivedBlocks: Block[]) => { if (receivedBlocks.length === 0) { console.log('received block chain size of 0'); @@ -189,4 +307,45 @@ const broadCastTransactionPool = () => { broadcast(responseTransactionPoolMsg()); }; -export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets}; +var wsCloud: WebSocket; + + +const setModeLocal = () => { + setMode('local'); + mode = getMode(); + console.log('running on ' + mode + ' mode.'); + + if (typeof wsCloud !== "undefined") { + wsCloud.close(); + }; +}; + +const setModeDew = () => { + setMode('dew'); + mode = getMode(); + console.log('running on ' + mode + ' mode.'); + + wsCloud = new WebSocket('ws://' + getCloud()); + wsCloud.on('open', () => { + console.log('connection with the cloud established'); + //sockets.push(wsCloud); + initCloudMessageHandler(wsCloud); + + //write(wsCloud, queryChainLengthMsg()); + // query transactions pool only some time after chain query + //setTimeout(() => { + //broadcast(queryTransactionPoolMsg()); + //}, 500); + }); + wsCloud.on('error', () => { + console.log('connection with the cloud failed'); + }); + wsCloud.on('close', () => { + console.log('connection with the cloud was closed'); + }); + +}; + + +//export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets}; +export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets, setModeLocal, setModeDew}; From fce73c45041c056eeddb0bf6af41c10ba9b1e1cb Mon Sep 17 00:00:00 2001 From: ywang Date: Thu, 9 Aug 2018 15:26:29 -0400 Subject: [PATCH 22/36] cloud-dew channel established From now on, the cloud and dew have different code. --- cloud/src/p2p.ts | 118 +++++++++++++++++++++++++++++++++++++++++++++- dew/README.md | 8 +++- dew/src/config.ts | 2 +- dew/src/p2p.ts | 79 ++++++++++++++++++++++++++----- 4 files changed, 189 insertions(+), 18 deletions(-) diff --git a/cloud/src/p2p.ts b/cloud/src/p2p.ts index 4ed3a68..690ee54 100644 --- a/cloud/src/p2p.ts +++ b/cloud/src/p2p.ts @@ -8,13 +8,23 @@ import {Transaction} from './transaction'; import {getTransactionPool} from './transactionPool'; const sockets: WebSocket[] = []; +const getSockets = () => sockets; + +//dewcoin +var wsCloud: WebSocket; +var dewAddress: string = '127.0.0.1'; +const setDewAddress = (address: string) => { + dewAddress = address; +} + enum MessageType { QUERY_LATEST = 0, QUERY_ALL = 1, RESPONSE_BLOCKCHAIN = 2, QUERY_TRANSACTION_POOL = 3, - RESPONSE_TRANSACTION_POOL = 4 + RESPONSE_TRANSACTION_POOL = 4, + DEW_CONNECTION =5 } class Message { @@ -22,6 +32,9 @@ class Message { public data: any; } + + +/* const initP2PServer = (p2pPort: number) => { const server: Server = new WebSocket.Server({port: p2pPort}); server.on('connection', (ws: WebSocket) => { @@ -29,9 +42,34 @@ const initP2PServer = (p2pPort: number) => { }); console.log('listening websocket p2p port on: ' + p2pPort); }; +*/ +const initP2PServer = (p2pPort: number) => { + const server: Server = new WebSocket.Server({port: p2pPort}); + server.on('connection', (ws: WebSocket, req) => { + console.log('New websocket connection from %s:%d', req.connection.remoteAddress.substring(7), req.connection.remotePort); + if(req.connection.remoteAddress.substring(7) == dewAddress){ + initCloudConnection(ws); + }else{ + initConnection(ws); + } + }); + console.log('listening websocket p2p port on: ' + p2pPort); +}; -const getSockets = () => sockets; +/* +const initConnection = (ws: WebSocket) => { + sockets.push(ws); + initMessageHandler(ws); + initErrorHandler(ws); + write(ws, queryChainLengthMsg()); + + // query transactions pool only some time after chain query + setTimeout(() => { + broadcast(queryTransactionPoolMsg()); + }, 500); +}; +*/ const initConnection = (ws: WebSocket) => { sockets.push(ws); initMessageHandler(ws); @@ -44,6 +82,27 @@ const initConnection = (ws: WebSocket) => { }, 500); }; + +const initCloudConnection = (ws: WebSocket) => { + console.log('Dew sent in connection.'); + wsCloud = ws; + initCloudMessageHandler(wsCloud); + wsCloud.on('error', () => { + console.log('connection with the dew failed'); + }); + wsCloud.on('close', () => { + console.log('connection with the dew was closed'); + }); + + write(wsCloud, queryChainLengthMsg()); + // query transactions pool only some time after chain query + //setTimeout(() => { + // broadcast(queryTransactionPoolMsg()); + //}, 500); +}; + + + const JSONToObject = (data: string): T => { try { return JSON.parse(data); @@ -106,6 +165,61 @@ const initMessageHandler = (ws: WebSocket) => { }); }; + +const initCloudMessageHandler = (ws: WebSocket) => { + ws.on('message', (data: string) => { + + try { + const message: Message = JSONToObject(data); + if (message === null) { + console.log('could not parse received JSON message: ' + data); + return; + } + console.log('[Received cloud message: %s', JSON.stringify(message)); + switch (message.type) { + case MessageType.QUERY_LATEST: + write(ws, responseLatestMsg()); + break; + case MessageType.QUERY_ALL: + write(ws, responseChainMsg()); + break; + case MessageType.RESPONSE_BLOCKCHAIN: + const receivedBlocks: Block[] = JSONToObject(message.data); + if (receivedBlocks === null) { + console.log('invalid blocks received: %s', JSON.stringify(message.data)); + break; + } + handleBlockchainResponse(receivedBlocks); + break; + case MessageType.QUERY_TRANSACTION_POOL: + write(ws, responseTransactionPoolMsg()); + break; + case MessageType.RESPONSE_TRANSACTION_POOL: + const receivedTransactions: Transaction[] = JSONToObject(message.data); + if (receivedTransactions === null) { + console.log('invalid transaction received: %s', JSON.stringify(message.data)); + break; + } + receivedTransactions.forEach((transaction: Transaction) => { + try { + handleReceivedTransaction(transaction); + // if no error is thrown, transaction was indeed added to the pool + // let's broadcast transaction pool + broadCastTransactionPool(); + } catch (e) { + console.log(e.message); + } + }); + break; + } + } catch (e) { + console.log(e); + } + console.log('Cloud message processing]'); + }); +}; + + const write = (ws: WebSocket, message: Message): void => ws.send(JSON.stringify(message)); const broadcast = (message: Message): void => sockets.forEach((socket) => write(socket, message)); diff --git a/dew/README.md b/dew/README.md index 6b9c875..7b62936 100644 --- a/dew/README.md +++ b/dew/README.md @@ -13,7 +13,7 @@ npm start ##### Query the whole blockchain curl http://localhost:3001/blocks - +pass to cloud ##### Query all accounts @@ -54,12 +54,14 @@ curl http://localhost:3001/myaddress curl http://localhost:3001/block/:hash +pass to cloud + ##### Query a transaction with transaction id curl http://localhost:3001/transaction/:id - +pass to cloud ##### Query an account with account address @@ -73,6 +75,7 @@ The block will contain the transactions in the pool. ``` curl -X POST http://localhost:3001/mineBlock ``` +pass to cloud ##### Send a transaction to the pool @@ -86,6 +89,7 @@ curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7 ##### Mine a block with a transaction If the transaction is invalid, the block will still be mined. +pass to cloud ``` curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction ``` diff --git a/dew/src/config.ts b/dew/src/config.ts index 36fd2ff..3d4d5f8 100644 --- a/dew/src/config.ts +++ b/dew/src/config.ts @@ -1,4 +1,4 @@ -var mode: string = 'local'; +var mode: string = 'dew'; var cloudServer = 'localhost:7001'; diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts index cc513cf..ca2e215 100644 --- a/dew/src/p2p.ts +++ b/dew/src/p2p.ts @@ -10,6 +10,7 @@ import {getTransactionPool} from './transactionPool'; //dewcoin import {getMode, setMode, getCloud} from './config'; var mode:string; +var wsCloud: WebSocket; const sockets: WebSocket[] = []; @@ -74,16 +75,17 @@ const JSONToObject = (data: string): T => { }; +/* const initMessageHandler = (ws: WebSocket) => { ws.on('message', (data: string) => { - + try { const message: Message = JSONToObject(data); if (message === null) { console.log('could not parse received JSON message: ' + data); return; } - console.log('[Received message: %s', JSON.stringify(message)); + console.log('Received message: %s', JSON.stringify(message)); switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -123,14 +125,10 @@ const initMessageHandler = (ws: WebSocket) => { } catch (e) { console.log(e); } - console.log('message processing]'); }); }; - - - - -const initCloudMessageHandler = (ws: WebSocket) => { +*/ +const initMessageHandler = (ws: WebSocket) => { ws.on('message', (data: string) => { mode = getMode(); try { @@ -140,7 +138,7 @@ const initCloudMessageHandler = (ws: WebSocket) => { return; } console.log('[Received message: %s', JSON.stringify(message)); - if(mode == 'local'){ + if(mode == 'local'){ switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -178,6 +176,64 @@ const initCloudMessageHandler = (ws: WebSocket) => { break; } }else if (mode == 'dew'){ + switch (message.type) { + case MessageType.QUERY_LATEST: + //write(ws, responseLatestMsg()); + break; + case MessageType.QUERY_ALL: + //write(ws, responseChainMsg()); + break; + case MessageType.RESPONSE_BLOCKCHAIN: + /* + const receivedBlocks: Block[] = JSONToObject(message.data); + if (receivedBlocks === null) { + console.log('invalid blocks received: %s', JSON.stringify(message.data)); + break; + } + handleBlockchainResponse(receivedBlocks); + */ + break; + case MessageType.QUERY_TRANSACTION_POOL: + write(ws, responseTransactionPoolMsg()); + break; + case MessageType.RESPONSE_TRANSACTION_POOL: + const receivedTransactions: Transaction[] = JSONToObject(message.data); + if (receivedTransactions === null) { + console.log('invalid transaction received: %s', JSON.stringify(message.data)); + break; + } + receivedTransactions.forEach((transaction: Transaction) => { + try { + handleReceivedTransaction(transaction); + // if no error is thrown, transaction was indeed added to the pool + // let's broadcast transaction pool + broadCastTransactionPool(); + } catch (e) { + console.log(e.message); + } + }); + break; + } + } + } catch (e) { + console.log(e); + } + console.log('message processing]'); + }); +}; + + + +const initCloudMessageHandler = (ws: WebSocket) => { + ws.on('message', (data: string) => { + + try { + const message: Message = JSONToObject(data); + if (message === null) { + console.log('could not parse received JSON message: ' + data); + return; + } + console.log('[Received cloud message: %s', JSON.stringify(message)); switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -214,11 +270,10 @@ const initCloudMessageHandler = (ws: WebSocket) => { }); break; } - } } catch (e) { console.log(e); } - console.log('message processing]'); + console.log('Cloud message processing]'); }); }; @@ -307,8 +362,6 @@ const broadCastTransactionPool = () => { broadcast(responseTransactionPoolMsg()); }; -var wsCloud: WebSocket; - const setModeLocal = () => { setMode('local'); From ae95a7c5541c0e935ddc116d55a68ca2be730235 Mon Sep 17 00:00:00 2001 From: ywang Date: Thu, 9 Aug 2018 17:23:33 -0400 Subject: [PATCH 23/36] Dew address web control dew-dew channels, cloud-cloud channels, cloud-dew channel, are all separated. The next step is message design. --- cloud/README.md | 102 +++++++++++++++++++++++++++++++++++++--------- cloud/src/main.ts | 9 +++- cloud/src/p2p.ts | 62 ++++++++++++++++++++++++++-- dew/src/p2p.ts | 3 +- 4 files changed, 150 insertions(+), 26 deletions(-) diff --git a/cloud/README.md b/cloud/README.md index 839b976..724e0a7 100644 --- a/cloud/README.md +++ b/cloud/README.md @@ -10,46 +10,108 @@ npm install npm start ``` -##### Get blockchain -``` +##### Set Dew Address +Example for Windows: +curl -H "Content-type:application/json" --data "{\"address\": \"192.168.1.186\"}" http://localhost:4001/SetDewAddress + + +##### Query the whole blockchain curl http://localhost:3001/blocks -``` +pass to cloud + + +##### Query all accounts + +curl http://localhost:3001/accounts -##### Mine a block -``` -curl -X POST http://localhost:3001/mineBlock -``` -##### Send transaction +##### Query the transaction pool ``` -curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction +curl http://localhost:3001/transactionPool ``` -##### Query transaction pool + +#### Query all connected peers ``` -curl http://localhost:3001/transactionPool +curl http://localhost:3001/peers ``` -##### Mine transaction + +##### Query my account + +curl http://localhost:3001/myaccount + + +##### Query my account balance ``` -curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction +curl http://localhost:3001/mybalance +``` + + +##### Query my account address + +curl http://localhost:3001/myaddress + + + +##### Query a block with block hash + +curl http://localhost:3001/block/:hash + +pass to cloud + + + +##### Query a transaction with transaction id + +curl http://localhost:3001/transaction/:id +pass to cloud + + +##### Query an account with account address + +curl http://localhost:3001/account/:address + + + +##### Mine a block +The block will contain the transactions in the pool. ``` +curl -X POST http://localhost:3001/mineBlock +``` +pass to cloud -##### Get balance + +##### Send a transaction to the pool ``` -curl http://localhost:3001/balance +curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction ``` +For Windows: +curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7cf8216982cf85f1b8edd51de012f1222bd2b37bb1217a42d31f8feda18be34aa09a759d2a70c5d6d0cc6cdd67e4e8c1761beb27e680bddd89b6\", \"amount\" : 25}" http://localhost:3001/sendTransaction -#### Query information about a specific address + + +##### Mine a block with a transaction +If the transaction is invalid, the block will still be mined. +pass to cloud ``` -curl http://localhost:3001/address/04f72a4541275aeb4344a8b049bfe2734b49fe25c08d56918f033507b96a61f9e3c330c4fcd46d0854a712dc878b9c280abe90c788c47497e06df78b25bf60ae64 +curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction ``` +For Windows: +curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7cf8216982cf85f1b8edd51de012f1222bd2b37bb1217a42d31f8feda18be34aa09a759d2a70c5d6d0cc6cdd67e4e8c1761beb27e680bddd89b6\", \"amount\" : 20}" http://localhost:3001/mineTransaction + ##### Add peer ``` -curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addPeer +curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addpeer ``` -#### Query connected peers +For Windows: +curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:7001\"}" http://localhost:3001/addpeer ``` -curl http://localhost:3001/peers + + +#### Stop the server +``` +curl -X POST http://localhost:3001/stop ``` + diff --git a/cloud/src/main.ts b/cloud/src/main.ts index 3be1e4d..6882f63 100644 --- a/cloud/src/main.ts +++ b/cloud/src/main.ts @@ -13,7 +13,8 @@ import { getBlockchain, getMyAccount, getAccounts, sendTransaction } from './blockchain'; -import {connectToPeers, getSockets, initP2PServer} from './p2p'; +//import {connectToPeers, getSockets, initP2PServer} from './p2p'; +import {connectToPeers, getSockets, initP2PServer, getDewAddress, setDewAddress} from './p2p'; //import {UnspentTxOut} from './transaction'; import {Account, findAccount} from './transaction'; @@ -34,6 +35,12 @@ const initHttpServer = (myHttpPort: number) => { } }); + app.post('/SetDewAddress', (req, res) => { + setDewAddress(req.body.address); + console.log('Dew address: ' + getDewAddress()); + res.send(); + }); + app.get('/blocks', (req, res) => { res.send(getBlockchain()); }); diff --git a/cloud/src/p2p.ts b/cloud/src/p2p.ts index 690ee54..61725de 100644 --- a/cloud/src/p2p.ts +++ b/cloud/src/p2p.ts @@ -13,6 +13,9 @@ const getSockets = () => sockets; //dewcoin var wsCloud: WebSocket; var dewAddress: string = '127.0.0.1'; +const getDewAddress = () => { + return dewAddress; +} const setDewAddress = (address: string) => { dewAddress = address; } @@ -23,8 +26,7 @@ enum MessageType { QUERY_ALL = 1, RESPONSE_BLOCKCHAIN = 2, QUERY_TRANSACTION_POOL = 3, - RESPONSE_TRANSACTION_POOL = 4, - DEW_CONNECTION =5 + RESPONSE_TRANSACTION_POOL = 4 } class Message { @@ -33,7 +35,6 @@ class Message { } - /* const initP2PServer = (p2pPort: number) => { const server: Server = new WebSocket.Server({port: p2pPort}); @@ -112,6 +113,59 @@ const JSONToObject = (data: string): T => { } }; +/* +const initMessageHandler = (ws: WebSocket) => { + ws.on('message', (data: string) => { + + try { + const message: Message = JSONToObject(data); + if (message === null) { + console.log('could not parse received JSON message: ' + data); + return; + } + console.log('Received message: %s', JSON.stringify(message)); + switch (message.type) { + case MessageType.QUERY_LATEST: + write(ws, responseLatestMsg()); + break; + case MessageType.QUERY_ALL: + write(ws, responseChainMsg()); + break; + case MessageType.RESPONSE_BLOCKCHAIN: + const receivedBlocks: Block[] = JSONToObject(message.data); + if (receivedBlocks === null) { + console.log('invalid blocks received: %s', JSON.stringify(message.data)); + break; + } + handleBlockchainResponse(receivedBlocks); + break; + case MessageType.QUERY_TRANSACTION_POOL: + write(ws, responseTransactionPoolMsg()); + break; + case MessageType.RESPONSE_TRANSACTION_POOL: + const receivedTransactions: Transaction[] = JSONToObject(message.data); + if (receivedTransactions === null) { + console.log('invalid transaction received: %s', JSON.stringify(message.data)); + break; + } + receivedTransactions.forEach((transaction: Transaction) => { + try { + handleReceivedTransaction(transaction); + // if no error is thrown, transaction was indeed added to the pool + // let's broadcast transaction pool + broadCastTransactionPool(); + } catch (e) { + console.log(e.message); + } + }); + break; + } + } catch (e) { + console.log(e); + } + }); +}; +*/ const initMessageHandler = (ws: WebSocket) => { ws.on('message', (data: string) => { @@ -303,4 +357,4 @@ const broadCastTransactionPool = () => { broadcast(responseTransactionPoolMsg()); }; -export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets}; +export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets, getDewAddress, setDewAddress}; diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts index ca2e215..746061a 100644 --- a/dew/src/p2p.ts +++ b/dew/src/p2p.ts @@ -384,7 +384,8 @@ const setModeDew = () => { //sockets.push(wsCloud); initCloudMessageHandler(wsCloud); - //write(wsCloud, queryChainLengthMsg()); + //write(wsCloud, {'type': 5, 'data': null}); + write(wsCloud, queryChainLengthMsg()); // query transactions pool only some time after chain query //setTimeout(() => { //broadcast(queryTransactionPoolMsg()); From c3ee207f8cacbe96f98c8509b1bc96d6a0af95eb Mon Sep 17 00:00:00 2001 From: ywang Date: Fri, 10 Aug 2018 23:19:18 -0400 Subject: [PATCH 24/36] dew mode and local mode both work dew mode does not have to keep the whole chain. It works. local mode works as if the dew mode has not been introduced. modes can be switched. Conveniently controlled through web and config file. --- cloud/src/blockchain.ts | 2 +- cloud/src/main.ts | 6 +- cloud/src/p2p.ts | 4 +- cloud/src/transaction.ts | 28 ++++---- cloud/src/transactionPool.ts | 10 +-- cloud/src/wallet.ts | 2 +- dew/src/blockchain.ts | 129 ++++++++++++++++++++++++++++++----- dew/src/config.ts | 4 +- dew/src/main.ts | 16 ++--- dew/src/p2p.ts | 63 ++++------------- dew/src/transaction.ts | 28 ++++---- dew/src/transactionPool.ts | 10 +-- dew/src/wallet.ts | 2 +- 13 files changed, 182 insertions(+), 122 deletions(-) diff --git a/cloud/src/blockchain.ts b/cloud/src/blockchain.ts index bd1e016..a8fe57a 100644 --- a/cloud/src/blockchain.ts +++ b/cloud/src/blockchain.ts @@ -175,7 +175,7 @@ const generatenextBlockWithTransaction = (receiverAddress: string, amount: numbe }; */ const generatenextBlockWithTransaction = (receiverAddress: string, amount: number) => { - var blockData: Transaction[]; + let blockData: Transaction[]; if (!isValidAddress(receiverAddress)) { throw Error('invalid address'); diff --git a/cloud/src/main.ts b/cloud/src/main.ts index 6882f63..9d886a8 100644 --- a/cloud/src/main.ts +++ b/cloud/src/main.ts @@ -66,7 +66,7 @@ const initHttpServer = (myHttpPort: number) => { }); */ app.get('/account/:address', (req, res) => { - var acc: Account = findAccount(req.params.address, getAccounts()); + let acc: Account = findAccount(req.params.address, getAccounts()); if(acc == undefined){ res.send({'Error:': "address is wrong"}); } @@ -89,7 +89,7 @@ const initHttpServer = (myHttpPort: number) => { }); */ app.get('/myaccount', (req, res) => { - var acc: Account = findAccount(getPublicFromWallet(), getAccounts()); + let acc: Account = findAccount(getPublicFromWallet(), getAccounts()); if(acc == undefined){ res.send({'Error': 'No account was found.'}) }else{ @@ -120,7 +120,7 @@ const initHttpServer = (myHttpPort: number) => { }); app.get('/mybalance', (req, res) => { - var acc: Account = findAccount(getPublicFromWallet(), getAccounts()); + let acc: Account = findAccount(getPublicFromWallet(), getAccounts()); if(acc == undefined){ res.send({'Error:': "No such account."}); }else{ diff --git a/cloud/src/p2p.ts b/cloud/src/p2p.ts index 61725de..2dbf41b 100644 --- a/cloud/src/p2p.ts +++ b/cloud/src/p2p.ts @@ -11,8 +11,8 @@ const sockets: WebSocket[] = []; const getSockets = () => sockets; //dewcoin -var wsCloud: WebSocket; -var dewAddress: string = '127.0.0.1'; +let wsCloud: WebSocket; +let dewAddress: string = '127.0.0.1'; const getDewAddress = () => { return dewAddress; } diff --git a/cloud/src/transaction.ts b/cloud/src/transaction.ts index 6d73843..2ef608a 100644 --- a/cloud/src/transaction.ts +++ b/cloud/src/transaction.ts @@ -157,12 +157,12 @@ const existAccount = (address: string, accounts: Account[]): boolean => { return _(accounts).map((acc: Account) => acc.address).includes(address); } const createAccount = (address: string, accounts: Account[]): boolean => { - var acc: Account = new Account(address); + let acc: Account = new Account(address); accounts.push(acc); return true; } const findAccount = (address: string, accounts: Account[]): Account => { - var account: Account = _.find(accounts, (acc: Account) => {return acc.address == address}); + let account: Account = _.find(accounts, (acc: Account) => {return acc.address == address}); return account; } const validateTransaction = (transaction: Transaction, accounts: Account[]): boolean => { @@ -186,7 +186,7 @@ const validateTransaction = (transaction: Transaction, accounts: Account[]): boo console.log('The transaction is too old. tx: ' + transaction.id); return false; } - var accSender: Account = findAccount(transaction.sender, accounts); + let accSender: Account = findAccount(transaction.sender, accounts); if(accSender == undefined){ console.log('validateTransaction: no account found.'); return false; @@ -228,7 +228,7 @@ const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: }; */ const validateBlockTransactions = (aTransactions: Transaction[], accounts: Account[]): boolean => { - var accSender: Account; + let accSender: Account; const coinbaseTx = aTransactions[0]; if (!validateCoinbaseTx(coinbaseTx)) { @@ -244,10 +244,10 @@ const validateBlockTransactions = (aTransactions: Transaction[], accounts: Accou return false; } - for(var i=0; i < accounts.length; i++){ + for(let i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } - for(var j=1; j < aTransactions.length; j++){ + for(let j=1; j < aTransactions.length; j++){ accSender = findAccount(aTransactions[j].sender, accounts); if(accSender == undefined){ console.log('validateBlockTransactions: no account found.'); @@ -470,14 +470,14 @@ const updateUnspentTxOuts = (aTransactions: Transaction[], aUnspentTxOuts: Unspe }; */ const updateAccounts = (aTransactions: Transaction[], accounts: Account[]): Account[] => { - var amt: number; - var thSender: TxHistory; - var thReceiver: TxHistory; - var accSender: Account; - var accReceiver: Account; - var now: number; - - for(var i=0; i { }; */ const updateTransactionPoolReplace = (accounts: Account[]) => { - var accSender; + let accSender; transactionPool = _(transactionPool).uniqBy('id').filter(tx => validateTransaction(tx, accounts)).value(); - for(var i=0; i < accounts.length; i++){ + for(let i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } const invalidTxs = []; @@ -93,7 +93,7 @@ const updateTransactionPool = (transactions: Transaction[]) => { //console.log('tansactionPool: '+JSON.stringify(transactionPool)); if (transactions.length > 0) { //console.log('removing the following transactions from txPool: %s', JSON.stringify(transactions)); - var txIDs: string[] = _.map(transactions, (tx: Transaction) => tx.id); + let txIDs: string[] = _.map(transactions, (tx: Transaction) => tx.id); transactionPool = _.filter(transactionPool, (tx: Transaction) => !_.includes(txIDs, tx.id)); } //console.log('tansactionPool: '+JSON.stringify(transactionPool)); @@ -129,11 +129,11 @@ const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): bo */ // This transaction tx has been validated in another function. id duplicate was checked in validation. const isValidTxForPool = (tx: Transaction, aTransactionPool: Transaction[], accounts: Account[]): boolean => { - var accSender: Account; + let accSender: Account; //console.log('isValidForPool: a Pool: ' + JSON.stringify(aTransactionPool)); //console.log('tx: ' + JSON.stringify(tx)); - for(var i=0; i < accounts.length; i++){ + for(let i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } for (const trx of aTransactionPool) { diff --git a/cloud/src/wallet.ts b/cloud/src/wallet.ts index bb72fc6..e166bfb 100644 --- a/cloud/src/wallet.ts +++ b/cloud/src/wallet.ts @@ -56,7 +56,7 @@ const getBalance = (address: string, unspentTxOuts: UnspentTxOut[]): number => { }; */ const getBalance = (address: string, accounts: Account[]): number => { - var acct: Account = findAccount(address, accounts); + let acct: Account = findAccount(address, accounts); if(acct == undefined){ console.log('getBalance: no account found.'); return 0; diff --git a/dew/src/blockchain.ts b/dew/src/blockchain.ts index bd1e016..485adfd 100644 --- a/dew/src/blockchain.ts +++ b/dew/src/blockchain.ts @@ -16,6 +16,11 @@ import {hexToBinary} from './util'; //import {createTransaction, findUnspentTxOuts, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; import {createTransaction, getBalance, getPrivateFromWallet, getPublicFromWallet} from './wallet'; +//dewcoin +import {getMode, setMode} from './config'; +let mode:string; + + class Block { public index: number; @@ -66,18 +71,21 @@ const genesisBlock: Block = new Block( ); let blockchain: Block[] = [genesisBlock]; +const getBlockchain = (): Block[] => blockchain; +//dewcoin +const resetBlockchain = () => {blockchain = [genesisBlock];}; // the unspent txOut of genesis block is set to unspentTxOuts on startup //let unspentTxOuts: UnspentTxOut[] = processTransactions(blockchain[0].data, []); let accounts: Account[] = processTransactions(blockchain[0].data, []); - -const getBlockchain = (): Block[] => blockchain; - //const getUnspentTxOuts = (): UnspentTxOut[] => _.cloneDeep(unspentTxOuts); //const getAccounts = (): Account[] => _.cloneDeep(accounts); const getAccounts = (): Account[] => accounts; - +//dewcoin +let theLatestBlock: Block = genesisBlock; +let previousAdjustBlock: Block = genesisBlock; +let accuDiff = 1; // and txPool should be only updated at the same time /* @@ -91,7 +99,16 @@ const setAccounts = (newAccount: Account[]) => { accounts = newAccount; }; -const getLatestBlock = (): Block => blockchain[blockchain.length - 1]; + +//const getLatestBlock = (): Block => blockchain[blockchain.length - 1]; +const getLatestBlock = (): Block => { + mode = getMode(); + if(mode == 'local'){ + return blockchain[blockchain.length - 1]; + }else if(mode == 'dew'){ + return theLatestBlock; + } +} // in seconds const BLOCK_GENERATION_INTERVAL: number = 10; @@ -99,6 +116,8 @@ const BLOCK_GENERATION_INTERVAL: number = 10; // in blocks const DIFFICULTY_ADJUSTMENT_INTERVAL: number = 10; + + const getDifficulty = (aBlockchain: Block[]): number => { const latestBlock: Block = aBlockchain[blockchain.length - 1]; if (latestBlock.index % DIFFICULTY_ADJUSTMENT_INTERVAL === 0 && latestBlock.index !== 0) { @@ -108,6 +127,14 @@ const getDifficulty = (aBlockchain: Block[]): number => { } }; +const getDifficultyChain1 = (): number => { + if (theLatestBlock.index % DIFFICULTY_ADJUSTMENT_INTERVAL === 0 && theLatestBlock.index !== 0) { + return getAdjustedDifficultyChain1(theLatestBlock); + } else { + return theLatestBlock.difficulty; + } +}; + const getAdjustedDifficulty = (latestBlock: Block, aBlockchain: Block[]) => { const prevAdjustmentBlock: Block = aBlockchain[blockchain.length - DIFFICULTY_ADJUSTMENT_INTERVAL]; const timeExpected: number = BLOCK_GENERATION_INTERVAL * DIFFICULTY_ADJUSTMENT_INTERVAL; @@ -120,8 +147,21 @@ const getAdjustedDifficulty = (latestBlock: Block, aBlockchain: Block[]) => { return prevAdjustmentBlock.difficulty; } }; +const getAdjustedDifficultyChain1 = (latestBlock: Block) => { + const prevAdjustmentBlock: Block = previousAdjustBlock; + const timeExpected: number = BLOCK_GENERATION_INTERVAL * DIFFICULTY_ADJUSTMENT_INTERVAL; + const timeTaken: number = latestBlock.timestamp - prevAdjustmentBlock.timestamp; + if (timeTaken < timeExpected / 2) { + return prevAdjustmentBlock.difficulty + 1; + } else if (timeTaken > timeExpected * 2) { + return prevAdjustmentBlock.difficulty - 1; + } else { + return prevAdjustmentBlock.difficulty; + } +}; + -//// +/* const generateRawNextBlock = (blockData: Transaction[]) => { const previousBlock: Block = getLatestBlock(); const difficulty: number = getDifficulty(getBlockchain()); @@ -135,6 +175,30 @@ const generateRawNextBlock = (blockData: Transaction[]) => { return null; } +}; +*/ +const generateRawNextBlock = (blockData: Transaction[]) => { + const previousBlock: Block = getLatestBlock(); + //console.log('previousBlock: '+ JSON.stringify(previousBlock)); + //console.log('getLatestBlock: '+ JSON.stringify(getLatestBlock())); + //console.log('theLatestBlock: '+ JSON.stringify(theLatestBlock)); + let difficulty: number; + mode = getMode(); + if(mode == 'local'){ + difficulty = getDifficulty(getBlockchain()); + }else if(mode == 'dew'){ + difficulty = getDifficultyChain1(); + } + const nextIndex: number = previousBlock.index + 1; + const nextTimestamp: number = getCurrentTimestamp(); + const newBlock: Block = findBlock(nextIndex, previousBlock.hash, nextTimestamp, blockData, difficulty); + if (addBlockToChain(newBlock)) { + broadcastLatest(); + return newBlock; + } else { + return null; + } + }; // gets the unspent transaction outputs owned by the wallet @@ -175,7 +239,7 @@ const generatenextBlockWithTransaction = (receiverAddress: string, amount: numbe }; */ const generatenextBlockWithTransaction = (receiverAddress: string, amount: number) => { - var blockData: Transaction[]; + let blockData: Transaction[]; if (!isValidAddress(receiverAddress)) { throw Error('invalid address'); @@ -269,6 +333,7 @@ const isValidNewBlock = (newBlock: Block, previousBlock: Block): boolean => { return true; }; + const getAccumulatedDifficulty = (aBlockchain: Block[]): number => { return aBlockchain .map((block) => block.difficulty) @@ -276,6 +341,10 @@ const getAccumulatedDifficulty = (aBlockchain: Block[]): number => { .reduce((a, b) => a + b); }; +const getAccumulatedDifficultyChain1 = (): number => { + return accuDiff; +}; + const isValidTimestamp = (newBlock: Block, previousBlock: Block): boolean => { return ( previousBlock.timestamp - 60 < newBlock.timestamp ) && newBlock.timestamp - 60 < getCurrentTimestamp(); @@ -340,6 +409,7 @@ const isValidChain = (blockchainToValidate: Block[]): UnspentTxOut[] => { return aUnspentTxOuts; }; */ +//only used for chain2 const isValidChain = (blockchainToValidate: Block[]): Account[] => { console.log('isValidChain:'); console.log(JSON.stringify(blockchainToValidate)); @@ -354,7 +424,7 @@ const isValidChain = (blockchainToValidate: Block[]): Account[] => { Validate each block in the chain. The block is valid if the block structure is valid and the transaction are valid */ - let accts: Account[] = []; + let accountsTemp: Account[] = []; for (let i = 0; i < blockchainToValidate.length; i++) { const currentBlock: Block = blockchainToValidate[i]; @@ -362,15 +432,16 @@ const isValidChain = (blockchainToValidate: Block[]): Account[] => { return null; } - accts = processTransactions(currentBlock.data, accts); - if (accts === null) { + accountsTemp = processTransactions(currentBlock.data, accountsTemp); + if (accountsTemp === null) { console.log('invalid transactions in blockchain'); return null; } } - return accts; + return accountsTemp; }; + /* const addBlockToChain = (newBlock: Block): boolean => { if (isValidNewBlock(newBlock, getLatestBlock())) { @@ -389,22 +460,31 @@ const addBlockToChain = (newBlock: Block): boolean => { }; */ const addBlockToChain = (newBlock: Block): boolean => { + mode = getMode(); if (isValidNewBlock(newBlock, getLatestBlock())) { const retVal: Account[] = processTransactions(newBlock.data, getAccounts()); if (retVal === null) { console.log('block is not valid in terms of transactions'); return false; } else { - blockchain.push(newBlock); + if(mode == 'local'){ + blockchain.push(newBlock); + } setAccounts(retVal); - //updateTransactionPool(accounts); updateTransactionPool(newBlock.data); + //The following is done even it is in local mode, preparing for mode change. + theLatestBlock = newBlock; + if (newBlock.index % DIFFICULTY_ADJUSTMENT_INTERVAL === 0) { + previousAdjustBlock = newBlock; + } + accuDiff += Math.pow(2, newBlock.difficulty); return true; } } return false; }; + /* const replaceChain = (newBlocks: Block[]) => { const aUnspentTxOuts = isValidChain(newBlocks); @@ -422,20 +502,33 @@ const replaceChain = (newBlocks: Block[]) => { }; */ const replaceChain = (newBlocks: Block[]) => { - const accts = isValidChain(newBlocks); - const validChain: boolean = accts !== null; + const accountsTemp = isValidChain(newBlocks); + const validChain: boolean = accountsTemp !== null; + mode = getMode(); + let currentDifficulty: number; + if(mode == 'local'){ + currentDifficulty = getAccumulatedDifficulty(getBlockchain()); + } else if(mode == 'dew'){ + currentDifficulty = getAccumulatedDifficultyChain1(); + } if (validChain && - getAccumulatedDifficulty(newBlocks) > getAccumulatedDifficulty(getBlockchain())) { + getAccumulatedDifficulty(newBlocks) > currentDifficulty) { console.log('Received blockchain is valid. Replacing current blockchain with received blockchain'); - blockchain = newBlocks; - setAccounts(accts); + if(mode == 'local'){ + blockchain = newBlocks; + } + setAccounts(accountsTemp); updateTransactionPoolReplace(accounts); + theLatestBlock = newBlocks[newBlocks.length - 1]; + previousAdjustBlock = newBlocks[theLatestBlock.index - theLatestBlock.index % DIFFICULTY_ADJUSTMENT_INTERVAL]; + accuDiff = getAccumulatedDifficulty(newBlocks); broadcastLatest(); } else { console.log('Received blockchain invalid'); } }; + /* const handleReceivedTransaction = (transaction: Transaction) => { addToTransactionPool(transaction, getUnspentTxOuts()); diff --git a/dew/src/config.ts b/dew/src/config.ts index 3d4d5f8..4bb3bde 100644 --- a/dew/src/config.ts +++ b/dew/src/config.ts @@ -1,5 +1,5 @@ -var mode: string = 'dew'; -var cloudServer = 'localhost:7001'; +let mode: string = 'dew'; +let cloudServer = 'localhost:7001'; diff --git a/dew/src/main.ts b/dew/src/main.ts index 6f64dd4..2bc6fee 100644 --- a/dew/src/main.ts +++ b/dew/src/main.ts @@ -25,7 +25,7 @@ import {getMode} from './config'; import {getTransactionPool} from './transactionPool'; import {getPublicFromWallet, initWallet} from './wallet'; -var mode:string = 'dew'; +let mode:string = 'dew'; const httpPort: number = parseInt(process.env.HTTP_PORT) || 3001; const p2pPort: number = parseInt(process.env.P2P_PORT) || 6001; @@ -54,11 +54,11 @@ const initHttpServer = (myHttpPort: number) => { app.get('/blocks', (req, res) => { mode = getMode(); - if(mode == 'local'){ + //if(mode == 'local'){ res.send(getBlockchain()); - }else if(mode == 'dew'){ - res.send('This request is not available in dew mode.'); - } + //}else if(mode == 'dew'){ + // res.send('This request is not available in dew mode.'); + //} }); app.get('/block/:hash', (req, res) => { @@ -82,7 +82,7 @@ const initHttpServer = (myHttpPort: number) => { }); */ app.get('/account/:address', (req, res) => { - var acc: Account = findAccount(req.params.address, getAccounts()); + let acc: Account = findAccount(req.params.address, getAccounts()); if(acc == undefined){ res.send({'Error:': "address is wrong"}); } @@ -105,7 +105,7 @@ const initHttpServer = (myHttpPort: number) => { }); */ app.get('/myaccount', (req, res) => { - var acc: Account = findAccount(getPublicFromWallet(), getAccounts()); + let acc: Account = findAccount(getPublicFromWallet(), getAccounts()); if(acc == undefined){ res.send({'Error': 'No account was found.'}) }else{ @@ -136,7 +136,7 @@ const initHttpServer = (myHttpPort: number) => { }); app.get('/mybalance', (req, res) => { - var acc: Account = findAccount(getPublicFromWallet(), getAccounts()); + let acc: Account = findAccount(getPublicFromWallet(), getAccounts()); if(acc == undefined){ res.send({'Error:': "No such account."}); }else{ diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts index 746061a..f3b3e4d 100644 --- a/dew/src/p2p.ts +++ b/dew/src/p2p.ts @@ -9,8 +9,8 @@ import {getTransactionPool} from './transactionPool'; //dewcoin import {getMode, setMode, getCloud} from './config'; -var mode:string; -var wsCloud: WebSocket; +let mode: string; +let wsCloud: WebSocket; const sockets: WebSocket[] = []; @@ -138,60 +138,22 @@ const initMessageHandler = (ws: WebSocket) => { return; } console.log('[Received message: %s', JSON.stringify(message)); - if(mode == 'local'){ switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); break; case MessageType.QUERY_ALL: - write(ws, responseChainMsg()); - break; - case MessageType.RESPONSE_BLOCKCHAIN: - const receivedBlocks: Block[] = JSONToObject(message.data); - if (receivedBlocks === null) { - console.log('invalid blocks received: %s', JSON.stringify(message.data)); - break; + if(mode == 'local'){ + write(ws, responseChainMsg()); } - handleBlockchainResponse(receivedBlocks); - break; - case MessageType.QUERY_TRANSACTION_POOL: - write(ws, responseTransactionPoolMsg()); - break; - case MessageType.RESPONSE_TRANSACTION_POOL: - const receivedTransactions: Transaction[] = JSONToObject(message.data); - if (receivedTransactions === null) { - console.log('invalid transaction received: %s', JSON.stringify(message.data)); - break; - } - receivedTransactions.forEach((transaction: Transaction) => { - try { - handleReceivedTransaction(transaction); - // if no error is thrown, transaction was indeed added to the pool - // let's broadcast transaction pool - broadCastTransactionPool(); - } catch (e) { - console.log(e.message); - } - }); - break; - } - }else if (mode == 'dew'){ - switch (message.type) { - case MessageType.QUERY_LATEST: - //write(ws, responseLatestMsg()); - break; - case MessageType.QUERY_ALL: - //write(ws, responseChainMsg()); break; case MessageType.RESPONSE_BLOCKCHAIN: - /* const receivedBlocks: Block[] = JSONToObject(message.data); if (receivedBlocks === null) { console.log('invalid blocks received: %s', JSON.stringify(message.data)); break; } handleBlockchainResponse(receivedBlocks); - */ break; case MessageType.QUERY_TRANSACTION_POOL: write(ws, responseTransactionPoolMsg()); @@ -214,7 +176,6 @@ const initMessageHandler = (ws: WebSocket) => { }); break; } - } } catch (e) { console.log(e); } @@ -223,7 +184,7 @@ const initMessageHandler = (ws: WebSocket) => { }; - +//for cloud-dew channel const initCloudMessageHandler = (ws: WebSocket) => { ws.on('message', (data: string) => { @@ -371,6 +332,11 @@ const setModeLocal = () => { if (typeof wsCloud !== "undefined") { wsCloud.close(); }; + broadcast(queryChainLengthMsg()); + //query transactions pool only some time after chain query + setTimeout(() => { + broadcast(queryTransactionPoolMsg()); + }, 500); }; const setModeDew = () => { @@ -385,11 +351,12 @@ const setModeDew = () => { initCloudMessageHandler(wsCloud); //write(wsCloud, {'type': 5, 'data': null}); + broadcast(queryChainLengthMsg()); write(wsCloud, queryChainLengthMsg()); - // query transactions pool only some time after chain query - //setTimeout(() => { - //broadcast(queryTransactionPoolMsg()); - //}, 500); + //query transactions pool only some time after chain query + setTimeout(() => { + broadcast(queryTransactionPoolMsg()); + }, 500); }); wsCloud.on('error', () => { console.log('connection with the cloud failed'); diff --git a/dew/src/transaction.ts b/dew/src/transaction.ts index 6d73843..2ef608a 100644 --- a/dew/src/transaction.ts +++ b/dew/src/transaction.ts @@ -157,12 +157,12 @@ const existAccount = (address: string, accounts: Account[]): boolean => { return _(accounts).map((acc: Account) => acc.address).includes(address); } const createAccount = (address: string, accounts: Account[]): boolean => { - var acc: Account = new Account(address); + let acc: Account = new Account(address); accounts.push(acc); return true; } const findAccount = (address: string, accounts: Account[]): Account => { - var account: Account = _.find(accounts, (acc: Account) => {return acc.address == address}); + let account: Account = _.find(accounts, (acc: Account) => {return acc.address == address}); return account; } const validateTransaction = (transaction: Transaction, accounts: Account[]): boolean => { @@ -186,7 +186,7 @@ const validateTransaction = (transaction: Transaction, accounts: Account[]): boo console.log('The transaction is too old. tx: ' + transaction.id); return false; } - var accSender: Account = findAccount(transaction.sender, accounts); + let accSender: Account = findAccount(transaction.sender, accounts); if(accSender == undefined){ console.log('validateTransaction: no account found.'); return false; @@ -228,7 +228,7 @@ const validateBlockTransactions = (aTransactions: Transaction[], aUnspentTxOuts: }; */ const validateBlockTransactions = (aTransactions: Transaction[], accounts: Account[]): boolean => { - var accSender: Account; + let accSender: Account; const coinbaseTx = aTransactions[0]; if (!validateCoinbaseTx(coinbaseTx)) { @@ -244,10 +244,10 @@ const validateBlockTransactions = (aTransactions: Transaction[], accounts: Accou return false; } - for(var i=0; i < accounts.length; i++){ + for(let i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } - for(var j=1; j < aTransactions.length; j++){ + for(let j=1; j < aTransactions.length; j++){ accSender = findAccount(aTransactions[j].sender, accounts); if(accSender == undefined){ console.log('validateBlockTransactions: no account found.'); @@ -470,14 +470,14 @@ const updateUnspentTxOuts = (aTransactions: Transaction[], aUnspentTxOuts: Unspe }; */ const updateAccounts = (aTransactions: Transaction[], accounts: Account[]): Account[] => { - var amt: number; - var thSender: TxHistory; - var thReceiver: TxHistory; - var accSender: Account; - var accReceiver: Account; - var now: number; - - for(var i=0; i { }; */ const updateTransactionPoolReplace = (accounts: Account[]) => { - var accSender; + let accSender; transactionPool = _(transactionPool).uniqBy('id').filter(tx => validateTransaction(tx, accounts)).value(); - for(var i=0; i < accounts.length; i++){ + for(let i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } const invalidTxs = []; @@ -93,7 +93,7 @@ const updateTransactionPool = (transactions: Transaction[]) => { //console.log('tansactionPool: '+JSON.stringify(transactionPool)); if (transactions.length > 0) { //console.log('removing the following transactions from txPool: %s', JSON.stringify(transactions)); - var txIDs: string[] = _.map(transactions, (tx: Transaction) => tx.id); + let txIDs: string[] = _.map(transactions, (tx: Transaction) => tx.id); transactionPool = _.filter(transactionPool, (tx: Transaction) => !_.includes(txIDs, tx.id)); } //console.log('tansactionPool: '+JSON.stringify(transactionPool)); @@ -129,11 +129,11 @@ const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): bo */ // This transaction tx has been validated in another function. id duplicate was checked in validation. const isValidTxForPool = (tx: Transaction, aTransactionPool: Transaction[], accounts: Account[]): boolean => { - var accSender: Account; + let accSender: Account; //console.log('isValidForPool: a Pool: ' + JSON.stringify(aTransactionPool)); //console.log('tx: ' + JSON.stringify(tx)); - for(var i=0; i < accounts.length; i++){ + for(let i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } for (const trx of aTransactionPool) { diff --git a/dew/src/wallet.ts b/dew/src/wallet.ts index bb72fc6..e166bfb 100644 --- a/dew/src/wallet.ts +++ b/dew/src/wallet.ts @@ -56,7 +56,7 @@ const getBalance = (address: string, unspentTxOuts: UnspentTxOut[]): number => { }; */ const getBalance = (address: string, accounts: Account[]): number => { - var acct: Account = findAccount(address, accounts); + let acct: Account = findAccount(address, accounts); if(acct == undefined){ console.log('getBalance: no account found.'); return 0; From 8ea4acaf1a0b8eaba0dd8091a732e8b59be476b2 Mon Sep 17 00:00:00 2001 From: ywang Date: Sat, 11 Aug 2018 07:57:42 -0400 Subject: [PATCH 25/36] cloud and dew coordinated --- cloud/src/p2p.ts | 15 +++++++++++---- dew/src/blockchain.ts | 2 +- dew/src/p2p.ts | 27 +++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 9 deletions(-) diff --git a/cloud/src/p2p.ts b/cloud/src/p2p.ts index 2dbf41b..a598f73 100644 --- a/cloud/src/p2p.ts +++ b/cloud/src/p2p.ts @@ -97,9 +97,10 @@ const initCloudConnection = (ws: WebSocket) => { write(wsCloud, queryChainLengthMsg()); // query transactions pool only some time after chain query - //setTimeout(() => { - // broadcast(queryTransactionPoolMsg()); - //}, 500); + setTimeout(() => { + write(wsCloud, queryTransactionPoolMsg()); + //broadcast(queryTransactionPoolMsg()); + }, 500); }; @@ -275,7 +276,13 @@ const initCloudMessageHandler = (ws: WebSocket) => { const write = (ws: WebSocket, message: Message): void => ws.send(JSON.stringify(message)); -const broadcast = (message: Message): void => sockets.forEach((socket) => write(socket, message)); +//const broadcast = (message: Message): void => sockets.forEach((socket) => write(socket, message)); +const broadcast = (message: Message): void => { + sockets.forEach((socket) => write(socket, message)); + if(wsCloud.readyState == 1){ + write(wsCloud, message); + } +} const queryChainLengthMsg = (): Message => ({'type': MessageType.QUERY_LATEST, 'data': null}); diff --git a/dew/src/blockchain.ts b/dew/src/blockchain.ts index 485adfd..95eeaaf 100644 --- a/dew/src/blockchain.ts +++ b/dew/src/blockchain.ts @@ -548,7 +548,7 @@ export { }; */ export { - Block, getBlockchain, getAccounts, getLatestBlock, sendTransaction, + Block, getBlockchain, resetBlockchain, getAccounts, getLatestBlock, sendTransaction, generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, handleReceivedTransaction, getMyAccount, getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain, getCurrentTimestamp diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts index f3b3e4d..1224cb5 100644 --- a/dew/src/p2p.ts +++ b/dew/src/p2p.ts @@ -1,9 +1,15 @@ import * as WebSocket from 'ws'; import {Server} from 'ws'; +/* import { addBlockToChain, Block, getBlockchain, getLatestBlock, handleReceivedTransaction, isValidBlockStructure, replaceChain } from './blockchain'; +*/ +import { + addBlockToChain, Block, getBlockchain, resetBlockchain, getLatestBlock, handleReceivedTransaction, isValidBlockStructure, + replaceChain +} from './blockchain'; import {Transaction} from './transaction'; import {getTransactionPool} from './transactionPool'; @@ -11,6 +17,7 @@ import {getTransactionPool} from './transactionPool'; import {getMode, setMode, getCloud} from './config'; let mode: string; let wsCloud: WebSocket; +const getWsCloud = (): WebSocket => wsCloud; const sockets: WebSocket[] = []; @@ -39,6 +46,7 @@ const initP2PServer = (p2pPort: number) => { const initP2PServer = (p2pPort: number) => { const server: Server = new WebSocket.Server({port: p2pPort}); server.on('connection', (ws: WebSocket) => { + //incoming connections. initConnection(ws); }); console.log('listening websocket p2p port on: ' + p2pPort); @@ -53,6 +61,7 @@ const initP2PServer = (p2pPort: number) => { const getSockets = () => sockets; + const initConnection = (ws: WebSocket) => { sockets.push(ws); initMessageHandler(ws); @@ -240,7 +249,14 @@ const initCloudMessageHandler = (ws: WebSocket) => { const write = (ws: WebSocket, message: Message): void => ws.send(JSON.stringify(message)); -const broadcast = (message: Message): void => sockets.forEach((socket) => write(socket, message)); +//const broadcast = (message: Message): void => sockets.forEach((socket) => write(socket, message)); +const broadcast = (message: Message): void => { + sockets.forEach((socket) => write(socket, message)); + mode = getMode(); + if(mode == 'dew'){ + write(wsCloud, message); + } +} const queryChainLengthMsg = (): Message => ({'type': MessageType.QUERY_LATEST, 'data': null}); @@ -349,13 +365,15 @@ const setModeDew = () => { console.log('connection with the cloud established'); //sockets.push(wsCloud); initCloudMessageHandler(wsCloud); + resetBlockchain(); //write(wsCloud, {'type': 5, 'data': null}); - broadcast(queryChainLengthMsg()); + //broadcast(queryChainLengthMsg()); write(wsCloud, queryChainLengthMsg()); //query transactions pool only some time after chain query setTimeout(() => { - broadcast(queryTransactionPoolMsg()); + write(wsCloud, queryTransactionPoolMsg()); + //broadcast(queryTransactionPoolMsg()); }, 500); }); wsCloud.on('error', () => { @@ -369,4 +387,5 @@ const setModeDew = () => { //export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets}; -export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets, setModeLocal, setModeDew}; +export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets, +setModeLocal, setModeDew}; From 17712f98efd33e96e80f2f68546d28890463b204 Mon Sep 17 00:00:00 2001 From: ywang Date: Sat, 11 Aug 2018 15:44:21 -0400 Subject: [PATCH 26/36] cloud-dew channel accounts messaging added Dew sends accounts for cloud to verify. If they are not consistent, the cloud will send acounts to dew to replace. --- cloud/src/blockchain.ts | 19 +++++++++++++-- cloud/src/p2p.ts | 49 +++++++++++++++++++++++++++++++++++--- cloud/src/transaction.ts | 17 +++++++++++++- dew/src/blockchain.ts | 26 ++++++++++++++++---- dew/src/main.ts | 8 ++++++- dew/src/p2p.ts | 51 ++++++++++++++++++++++++++++++++++++---- dew/src/transaction.ts | 7 ++++-- 7 files changed, 158 insertions(+), 19 deletions(-) diff --git a/cloud/src/blockchain.ts b/cloud/src/blockchain.ts index a8fe57a..2a97d0d 100644 --- a/cloud/src/blockchain.ts +++ b/cloud/src/blockchain.ts @@ -446,6 +446,21 @@ const handleReceivedTransaction = (transaction: Transaction) => { addToTransactionPool(transaction, getAccounts()); }; +const validateAccount = (account: Account) => { +/* + if (!validateTransaction(tx, accounts)) { + throw Error('Trying to add invalid tx to pool. Tx: ' + tx.id); + } + + if (!isValidTxForPool(tx, transactionPool, accounts)) { + throw Error('Tx is not valid for the pool, Tx: ' + tx.id); + } + //console.log('adding to txPool: %s', JSON.stringify(tx)); + transactionPool.push(tx); +*/ +}; + + /* export { Block, getBlockchain, getUnspentTxOuts, getLatestBlock, sendTransaction, @@ -455,9 +470,9 @@ export { }; */ export { - Block, getBlockchain, getAccounts, getLatestBlock, sendTransaction, + Block, getBlockchain, getAccounts, setAccounts, getLatestBlock, sendTransaction, generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, - handleReceivedTransaction, getMyAccount, + handleReceivedTransaction, validateAccount, getMyAccount, getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain, getCurrentTimestamp }; diff --git a/cloud/src/p2p.ts b/cloud/src/p2p.ts index a598f73..851c7d8 100644 --- a/cloud/src/p2p.ts +++ b/cloud/src/p2p.ts @@ -1,10 +1,17 @@ import * as WebSocket from 'ws'; import {Server} from 'ws'; +/* import { - addBlockToChain, Block, getBlockchain, getLatestBlock, handleReceivedTransaction, isValidBlockStructure, + addBlockToChain, Block, getBlockchain, getLatestBlock, handleReceivedTransaction, validateAccount, isValidBlockStructure, replaceChain } from './blockchain'; -import {Transaction} from './transaction'; +*/ +import { + addBlockToChain, Block, getBlockchain, getLatestBlock, handleReceivedTransaction, validateAccount, isValidBlockStructure, + replaceChain, setAccounts, getAccounts +} from './blockchain'; +//import {Transaction} from './transaction'; +import {Transaction, Account, verifyAccounts} from './transaction'; import {getTransactionPool} from './transactionPool'; const sockets: WebSocket[] = []; @@ -26,7 +33,9 @@ enum MessageType { QUERY_ALL = 1, RESPONSE_BLOCKCHAIN = 2, QUERY_TRANSACTION_POOL = 3, - RESPONSE_TRANSACTION_POOL = 4 + RESPONSE_TRANSACTION_POOL = 4, + QUERY_ACCOUNTS = 5, + RESPONSE_ACCOUNTS = 6 } class Message { @@ -266,6 +275,35 @@ const initCloudMessageHandler = (ws: WebSocket) => { } }); break; + case MessageType.QUERY_ACCOUNTS: + const dewAccounts: Account[] = JSONToObject(message.data); + if (dewAccounts === null) { + console.log('invalid dew accounts received: %s', JSON.stringify(message.data)); + break; + } + const consistent: boolean = verifyAccounts(dewAccounts, getAccounts()); + if (!consistent){ + write(ws, responseAccountsMsg()); + } + break; + case MessageType.RESPONSE_ACCOUNTS: + const receivedAccounts: Account[] = JSONToObject(message.data); + if (receivedAccounts === null) { + console.log('invalid account received: %s', JSON.stringify(message.data)); + break; + } + receivedAccounts.forEach((account: Account) => { + try { + validateAccount(account); + // if no error is thrown, account was indeed added to the account pool + // let's broadcast account pool + // broadCastTransactionPool(); + } catch (e) { + console.log(e.message); + } + }); + setAccounts(receivedAccounts); + break; } } catch (e) { console.log(e); @@ -307,6 +345,11 @@ const responseTransactionPoolMsg = (): Message => ({ 'data': JSON.stringify(getTransactionPool()) }); +const responseAccountsMsg = (): Message => ({ + 'type': MessageType.RESPONSE_ACCOUNTS, + 'data': JSON.stringify(getAccounts()) +}); + const initErrorHandler = (ws: WebSocket) => { const closeConnection = (myWs: WebSocket) => { console.log('connection failed to peer: ' + myWs.url); diff --git a/cloud/src/transaction.ts b/cloud/src/transaction.ts index 2ef608a..64b7e9e 100644 --- a/cloud/src/transaction.ts +++ b/cloud/src/transaction.ts @@ -96,6 +96,21 @@ class TxHistory { } } + +const verifyAccounts = (accounts1: Account[], accounts2: Account[]): boolean => { + console.log('accounts1: ' + JSON.stringify(accounts1)); + console.log('accounts2: ' + JSON.stringify(accounts2)); + const a1: Account[] = _.sortBy(accounts1, 'id'); + const a2: Account[] = _.sortBy(accounts2, 'id'); + const s1: string = JSON.stringify(a1); + const s2: string = JSON.stringify(a2); + console.log('s1:' + s1); + console.log('s2:' + s2); + return s1 === s2; +} + + + /* const getTransactionId = (transaction: Transaction): string => { const txInContent: string = transaction.txIns @@ -675,7 +690,7 @@ export { */ export { processTransactions, signTransaction, getTransactionId, isValidAddress, validateTransaction, - Account, findAccount, existAccount, createAccount, getCoinbaseTransaction, getPublicKey, hasDuplicates, + Account, findAccount, existAccount, createAccount, verifyAccounts, getCoinbaseTransaction, getPublicKey, hasDuplicates, Transaction }; // diff --git a/dew/src/blockchain.ts b/dew/src/blockchain.ts index 95eeaaf..72d1a75 100644 --- a/dew/src/blockchain.ts +++ b/dew/src/blockchain.ts @@ -94,9 +94,9 @@ const setUnspentTxOuts = (newUnspentTxOut: UnspentTxOut[]) => { unspentTxOuts = newUnspentTxOut; }; */ -const setAccounts = (newAccount: Account[]) => { - //console.log('replacing accounts with: %s', newAccount); - accounts = newAccount; +const setAccounts = (newAccounts: Account[]) => { + //console.log('replacing accounts with: %s', newAccounts); + accounts = newAccounts; }; @@ -539,6 +539,22 @@ const handleReceivedTransaction = (transaction: Transaction) => { addToTransactionPool(transaction, getAccounts()); }; + +const validateAccount = (account: Account) => { +/* + if (!validateTransaction(tx, accounts)) { + throw Error('Trying to add invalid tx to pool. Tx: ' + tx.id); + } + + if (!isValidTxForPool(tx, transactionPool, accounts)) { + throw Error('Tx is not valid for the pool, Tx: ' + tx.id); + } + //console.log('adding to txPool: %s', JSON.stringify(tx)); + transactionPool.push(tx); +*/ +}; + + /* export { Block, getBlockchain, getUnspentTxOuts, getLatestBlock, sendTransaction, @@ -548,9 +564,9 @@ export { }; */ export { - Block, getBlockchain, resetBlockchain, getAccounts, getLatestBlock, sendTransaction, + Block, getBlockchain, resetBlockchain, getAccounts, setAccounts, getLatestBlock, sendTransaction, generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, - handleReceivedTransaction, getMyAccount, + handleReceivedTransaction, validateAccount, getMyAccount, getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain, getCurrentTimestamp }; diff --git a/dew/src/main.ts b/dew/src/main.ts index 2bc6fee..4cc0821 100644 --- a/dew/src/main.ts +++ b/dew/src/main.ts @@ -14,7 +14,7 @@ import { } from './blockchain'; //import {connectToPeers, getSockets, initP2PServer} from './p2p'; -import {connectToPeers, getSockets, initP2PServer, setModeLocal, setModeDew} from './p2p'; +import {connectToPeers, getSockets, initP2PServer, setModeLocal, setModeDew, fetchAccounts} from './p2p'; //import {UnspentTxOut} from './transaction'; import {Account, findAccount} from './transaction'; @@ -52,6 +52,12 @@ const initHttpServer = (myHttpPort: number) => { res.send('The system is in ' + mode + ' mode.'); }); + app.get('/fetchAccounts', (req, res) => { + //This one should not be available in local mode. + fetchAccounts() + res.send('Accounts fetch requested.'); + }); + app.get('/blocks', (req, res) => { mode = getMode(); //if(mode == 'local'){ diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts index 1224cb5..043a7ba 100644 --- a/dew/src/p2p.ts +++ b/dew/src/p2p.ts @@ -7,10 +7,11 @@ import { } from './blockchain'; */ import { - addBlockToChain, Block, getBlockchain, resetBlockchain, getLatestBlock, handleReceivedTransaction, isValidBlockStructure, - replaceChain + addBlockToChain, Block, getBlockchain, resetBlockchain, getLatestBlock, handleReceivedTransaction, validateAccount, isValidBlockStructure, + replaceChain, setAccounts, getAccounts } from './blockchain'; -import {Transaction} from './transaction'; +//import {Transaction} from './transaction'; +import {Transaction, Account} from './transaction'; import {getTransactionPool} from './transactionPool'; //dewcoin @@ -26,7 +27,9 @@ enum MessageType { QUERY_ALL = 1, RESPONSE_BLOCKCHAIN = 2, QUERY_TRANSACTION_POOL = 3, - RESPONSE_TRANSACTION_POOL = 4 + RESPONSE_TRANSACTION_POOL = 4, + QUERY_ACCOUNTS = 5, + RESPONSE_ACCOUNTS = 6 } class Message { @@ -239,6 +242,25 @@ const initCloudMessageHandler = (ws: WebSocket) => { } }); break; + case MessageType.QUERY_ACCOUNTS: + write(ws, responseAccountsMsg()); + break; + case MessageType.RESPONSE_ACCOUNTS: + const receivedAccounts: Account[] = JSONToObject(message.data); + if (receivedAccounts === null) { + console.log('invalid accounts received: %s', JSON.stringify(message.data)); + break; + } + receivedAccounts.forEach((account: Account) => { + try { + validateAccount(account); + // if no error is thrown, accounts is valid + } catch (e) { + console.log(e.message); + } + }); + setAccounts(receivedAccounts); + break; } } catch (e) { console.log(e); @@ -281,6 +303,16 @@ const responseTransactionPoolMsg = (): Message => ({ 'data': JSON.stringify(getTransactionPool()) }); +const queryAccountsMsg = (): Message => ({ + 'type': MessageType.QUERY_ACCOUNTS, + 'data': JSON.stringify(getAccounts()) +}); + +const responseAccountsMsg = (): Message => ({ + 'type': MessageType.RESPONSE_ACCOUNTS, + 'data': JSON.stringify(getAccounts()) +}); + const initErrorHandler = (ws: WebSocket) => { const closeConnection = (myWs: WebSocket) => { console.log('connection failed to peer: ' + myWs.url); @@ -290,6 +322,15 @@ const initErrorHandler = (ws: WebSocket) => { ws.on('error', () => closeConnection(ws)); }; +const fetchAccounts = (): void => { + if((typeof wsCloud !== undefined) && (wsCloud.readyState == 1)){ + write(wsCloud, queryAccountsMsg()); + console.log('Accounts fetched.'); + } else { + console.log('Accounts fetch failed.'); + } +}; + const handleBlockchainResponse = (receivedBlocks: Block[]) => { if (receivedBlocks.length === 0) { @@ -388,4 +429,4 @@ const setModeDew = () => { //export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets}; export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets, -setModeLocal, setModeDew}; +setModeLocal, setModeDew, fetchAccounts}; diff --git a/dew/src/transaction.ts b/dew/src/transaction.ts index 2ef608a..1a41351 100644 --- a/dew/src/transaction.ts +++ b/dew/src/transaction.ts @@ -96,6 +96,9 @@ class TxHistory { } } + + + /* const getTransactionId = (transaction: Transaction): string => { const txInContent: string = transaction.txIns @@ -675,8 +678,8 @@ export { */ export { processTransactions, signTransaction, getTransactionId, isValidAddress, validateTransaction, - Account, findAccount, existAccount, createAccount, getCoinbaseTransaction, getPublicKey, hasDuplicates, - Transaction + Account, findAccount, existAccount, createAccount, getCoinbaseTransaction, + getPublicKey, hasDuplicates, Transaction }; // // From 4e06bf0b54aca9ba0def00f0e5436581ba7d447b Mon Sep 17 00:00:00 2001 From: ywang Date: Sun, 12 Aug 2018 08:49:42 -0400 Subject: [PATCH 27/36] ALTERNATE_ADDRESS message added --- cloud/src/p2p.ts | 16 ++++++++++++++-- cloud/src/transaction.ts | 8 ++++---- dew/src/p2p.ts | 18 ++++++++++++++++-- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/cloud/src/p2p.ts b/cloud/src/p2p.ts index 851c7d8..9f1c760 100644 --- a/cloud/src/p2p.ts +++ b/cloud/src/p2p.ts @@ -35,7 +35,8 @@ enum MessageType { QUERY_TRANSACTION_POOL = 3, RESPONSE_TRANSACTION_POOL = 4, QUERY_ACCOUNTS = 5, - RESPONSE_ACCOUNTS = 6 + RESPONSE_ACCOUNTS = 6, + ALTERNATE_ADDRESS = 7 } class Message { @@ -126,7 +127,6 @@ const JSONToObject = (data: string): T => { /* const initMessageHandler = (ws: WebSocket) => { ws.on('message', (data: string) => { - try { const message: Message = JSONToObject(data); if (message === null) { @@ -221,6 +221,10 @@ const initMessageHandler = (ws: WebSocket) => { } }); break; + case MessageType.ALTERNATE_ADDRESS: + //console.log('Alternate address received: %s', message.data); + //connectToPeers(message.data); + break; } } catch (e) { console.log(e); @@ -232,6 +236,7 @@ const initMessageHandler = (ws: WebSocket) => { const initCloudMessageHandler = (ws: WebSocket) => { ws.on('message', (data: string) => { + //console.log('New message from %s:%d', req.connection.remoteAddress.substring(7), req.connection.remotePort); try { const message: Message = JSONToObject(data); @@ -350,6 +355,13 @@ const responseAccountsMsg = (): Message => ({ 'data': JSON.stringify(getAccounts()) }); +/* +const alternateAddressMsg = (address: string): Message => ({ + 'type': MessageType.ALTERNATE_ADDRESS, + 'data': address +}); +*/ + const initErrorHandler = (ws: WebSocket) => { const closeConnection = (myWs: WebSocket) => { console.log('connection failed to peer: ' + myWs.url); diff --git a/cloud/src/transaction.ts b/cloud/src/transaction.ts index 64b7e9e..0299913 100644 --- a/cloud/src/transaction.ts +++ b/cloud/src/transaction.ts @@ -98,14 +98,14 @@ class TxHistory { const verifyAccounts = (accounts1: Account[], accounts2: Account[]): boolean => { - console.log('accounts1: ' + JSON.stringify(accounts1)); - console.log('accounts2: ' + JSON.stringify(accounts2)); + //console.log('accounts1: ' + JSON.stringify(accounts1)); + //console.log('accounts2: ' + JSON.stringify(accounts2)); const a1: Account[] = _.sortBy(accounts1, 'id'); const a2: Account[] = _.sortBy(accounts2, 'id'); const s1: string = JSON.stringify(a1); const s2: string = JSON.stringify(a2); - console.log('s1:' + s1); - console.log('s2:' + s2); + //console.log('s1:' + s1); + //console.log('s2:' + s2); return s1 === s2; } diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts index 043a7ba..bf29e62 100644 --- a/dew/src/p2p.ts +++ b/dew/src/p2p.ts @@ -29,7 +29,8 @@ enum MessageType { QUERY_TRANSACTION_POOL = 3, RESPONSE_TRANSACTION_POOL = 4, QUERY_ACCOUNTS = 5, - RESPONSE_ACCOUNTS = 6 + RESPONSE_ACCOUNTS = 6, + ALTERNATE_ADDRESS = 7 } class Message { @@ -69,6 +70,9 @@ const initConnection = (ws: WebSocket) => { sockets.push(ws); initMessageHandler(ws); initErrorHandler(ws); + if(getMode() == 'dew'){ + write(ws, alternateAddressMsg(getCloud())); + } write(ws, queryChainLengthMsg()); // query transactions pool only some time after chain query @@ -187,7 +191,11 @@ const initMessageHandler = (ws: WebSocket) => { } }); break; - } + case MessageType.ALTERNATE_ADDRESS: + console.log('Alternate address received: %s', message.data); + connectToPeers(message.data); + break; + } } catch (e) { console.log(e); } @@ -313,6 +321,12 @@ const responseAccountsMsg = (): Message => ({ 'data': JSON.stringify(getAccounts()) }); +const alternateAddressMsg = (address: string): Message => ({ + 'type': MessageType.ALTERNATE_ADDRESS, + 'data': address +}); + + const initErrorHandler = (ws: WebSocket) => { const closeConnection = (myWs: WebSocket) => { console.log('connection failed to peer: ' + myWs.url); From f96b59b4f9926f9fd116cfb41fab53916216b3dd Mon Sep 17 00:00:00 2001 From: ywang Date: Sun, 12 Aug 2018 14:10:25 -0400 Subject: [PATCH 28/36] ready for two machine debugging --- cloud/src/config.ts | 6 ++++++ cloud/src/main.ts | 12 ++++++++---- cloud/src/p2p.ts | 25 +++++++++---------------- dew/README.md | 3 ++- dew/src/config.ts | 6 +++--- dew/src/p2p.ts | 3 ++- 6 files changed, 30 insertions(+), 25 deletions(-) create mode 100644 cloud/src/config.ts diff --git a/cloud/src/config.ts b/cloud/src/config.ts new file mode 100644 index 0000000..3b82784 --- /dev/null +++ b/cloud/src/config.ts @@ -0,0 +1,6 @@ +let dewAddress = '127.0.0.1:6001'; + +const getDew = (): string => {return dewAddress}; +const setDew = (address: string) => {dewAddress = address}; + +export {getDew, setDew}; diff --git a/cloud/src/main.ts b/cloud/src/main.ts index 9d886a8..c79b367 100644 --- a/cloud/src/main.ts +++ b/cloud/src/main.ts @@ -13,8 +13,7 @@ import { getBlockchain, getMyAccount, getAccounts, sendTransaction } from './blockchain'; -//import {connectToPeers, getSockets, initP2PServer} from './p2p'; -import {connectToPeers, getSockets, initP2PServer, getDewAddress, setDewAddress} from './p2p'; +import {connectToPeers, getSockets, initP2PServer} from './p2p'; //import {UnspentTxOut} from './transaction'; import {Account, findAccount} from './transaction'; @@ -22,6 +21,11 @@ import {Account, findAccount} from './transaction'; import {getTransactionPool} from './transactionPool'; import {getPublicFromWallet, initWallet} from './wallet'; +//dewcoin +import {getDew, setDew} from './config'; + + + const httpPort: number = parseInt(process.env.HTTP_PORT) || 4001; const p2pPort: number = parseInt(process.env.P2P_PORT) || 7001; @@ -36,8 +40,8 @@ const initHttpServer = (myHttpPort: number) => { }); app.post('/SetDewAddress', (req, res) => { - setDewAddress(req.body.address); - console.log('Dew address: ' + getDewAddress()); + setDew(req.body.address); + console.log('Dew address: ' + getDew()); res.send(); }); diff --git a/cloud/src/p2p.ts b/cloud/src/p2p.ts index 9f1c760..17afeff 100644 --- a/cloud/src/p2p.ts +++ b/cloud/src/p2p.ts @@ -14,18 +14,14 @@ import { import {Transaction, Account, verifyAccounts} from './transaction'; import {getTransactionPool} from './transactionPool'; +//dewcoin +import {getDew} from './config'; + const sockets: WebSocket[] = []; const getSockets = () => sockets; //dewcoin let wsCloud: WebSocket; -let dewAddress: string = '127.0.0.1'; -const getDewAddress = () => { - return dewAddress; -} -const setDewAddress = (address: string) => { - dewAddress = address; -} enum MessageType { @@ -58,7 +54,10 @@ const initP2PServer = (p2pPort: number) => { const server: Server = new WebSocket.Server({port: p2pPort}); server.on('connection', (ws: WebSocket, req) => { console.log('New websocket connection from %s:%d', req.connection.remoteAddress.substring(7), req.connection.remotePort); - if(req.connection.remoteAddress.substring(7) == dewAddress){ + const dew: string = getDew(); + const address: string = dew.substring(0, dew.search(':')); + console.log('Address: %s', address); + if(req.connection.remoteAddress.substring(7) == address){ initCloudConnection(ws); }else{ initConnection(ws); @@ -82,6 +81,7 @@ const initConnection = (ws: WebSocket) => { }; */ const initConnection = (ws: WebSocket) => { + console.log('AAAAAAAAAAinit: ' + ws.url); sockets.push(ws); initMessageHandler(ws); initErrorHandler(ws); @@ -355,13 +355,6 @@ const responseAccountsMsg = (): Message => ({ 'data': JSON.stringify(getAccounts()) }); -/* -const alternateAddressMsg = (address: string): Message => ({ - 'type': MessageType.ALTERNATE_ADDRESS, - 'data': address -}); -*/ - const initErrorHandler = (ws: WebSocket) => { const closeConnection = (myWs: WebSocket) => { console.log('connection failed to peer: ' + myWs.url); @@ -419,4 +412,4 @@ const broadCastTransactionPool = () => { broadcast(responseTransactionPoolMsg()); }; -export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets, getDewAddress, setDewAddress}; +export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets}; diff --git a/dew/README.md b/dew/README.md index 7b62936..262af85 100644 --- a/dew/README.md +++ b/dew/README.md @@ -102,8 +102,9 @@ curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7 curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addpeer ``` For Windows: -curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:7001\"}" http://localhost:3001/addpeer +curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:6002\"}" http://localhost:3001/addpeer ``` +curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://192.168.1.186:6002\"}" http://localhost:3001/addpeer #### Stop the server diff --git a/dew/src/config.ts b/dew/src/config.ts index 4bb3bde..7adcad7 100644 --- a/dew/src/config.ts +++ b/dew/src/config.ts @@ -1,11 +1,11 @@ let mode: string = 'dew'; -let cloudServer = 'localhost:7001'; +let cloudAddress = '127.0.0.1:7001'; const getMode = ():string => {return mode;}; const setMode = (s: string) => {mode = s}; -const getCloud = (): string => {return cloudServer}; -const setCloud = (addressPort: string) => {cloudServer = addressPort}; +const getCloud = (): string => {return cloudAddress}; +const setCloud = (address: string) => {cloudAddress = address}; export {setMode, getMode, getCloud, setCloud}; diff --git a/dew/src/p2p.ts b/dew/src/p2p.ts index bf29e62..2b4e2c5 100644 --- a/dew/src/p2p.ts +++ b/dew/src/p2p.ts @@ -67,6 +67,7 @@ const getSockets = () => sockets; const initConnection = (ws: WebSocket) => { + console.log('AAAAAAAAAAinit: ' + ws.url); sockets.push(ws); initMessageHandler(ws); initErrorHandler(ws); @@ -193,7 +194,7 @@ const initMessageHandler = (ws: WebSocket) => { break; case MessageType.ALTERNATE_ADDRESS: console.log('Alternate address received: %s', message.data); - connectToPeers(message.data); + connectToPeers('ws://' + message.data); break; } } catch (e) { From b4589231793099bc2db3ee52539f9f6ce57ec13a Mon Sep 17 00:00:00 2001 From: Yingwei Wang Date: Sun, 12 Aug 2018 14:54:12 -0400 Subject: [PATCH 29/36] Two machine initial test OK --- cloud/src/config.ts | 3 ++- cloud/src/wallet.ts | 9 ++++++--- dew/src/config.ts | 3 ++- dew/src/wallet.ts | 9 ++++++--- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/cloud/src/config.ts b/cloud/src/config.ts index 3b82784..93593f9 100644 --- a/cloud/src/config.ts +++ b/cloud/src/config.ts @@ -1,4 +1,5 @@ -let dewAddress = '127.0.0.1:6001'; +//let dewAddress = '127.0.0.1:6001'; +let dewAddress = '192.168.1.114:6001'; const getDew = (): string => {return dewAddress}; const setDew = (address: string) => {dewAddress = address}; diff --git a/cloud/src/wallet.ts b/cloud/src/wallet.ts index e166bfb..62d02ae 100644 --- a/cloud/src/wallet.ts +++ b/cloud/src/wallet.ts @@ -28,18 +28,21 @@ const generatePrivateKey = (): string => { }; const initWallet = () => { - if (!existAccount(getPublicFromWallet(), getAccounts())) { - createAccount(getPublicFromWallet(), getAccounts()); - } console.log('an account was created.'); // let's not override existing private keys if (existsSync(privateKeyLocation)) { + if (!existAccount(getPublicFromWallet(), getAccounts())) { + createAccount(getPublicFromWallet(), getAccounts()); + } return; } const newPrivateKey = generatePrivateKey(); writeFileSync(privateKeyLocation, newPrivateKey); console.log('new wallet with private key created to : %s', privateKeyLocation); + if (!existAccount(getPublicFromWallet(), getAccounts())) { + createAccount(getPublicFromWallet(), getAccounts()); + } }; const deleteWallet = () => { diff --git a/dew/src/config.ts b/dew/src/config.ts index 7adcad7..178f653 100644 --- a/dew/src/config.ts +++ b/dew/src/config.ts @@ -1,5 +1,6 @@ let mode: string = 'dew'; -let cloudAddress = '127.0.0.1:7001'; +//let cloudAddress = '127.0.0.1:7001'; +let cloudAddress = '192.168.1.114:7001'; diff --git a/dew/src/wallet.ts b/dew/src/wallet.ts index e166bfb..62d02ae 100644 --- a/dew/src/wallet.ts +++ b/dew/src/wallet.ts @@ -28,18 +28,21 @@ const generatePrivateKey = (): string => { }; const initWallet = () => { - if (!existAccount(getPublicFromWallet(), getAccounts())) { - createAccount(getPublicFromWallet(), getAccounts()); - } console.log('an account was created.'); // let's not override existing private keys if (existsSync(privateKeyLocation)) { + if (!existAccount(getPublicFromWallet(), getAccounts())) { + createAccount(getPublicFromWallet(), getAccounts()); + } return; } const newPrivateKey = generatePrivateKey(); writeFileSync(privateKeyLocation, newPrivateKey); console.log('new wallet with private key created to : %s', privateKeyLocation); + if (!existAccount(getPublicFromWallet(), getAccounts())) { + createAccount(getPublicFromWallet(), getAccounts()); + } }; const deleteWallet = () => { From 6617932ae4a79a1f098b1a2baa444543ea9802aa Mon Sep 17 00:00:00 2001 From: ywang Date: Mon, 13 Aug 2018 13:29:14 -0400 Subject: [PATCH 30/36] Mine in cloud added folders changed --- .gitignore | 16 +-- README.md | 63 ++++------ cloud/README.md | 117 ------------------ cloud/src/config.ts | 7 -- dew/src/config.ts | 12 -- {cloud => dewcoin-cloud}/License.txt | 0 dewcoin-cloud/README.md | 73 +++++++++++ .../node/wallet/.gitignore | 0 {cloud => dewcoin-cloud}/package-lock.json | 0 {cloud => dewcoin-cloud}/package.json | 0 {cloud => dewcoin-cloud}/src/blockchain.ts | 14 +-- dewcoin-cloud/src/config.ts | 9 ++ {cloud => dewcoin-cloud}/src/main.ts | 27 +++- {cloud => dewcoin-cloud}/src/p2p.ts | 25 ++-- {cloud => dewcoin-cloud}/src/transaction.ts | 24 ---- {dew => dewcoin-cloud}/src/transactionPool.ts | 2 - {cloud => dewcoin-cloud}/src/util.ts | 0 {cloud => dewcoin-cloud}/src/wallet.ts | 3 +- {cloud => dewcoin-cloud}/tsconfig.json | 0 {cloud => dewcoin-cloud}/tslint.json | 0 {dew => dewcoin-dew}/License.txt | 0 {dew => dewcoin-dew}/README.md | 73 ++++++++--- {dew => dewcoin-dew}/node/wallet/.gitignore | 0 {dew => dewcoin-dew}/package-lock.json | 0 {dew => dewcoin-dew}/package.json | 0 {dew => dewcoin-dew}/src/blockchain.ts | 54 ++++---- dewcoin-dew/src/config.ts | 16 +++ {dew => dewcoin-dew}/src/main.ts | 7 +- {dew => dewcoin-dew}/src/p2p.ts | 19 +-- {dew => dewcoin-dew}/src/transaction.ts | 50 +++----- {cloud => dewcoin-dew}/src/transactionPool.ts | 2 - {dew => dewcoin-dew}/src/util.ts | 0 {dew => dewcoin-dew}/src/wallet.ts | 3 +- {dew => dewcoin-dew}/tsconfig.json | 0 {dew => dewcoin-dew}/tslint.json | 0 35 files changed, 291 insertions(+), 325 deletions(-) delete mode 100644 cloud/README.md delete mode 100644 cloud/src/config.ts delete mode 100644 dew/src/config.ts rename {cloud => dewcoin-cloud}/License.txt (100%) create mode 100644 dewcoin-cloud/README.md rename {cloud => dewcoin-cloud}/node/wallet/.gitignore (100%) rename {cloud => dewcoin-cloud}/package-lock.json (100%) rename {cloud => dewcoin-cloud}/package.json (100%) rename {cloud => dewcoin-cloud}/src/blockchain.ts (98%) create mode 100644 dewcoin-cloud/src/config.ts rename {cloud => dewcoin-cloud}/src/main.ts (97%) rename {cloud => dewcoin-cloud}/src/p2p.ts (94%) rename {cloud => dewcoin-cloud}/src/transaction.ts (95%) rename {dew => dewcoin-cloud}/src/transactionPool.ts (97%) rename {cloud => dewcoin-cloud}/src/util.ts (100%) rename {cloud => dewcoin-cloud}/src/wallet.ts (98%) rename {cloud => dewcoin-cloud}/tsconfig.json (100%) rename {cloud => dewcoin-cloud}/tslint.json (100%) rename {dew => dewcoin-dew}/License.txt (100%) rename {dew => dewcoin-dew}/README.md (71%) rename {dew => dewcoin-dew}/node/wallet/.gitignore (100%) rename {dew => dewcoin-dew}/package-lock.json (100%) rename {dew => dewcoin-dew}/package.json (100%) rename {dew => dewcoin-dew}/src/blockchain.ts (94%) create mode 100644 dewcoin-dew/src/config.ts rename {dew => dewcoin-dew}/src/main.ts (96%) rename {dew => dewcoin-dew}/src/p2p.ts (97%) rename {dew => dewcoin-dew}/src/transaction.ts (96%) rename {cloud => dewcoin-dew}/src/transactionPool.ts (97%) rename {dew => dewcoin-dew}/src/util.ts (100%) rename {dew => dewcoin-dew}/src/wallet.ts (98%) rename {dew => dewcoin-dew}/tsconfig.json (100%) rename {dew => dewcoin-dew}/tslint.json (100%) diff --git a/.gitignore b/.gitignore index 773ecb3..e012045 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ -cloud/node_modules -cloud/npm-debug.log -cloud/src/*.js -cloud/src/*.map -dew/node_modules -dew/npm-debug.log -dew/src/*.js -dew/src/*.map +dewcoin-cloud/node_modules +dewcoin-cloud/npm-debug.log +dewcoin-cloud/src/*.js +dewcoin-cloud/src/*.map +dewcoin-dew/node_modules +dewcoin-dew/npm-debug.log +dewcoin-dew/src/*.js +dewcoin-dew/src/*.map diff --git a/README.md b/README.md index 839b976..d4409f2 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,40 @@ # Dewcoin -naivecoin dew computing version. a proof of concept for blockchain applications that follow dew computing principles. http://www.dewcomputing.org/ +Dewcoin is a blockchain cryptocurrency system that is based on dew computing principles. The code is pretty detailed but still not detailed enough for immediate production operation. It is basically a Proof of Concept system. -(in progress) +The mechanism of dewcoin will be introduced separately. Some information about dew computing can be found in: http://www.dewcomputing.org/ -Basic principles of naivecoin can be found in: A tutorial for building a cryptocurrency https://lhartikk.github.io/ -``` -npm install -npm start -``` +Dewcoin is based on Naivecoin. The introduction of Naivecoin can be found in: A tutorial for building a cryptocurrency https://lhartikk.github.io/ -##### Get blockchain -``` -curl http://localhost:3001/blocks -``` -##### Mine a block -``` -curl -X POST http://localhost:3001/mineBlock -``` +## Package Placement -##### Send transaction -``` -curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction -``` +Dewcoin has two components: the cloud package and the dew package. Ideally, the cloud package should be installed in a computer that is running all the time and has a fixed IP address so that it can be accessed easily. The dew package can be installed in a locally computer. For testing purposes, the cloud package and the dew package can be put in the same computer. -##### Query transaction pool -``` -curl http://localhost:3001/transactionPool -``` +## Package Configuraton -##### Mine transaction -``` -curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction -``` +Configuraton files: +dewcoin-dew/src/config.ts +dewcoin-cloud/src/config.ts -##### Get balance -``` -curl http://localhost:3001/balance -``` +Detailed configuration guidelines can be found in these files. -#### Query information about a specific address -``` -curl http://localhost:3001/address/04f72a4541275aeb4344a8b049bfe2734b49fe25c08d56918f033507b96a61f9e3c330c4fcd46d0854a712dc878b9c280abe90c788c47497e06df78b25bf60ae64 -``` -##### Add peer +## Package Installation + +Both packages should be installed in the Node.js environment. + +Installation command: ``` -curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addPeer +npm install ``` -#### Query connected peers +Running command: ``` -curl http://localhost:3001/peers +npm start ``` +## Dewcoin Operation + +Dewcoin system can be operated through an API composed of a group of HTTP commands. These commands can be issued through browsers, designed web forms, HTTP clients such as curl. + +We use curl to describe the API, but it does not mean curl is the only way to operate Dewcoin. + diff --git a/cloud/README.md b/cloud/README.md deleted file mode 100644 index 724e0a7..0000000 --- a/cloud/README.md +++ /dev/null @@ -1,117 +0,0 @@ -# Dewcoin - -naivecoin dew computing version. a proof of concept for blockchain applications that follow dew computing principles. http://www.dewcomputing.org/ - -(in progress) - -Basic principles of naivecoin can be found in: A tutorial for building a cryptocurrency https://lhartikk.github.io/ -``` -npm install -npm start -``` - -##### Set Dew Address -Example for Windows: -curl -H "Content-type:application/json" --data "{\"address\": \"192.168.1.186\"}" http://localhost:4001/SetDewAddress - - -##### Query the whole blockchain -curl http://localhost:3001/blocks -pass to cloud - - -##### Query all accounts - -curl http://localhost:3001/accounts - - -##### Query the transaction pool -``` -curl http://localhost:3001/transactionPool -``` - - -#### Query all connected peers -``` -curl http://localhost:3001/peers -``` - - -##### Query my account - -curl http://localhost:3001/myaccount - - -##### Query my account balance -``` -curl http://localhost:3001/mybalance -``` - - -##### Query my account address - -curl http://localhost:3001/myaddress - - - -##### Query a block with block hash - -curl http://localhost:3001/block/:hash - -pass to cloud - - - -##### Query a transaction with transaction id - -curl http://localhost:3001/transaction/:id -pass to cloud - - -##### Query an account with account address - -curl http://localhost:3001/account/:address - - - -##### Mine a block -The block will contain the transactions in the pool. -``` -curl -X POST http://localhost:3001/mineBlock -``` -pass to cloud - - -##### Send a transaction to the pool -``` -curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction -``` -For Windows: -curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7cf8216982cf85f1b8edd51de012f1222bd2b37bb1217a42d31f8feda18be34aa09a759d2a70c5d6d0cc6cdd67e4e8c1761beb27e680bddd89b6\", \"amount\" : 25}" http://localhost:3001/sendTransaction - - - -##### Mine a block with a transaction -If the transaction is invalid, the block will still be mined. -pass to cloud -``` -curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction -``` -For Windows: -curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7cf8216982cf85f1b8edd51de012f1222bd2b37bb1217a42d31f8feda18be34aa09a759d2a70c5d6d0cc6cdd67e4e8c1761beb27e680bddd89b6\", \"amount\" : 20}" http://localhost:3001/mineTransaction - - -##### Add peer -``` -curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addpeer -``` -For Windows: -curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:7001\"}" http://localhost:3001/addpeer -``` - - -#### Stop the server -``` -curl -X POST http://localhost:3001/stop -``` - diff --git a/cloud/src/config.ts b/cloud/src/config.ts deleted file mode 100644 index 93593f9..0000000 --- a/cloud/src/config.ts +++ /dev/null @@ -1,7 +0,0 @@ -//let dewAddress = '127.0.0.1:6001'; -let dewAddress = '192.168.1.114:6001'; - -const getDew = (): string => {return dewAddress}; -const setDew = (address: string) => {dewAddress = address}; - -export {getDew, setDew}; diff --git a/dew/src/config.ts b/dew/src/config.ts deleted file mode 100644 index 178f653..0000000 --- a/dew/src/config.ts +++ /dev/null @@ -1,12 +0,0 @@ -let mode: string = 'dew'; -//let cloudAddress = '127.0.0.1:7001'; -let cloudAddress = '192.168.1.114:7001'; - - - -const getMode = ():string => {return mode;}; -const setMode = (s: string) => {mode = s}; -const getCloud = (): string => {return cloudAddress}; -const setCloud = (address: string) => {cloudAddress = address}; - -export {setMode, getMode, getCloud, setCloud}; diff --git a/cloud/License.txt b/dewcoin-cloud/License.txt similarity index 100% rename from cloud/License.txt rename to dewcoin-cloud/License.txt diff --git a/dewcoin-cloud/README.md b/dewcoin-cloud/README.md new file mode 100644 index 0000000..735cb80 --- /dev/null +++ b/dewcoin-cloud/README.md @@ -0,0 +1,73 @@ +# Dewcoin-cloud Package + +This package has no modes. Dewcoin-cloud behaves like Naivecoin. Especially, it provides the whole blockchain to other nodes to fulfil the responsibility a full blockchain node. It also uses the complete blochchain to garantee the accuracy of all the transactions. + + +#### Installation and System Start + +``` +npm install +npm start +``` + +##### Set Dew Address +``` +curl -H "Content-type:application/json" --data '{"address" : "192.168.1.186"}' http://localhost:3001/SetDewAddress +``` +For Windows: +``` +curl -H "Content-type:application/json" --data "{\"address\" : \"192.168.1.186\"}" http://localhost:3001/SetDewAddress +``` + +##### Query the whole blockchain +``` +curl http://localhost:3001/blocks +``` +In dew mode, the blockchain has only the genesis block. + + +##### Query all accounts + +``` +curl http://localhost:3001/accounts +``` + +##### Query the transaction pool +``` +curl http://localhost:3001/transactionPool +``` + + +#### Query all connected peers +``` +curl http://localhost:3001/peers +``` + + +##### Query a block with block hash + +``` +curl http://localhost:3001/block/:hash +``` +In dew mode, this is useless. + + + +##### Query a transaction with transaction id + +``` +curl http://localhost:3001/transaction/:id +``` +In dew mode, this is useless. + + +##### Query an account with account address + +``` +curl http://localhost:3001/account/:address +``` + +#### Stop the server +``` +curl -X POST http://localhost:3001/stop +``` diff --git a/cloud/node/wallet/.gitignore b/dewcoin-cloud/node/wallet/.gitignore similarity index 100% rename from cloud/node/wallet/.gitignore rename to dewcoin-cloud/node/wallet/.gitignore diff --git a/cloud/package-lock.json b/dewcoin-cloud/package-lock.json similarity index 100% rename from cloud/package-lock.json rename to dewcoin-cloud/package-lock.json diff --git a/cloud/package.json b/dewcoin-cloud/package.json similarity index 100% rename from cloud/package.json rename to dewcoin-cloud/package.json diff --git a/cloud/src/blockchain.ts b/dewcoin-cloud/src/blockchain.ts similarity index 98% rename from cloud/src/blockchain.ts rename to dewcoin-cloud/src/blockchain.ts index 2a97d0d..ea8d71f 100644 --- a/cloud/src/blockchain.ts +++ b/dewcoin-cloud/src/blockchain.ts @@ -341,8 +341,7 @@ const isValidChain = (blockchainToValidate: Block[]): UnspentTxOut[] => { }; */ const isValidChain = (blockchainToValidate: Block[]): Account[] => { - console.log('isValidChain:'); - console.log(JSON.stringify(blockchainToValidate)); + //console.log(JSON.stringify(blockchainToValidate)); const isValidGenesis = (block: Block): boolean => { return JSON.stringify(block) === JSON.stringify(genesisBlock); }; @@ -442,7 +441,6 @@ const handleReceivedTransaction = (transaction: Transaction) => { }; */ const handleReceivedTransaction = (transaction: Transaction) => { -//console.log('***handleReceivedTransacton:***'); addToTransactionPool(transaction, getAccounts()); }; @@ -473,13 +471,5 @@ export { Block, getBlockchain, getAccounts, setAccounts, getLatestBlock, sendTransaction, generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, handleReceivedTransaction, validateAccount, getMyAccount, - getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain, getCurrentTimestamp + getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain, getCurrentTimestamp, findBlock }; - -/* -getUnspentTxOuts = (): UnspentTxOut[] -getAccounts = (): Account[] - -getMyUnspentTransactionOutputs() -getMyAccount() -*/ diff --git a/dewcoin-cloud/src/config.ts b/dewcoin-cloud/src/config.ts new file mode 100644 index 0000000..60e1bb0 --- /dev/null +++ b/dewcoin-cloud/src/config.ts @@ -0,0 +1,9 @@ +let dewAddress = '127.0.0.1:6001'; +//let dewAddress = '192.168.1.114:6001'; +//If dew address is not correct, it can also be set using HTTP command. See Readme. + + + +const getDew = (): string => {return dewAddress}; +const setDew = (address: string) => {dewAddress = address}; +export {getDew, setDew}; diff --git a/cloud/src/main.ts b/dewcoin-cloud/src/main.ts similarity index 97% rename from cloud/src/main.ts rename to dewcoin-cloud/src/main.ts index c79b367..b496033 100644 --- a/cloud/src/main.ts +++ b/dewcoin-cloud/src/main.ts @@ -24,8 +24,6 @@ import {getPublicFromWallet, initWallet} from './wallet'; //dewcoin import {getDew, setDew} from './config'; - - const httpPort: number = parseInt(process.env.HTTP_PORT) || 4001; const p2pPort: number = parseInt(process.env.P2P_PORT) || 7001; @@ -92,6 +90,7 @@ const initHttpServer = (myHttpPort: number) => { res.send(getMyUnspentTransactionOutputs()); }); */ + /* app.get('/myaccount', (req, res) => { let acc: Account = findAccount(getPublicFromWallet(), getAccounts()); if(acc == undefined){ @@ -100,7 +99,9 @@ const initHttpServer = (myHttpPort: number) => { res.send({'My Account': acc}); } }); + */ + /* app.post('/mineRawBlock', (req, res) => { if (req.body.data == null) { res.send('data parameter is missing'); @@ -113,7 +114,8 @@ const initHttpServer = (myHttpPort: number) => { res.send(newBlock); } }); - + */ + /* app.post('/mineBlock', (req, res) => { const newBlock: Block = generateNextBlock(); if (newBlock === null) { @@ -122,7 +124,9 @@ const initHttpServer = (myHttpPort: number) => { res.send(newBlock); } }); - + */ + + /* app.get('/mybalance', (req, res) => { let acc: Account = findAccount(getPublicFromWallet(), getAccounts()); if(acc == undefined){ @@ -131,12 +135,16 @@ const initHttpServer = (myHttpPort: number) => { res.send({'Balance': acc.balance}); } }); + */ + /* app.get('/myaddress', (req, res) => { const address: string = getPublicFromWallet(); res.send({'address': address}); }); + */ + /* app.post('/mineTransaction', (req, res) => { const address = req.body.address; const amount = req.body.amount; @@ -148,7 +156,9 @@ const initHttpServer = (myHttpPort: number) => { res.status(400).send(e.message); } }); + */ + /* app.post('/sendTransaction', (req, res) => { try { const address = req.body.address; @@ -164,6 +174,7 @@ const initHttpServer = (myHttpPort: number) => { res.status(400).send(e.message); } }); + */ app.get('/transactionpool', (req, res) => { res.send(getTransactionPool()); @@ -172,16 +183,20 @@ const initHttpServer = (myHttpPort: number) => { app.get('/peers', (req, res) => { res.send(getSockets().map((s: any) => s._socket.remoteAddress + ':' + s._socket.remotePort)); }); + + /* app.post('/addpeer', (req, res) => { connectToPeers(req.body.peer); res.send(); }); - + */ + app.post('/stop', (req, res) => { res.send({'msg' : 'stopping server'}); process.exit(); }); + app.listen(myHttpPort, () => { console.log('Listening http on port: ' + myHttpPort); }); @@ -189,4 +204,4 @@ const initHttpServer = (myHttpPort: number) => { initHttpServer(httpPort); initP2PServer(p2pPort); -initWallet(); +//initWallet(); diff --git a/cloud/src/p2p.ts b/dewcoin-cloud/src/p2p.ts similarity index 94% rename from cloud/src/p2p.ts rename to dewcoin-cloud/src/p2p.ts index 17afeff..13c1c8b 100644 --- a/cloud/src/p2p.ts +++ b/dewcoin-cloud/src/p2p.ts @@ -8,7 +8,7 @@ import { */ import { addBlockToChain, Block, getBlockchain, getLatestBlock, handleReceivedTransaction, validateAccount, isValidBlockStructure, - replaceChain, setAccounts, getAccounts + replaceChain, setAccounts, getAccounts, findBlock } from './blockchain'; //import {Transaction} from './transaction'; import {Transaction, Account, verifyAccounts} from './transaction'; @@ -32,7 +32,8 @@ enum MessageType { RESPONSE_TRANSACTION_POOL = 4, QUERY_ACCOUNTS = 5, RESPONSE_ACCOUNTS = 6, - ALTERNATE_ADDRESS = 7 + ALTERNATE_ADDRESS = 7, + MINING_REQUEST = 8 } class Message { @@ -56,7 +57,7 @@ const initP2PServer = (p2pPort: number) => { console.log('New websocket connection from %s:%d', req.connection.remoteAddress.substring(7), req.connection.remotePort); const dew: string = getDew(); const address: string = dew.substring(0, dew.search(':')); - console.log('Address: %s', address); + //console.log('Address: %s', address); if(req.connection.remoteAddress.substring(7) == address){ initCloudConnection(ws); }else{ @@ -81,7 +82,7 @@ const initConnection = (ws: WebSocket) => { }; */ const initConnection = (ws: WebSocket) => { - console.log('AAAAAAAAAAinit: ' + ws.url); + console.log('A socket is created: ' + ws.url); sockets.push(ws); initMessageHandler(ws); initErrorHandler(ws); @@ -109,7 +110,6 @@ const initCloudConnection = (ws: WebSocket) => { // query transactions pool only some time after chain query setTimeout(() => { write(wsCloud, queryTransactionPoolMsg()); - //broadcast(queryTransactionPoolMsg()); }, 500); }; @@ -185,7 +185,7 @@ const initMessageHandler = (ws: WebSocket) => { console.log('could not parse received JSON message: ' + data); return; } - console.log('[Received message: %s', JSON.stringify(message)); + console.log('[Received message: %s', data); switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -244,7 +244,7 @@ const initCloudMessageHandler = (ws: WebSocket) => { console.log('could not parse received JSON message: ' + data); return; } - console.log('[Received cloud message: %s', JSON.stringify(message)); + console.log('[Received cloud message: %s', data); switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -309,6 +309,17 @@ const initCloudMessageHandler = (ws: WebSocket) => { }); setAccounts(receivedAccounts); break; + case MessageType.MINING_REQUEST: + const aBlock: Block = JSONToObject(message.data); + if (aBlock === null) { + console.log('invalid block received: %s', JSON.stringify(message.data)); + break; + } + const newBlock: Block = findBlock(aBlock.index, aBlock.previousHash, aBlock.timestamp, aBlock.data, aBlock.difficulty); + if (addBlockToChain(newBlock)) { + broadcastLatest(); + } + break; } } catch (e) { console.log(e); diff --git a/cloud/src/transaction.ts b/dewcoin-cloud/src/transaction.ts similarity index 95% rename from cloud/src/transaction.ts rename to dewcoin-cloud/src/transaction.ts index 0299913..1732b17 100644 --- a/cloud/src/transaction.ts +++ b/dewcoin-cloud/src/transaction.ts @@ -167,8 +167,6 @@ const validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTx }; */ const existAccount = (address: string, accounts: Account[]): boolean => { - //console.log('address: ' + address); - //console.log('accounts: '+ JSON.stringify(accounts)); return _(accounts).map((acc: Account) => acc.address).includes(address); } const createAccount = (address: string, accounts: Account[]): boolean => { @@ -693,25 +691,3 @@ export { Account, findAccount, existAccount, createAccount, verifyAccounts, getCoinbaseTransaction, getPublicKey, hasDuplicates, Transaction }; -// -// -//Transaction -//UnspentTxOut => Account -//-TxIn -//-TxOut -// -//signTxIn = (transaction: Transaction, txInIndex: number, -// privateKey: string, aUnspentTxOuts: UnspentTxOut[]): string => { -//signTransaction = (transaction: Transaction, privateKey: string): string => { -// -//processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number) -//processTransactions = (aTransactions: Transaction[], accounts: Account[]) -// -//validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean -//validateTransaction = (transaction: Transaction, accounts: Account[]): boolean -// -//getCoinbaseTransaction = (address: string, blockIndex: number): Transaction -//getCoinbaseTransaction = (miner: string): Transaction -// -//hasDuplicates = (txIns: TxIn[]): boolean -//hasDuplicates = (nums: number[]): boolean diff --git a/dew/src/transactionPool.ts b/dewcoin-cloud/src/transactionPool.ts similarity index 97% rename from dew/src/transactionPool.ts rename to dewcoin-cloud/src/transactionPool.ts index 66333df..4d20902 100644 --- a/dew/src/transactionPool.ts +++ b/dewcoin-cloud/src/transactionPool.ts @@ -131,8 +131,6 @@ const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): bo const isValidTxForPool = (tx: Transaction, aTransactionPool: Transaction[], accounts: Account[]): boolean => { let accSender: Account; -//console.log('isValidForPool: a Pool: ' + JSON.stringify(aTransactionPool)); -//console.log('tx: ' + JSON.stringify(tx)); for(let i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } diff --git a/cloud/src/util.ts b/dewcoin-cloud/src/util.ts similarity index 100% rename from cloud/src/util.ts rename to dewcoin-cloud/src/util.ts diff --git a/cloud/src/wallet.ts b/dewcoin-cloud/src/wallet.ts similarity index 98% rename from cloud/src/wallet.ts rename to dewcoin-cloud/src/wallet.ts index 62d02ae..4760054 100644 --- a/cloud/src/wallet.ts +++ b/dewcoin-cloud/src/wallet.ts @@ -28,11 +28,11 @@ const generatePrivateKey = (): string => { }; const initWallet = () => { - console.log('an account was created.'); // let's not override existing private keys if (existsSync(privateKeyLocation)) { if (!existAccount(getPublicFromWallet(), getAccounts())) { createAccount(getPublicFromWallet(), getAccounts()); + console.log('an account was created.'); } return; } @@ -42,6 +42,7 @@ const initWallet = () => { console.log('new wallet with private key created to : %s', privateKeyLocation); if (!existAccount(getPublicFromWallet(), getAccounts())) { createAccount(getPublicFromWallet(), getAccounts()); + console.log('an account was created.'); } }; diff --git a/cloud/tsconfig.json b/dewcoin-cloud/tsconfig.json similarity index 100% rename from cloud/tsconfig.json rename to dewcoin-cloud/tsconfig.json diff --git a/cloud/tslint.json b/dewcoin-cloud/tslint.json similarity index 100% rename from cloud/tslint.json rename to dewcoin-cloud/tslint.json diff --git a/dew/License.txt b/dewcoin-dew/License.txt similarity index 100% rename from dew/License.txt rename to dewcoin-dew/License.txt diff --git a/dew/README.md b/dewcoin-dew/README.md similarity index 71% rename from dew/README.md rename to dewcoin-dew/README.md index 262af85..efab463 100644 --- a/dew/README.md +++ b/dewcoin-dew/README.md @@ -1,25 +1,49 @@ -# Dewcoin +# Dewcoin-dew Package -naivecoin dew computing version. a proof of concept for blockchain applications that follow dew computing principles. http://www.dewcomputing.org/ +This package has two modes: local mode and dew mode. -(in progress) +In local mode, dewcoin behaves like Naivecoin. + +In dew mode, dewcoin behaves like Naivecoin without the blockchain. Thus, dewcoin-dew does not need huge memory like a normal blockchain system. + +#### Installation and System Start -Basic principles of naivecoin can be found in: A tutorial for building a cryptocurrency https://lhartikk.github.io/ ``` npm install npm start ``` +##### Set Mode Local +``` +curl http://localhost:3001/setmodelocal +``` + + +##### Set Mode Dew +``` +curl http://localhost:3001/setmodedew +``` + + +##### Fetch Accounts +Send dew accounts to the cloud for verification. If consistent, nothing the cloud will do; if not consistent, the cloud accounts will be fetched to the dew and replace the dew accounts. +``` +curl http://localhost:3001/fetchAccounts +``` + ##### Query the whole blockchain +``` curl http://localhost:3001/blocks -pass to cloud +``` +In dew mode, the blockchain has only the genesis block. ##### Query all accounts +``` curl http://localhost:3001/accounts - +``` ##### Query the transaction pool ``` @@ -35,8 +59,9 @@ curl http://localhost:3001/peers ##### Query my account +``` curl http://localhost:3001/myaccount - +``` ##### Query my account balance ``` @@ -46,69 +71,77 @@ curl http://localhost:3001/mybalance ##### Query my account address +``` curl http://localhost:3001/myaddress +``` ##### Query a block with block hash +``` curl http://localhost:3001/block/:hash - -pass to cloud +``` +In dew mode, this is useless. ##### Query a transaction with transaction id +``` curl http://localhost:3001/transaction/:id -pass to cloud +``` +In dew mode, this is useless. ##### Query an account with account address +``` curl http://localhost:3001/account/:address - - +``` ##### Mine a block The block will contain the transactions in the pool. ``` curl -X POST http://localhost:3001/mineBlock ``` -pass to cloud +##### Mine a block in the cloud +The block will contain the transactions in the pool. +``` +curl -X POST http://localhost:3001/mineInCloud +``` ##### Send a transaction to the pool ``` curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/sendTransaction ``` For Windows: +``` curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7cf8216982cf85f1b8edd51de012f1222bd2b37bb1217a42d31f8feda18be34aa09a759d2a70c5d6d0cc6cdd67e4e8c1761beb27e680bddd89b6\", \"amount\" : 25}" http://localhost:3001/sendTransaction - - +``` ##### Mine a block with a transaction If the transaction is invalid, the block will still be mined. -pass to cloud ``` curl -H "Content-type: application/json" --data '{"address": "04bfcab8722991ae774db48f934ca79cfb7dd991229153b9f732ba5334aafcd8e7266e47076996b55a14bf9913ee3145ce0cfc1372ada8ada74bd287450313534b", "amount" : 35}' http://localhost:3001/mineTransaction ``` For Windows: +``` curl -H "Content-type: application/json" --data "{\"address\": \"04b3e56e277a9a7cf8216982cf85f1b8edd51de012f1222bd2b37bb1217a42d31f8feda18be34aa09a759d2a70c5d6d0cc6cdd67e4e8c1761beb27e680bddd89b6\", \"amount\" : 20}" http://localhost:3001/mineTransaction - +``` ##### Add peer ``` curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"}' http://localhost:3001/addpeer ``` For Windows: -curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:6002\"}" http://localhost:3001/addpeer ``` +curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:6002\"}" http://localhost:3001/addpeer curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://192.168.1.186:6002\"}" http://localhost:3001/addpeer - +``` #### Stop the server ``` curl -X POST http://localhost:3001/stop ``` - diff --git a/dew/node/wallet/.gitignore b/dewcoin-dew/node/wallet/.gitignore similarity index 100% rename from dew/node/wallet/.gitignore rename to dewcoin-dew/node/wallet/.gitignore diff --git a/dew/package-lock.json b/dewcoin-dew/package-lock.json similarity index 100% rename from dew/package-lock.json rename to dewcoin-dew/package-lock.json diff --git a/dew/package.json b/dewcoin-dew/package.json similarity index 100% rename from dew/package.json rename to dewcoin-dew/package.json diff --git a/dew/src/blockchain.ts b/dewcoin-dew/src/blockchain.ts similarity index 94% rename from dew/src/blockchain.ts rename to dewcoin-dew/src/blockchain.ts index 72d1a75..4637b1c 100644 --- a/dew/src/blockchain.ts +++ b/dewcoin-dew/src/blockchain.ts @@ -1,6 +1,7 @@ import * as CryptoJS from 'crypto-js'; import * as _ from 'lodash'; -import {broadcastLatest, broadCastTransactionPool} from './p2p'; +//import {broadcastLatest, broadCastTransactionPool} from './p2p'; +import {broadcastLatest, broadCastTransactionPool, sendMiningRequest} from './p2p'; /* import { @@ -69,7 +70,6 @@ const genesisBlock: Block = new Block( const genesisBlock: Block = new Block( 0, '91a73664bc84c0baa1fc75ea6e4aa6d1d20c5df664c724e3159aefc2e1186627', '', 1533641911, [genesisTransaction], 0, 0 ); - let blockchain: Block[] = [genesisBlock]; const getBlockchain = (): Block[] => blockchain; //dewcoin @@ -81,12 +81,6 @@ let accounts: Account[] = processTransactions(blockchain[0].data, []); //const getUnspentTxOuts = (): UnspentTxOut[] => _.cloneDeep(unspentTxOuts); //const getAccounts = (): Account[] => _.cloneDeep(accounts); const getAccounts = (): Account[] => accounts; - -//dewcoin -let theLatestBlock: Block = genesisBlock; -let previousAdjustBlock: Block = genesisBlock; -let accuDiff = 1; - // and txPool should be only updated at the same time /* const setUnspentTxOuts = (newUnspentTxOut: UnspentTxOut[]) => { @@ -99,7 +93,10 @@ const setAccounts = (newAccounts: Account[]) => { accounts = newAccounts; }; - +//dewcoin +let theLatestBlock: Block = genesisBlock; +let previousAdjustBlock: Block = genesisBlock; +let accuDiff = 1; //const getLatestBlock = (): Block => blockchain[blockchain.length - 1]; const getLatestBlock = (): Block => { mode = getMode(); @@ -153,7 +150,7 @@ const getAdjustedDifficultyChain1 = (latestBlock: Block) => { const timeTaken: number = latestBlock.timestamp - prevAdjustmentBlock.timestamp; if (timeTaken < timeExpected / 2) { return prevAdjustmentBlock.difficulty + 1; - } else if (timeTaken > timeExpected * 2) { + } else if (timeTaken > timeExpected * 2) {//&& (prevAdjustmentBlock.difficulty > 0) return prevAdjustmentBlock.difficulty - 1; } else { return prevAdjustmentBlock.difficulty; @@ -161,6 +158,7 @@ const getAdjustedDifficultyChain1 = (latestBlock: Block) => { }; + /* const generateRawNextBlock = (blockData: Transaction[]) => { const previousBlock: Block = getLatestBlock(); @@ -179,9 +177,6 @@ const generateRawNextBlock = (blockData: Transaction[]) => { */ const generateRawNextBlock = (blockData: Transaction[]) => { const previousBlock: Block = getLatestBlock(); - //console.log('previousBlock: '+ JSON.stringify(previousBlock)); - //console.log('getLatestBlock: '+ JSON.stringify(getLatestBlock())); - //console.log('theLatestBlock: '+ JSON.stringify(theLatestBlock)); let difficulty: number; mode = getMode(); if(mode == 'local'){ @@ -198,9 +193,24 @@ const generateRawNextBlock = (blockData: Transaction[]) => { } else { return null; } +}; +const generateRawNextBlockInCloud = (blockData: Transaction[]) => { + const previousBlock: Block = getLatestBlock(); + let difficulty: number; + mode = getMode(); + if(mode == 'local'){ + difficulty = getDifficulty(getBlockchain()); + }else if(mode == 'dew'){ + difficulty = getDifficultyChain1(); + } + const nextIndex: number = previousBlock.index + 1; + const nextTimestamp: number = getCurrentTimestamp(); + const newBlock: Block = new Block(nextIndex, '', previousBlock.hash, nextTimestamp, blockData, difficulty, 0); + sendMiningRequest(newBlock); }; + // gets the unspent transaction outputs owned by the wallet /* const getMyUnspentTransactionOutputs = () => { @@ -224,6 +234,14 @@ const generateNextBlock = () => { return generateRawNextBlock(blockData); }; + +const mineInCloud = () => { + const coinbaseTx: Transaction = getCoinbaseTransaction(getPublicFromWallet()); + const blockData: Transaction[] = [coinbaseTx].concat(getTransactionPool()); + generateRawNextBlockInCloud(blockData); +}; + + /* const generatenextBlockWithTransaction = (receiverAddress: string, amount: number) => { if (!isValidAddress(receiverAddress)) { @@ -565,15 +583,7 @@ export { */ export { Block, getBlockchain, resetBlockchain, getAccounts, setAccounts, getLatestBlock, sendTransaction, - generateRawNextBlock, generateNextBlock, generatenextBlockWithTransaction, + generateRawNextBlock, generateNextBlock, mineInCloud, generatenextBlockWithTransaction, handleReceivedTransaction, validateAccount, getMyAccount, getAccountBalance, isValidBlockStructure, replaceChain, addBlockToChain, getCurrentTimestamp }; - -/* -getUnspentTxOuts = (): UnspentTxOut[] -getAccounts = (): Account[] - -getMyUnspentTransactionOutputs() -getMyAccount() -*/ diff --git a/dewcoin-dew/src/config.ts b/dewcoin-dew/src/config.ts new file mode 100644 index 0000000..4745e5d --- /dev/null +++ b/dewcoin-dew/src/config.ts @@ -0,0 +1,16 @@ +let mode: string = 'dew'; +//If mode is dew and configured properly, dew can cloud can be automatically lined together through sockets. +//If mode is local, it has no connection with the cloud; it will have the complete blockchain. +//modes can be switched through HTTP commands. + +let cloudAddress = '127.0.0.1:7001'; +//let cloudAddress = '192.168.1.114:7001'; + + + +const getMode = ():string => {return mode;}; +const setMode = (s: string) => {mode = s}; +const getCloud = (): string => {return cloudAddress}; +const setCloud = (address: string) => {cloudAddress = address}; + +export {setMode, getMode, getCloud, setCloud}; diff --git a/dew/src/main.ts b/dewcoin-dew/src/main.ts similarity index 96% rename from dew/src/main.ts rename to dewcoin-dew/src/main.ts index 4cc0821..0d91729 100644 --- a/dew/src/main.ts +++ b/dewcoin-dew/src/main.ts @@ -9,7 +9,7 @@ import { } from './blockchain'; */ import { - Block, generateNextBlock, generatenextBlockWithTransaction, generateRawNextBlock, getAccountBalance, + Block, generateNextBlock, mineInCloud, generatenextBlockWithTransaction, generateRawNextBlock, getAccountBalance, getBlockchain, getMyAccount, getAccounts, sendTransaction } from './blockchain'; @@ -141,6 +141,11 @@ const initHttpServer = (myHttpPort: number) => { } }); + app.post('/mineInCloud', (req, res) => { + mineInCloud(); + res.send(); + }); + app.get('/mybalance', (req, res) => { let acc: Account = findAccount(getPublicFromWallet(), getAccounts()); if(acc == undefined){ diff --git a/dew/src/p2p.ts b/dewcoin-dew/src/p2p.ts similarity index 97% rename from dew/src/p2p.ts rename to dewcoin-dew/src/p2p.ts index 2b4e2c5..b606a5f 100644 --- a/dew/src/p2p.ts +++ b/dewcoin-dew/src/p2p.ts @@ -16,6 +16,7 @@ import {getTransactionPool} from './transactionPool'; //dewcoin import {getMode, setMode, getCloud} from './config'; + let mode: string; let wsCloud: WebSocket; const getWsCloud = (): WebSocket => wsCloud; @@ -30,7 +31,8 @@ enum MessageType { RESPONSE_TRANSACTION_POOL = 4, QUERY_ACCOUNTS = 5, RESPONSE_ACCOUNTS = 6, - ALTERNATE_ADDRESS = 7 + ALTERNATE_ADDRESS = 7, + MINING_REQUEST = 8 } class Message { @@ -67,7 +69,7 @@ const getSockets = () => sockets; const initConnection = (ws: WebSocket) => { - console.log('AAAAAAAAAAinit: ' + ws.url); + console.log('A socket is added: ' + ws.url); sockets.push(ws); initMessageHandler(ws); initErrorHandler(ws); @@ -154,7 +156,7 @@ const initMessageHandler = (ws: WebSocket) => { console.log('could not parse received JSON message: ' + data); return; } - console.log('[Received message: %s', JSON.stringify(message)); + console.log('[Received message: %s', data); switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -215,7 +217,7 @@ const initCloudMessageHandler = (ws: WebSocket) => { console.log('could not parse received JSON message: ' + data); return; } - console.log('[Received cloud message: %s', JSON.stringify(message)); + console.log('[Received cloud message: %s', data); switch (message.type) { case MessageType.QUERY_LATEST: write(ws, responseLatestMsg()); @@ -327,6 +329,10 @@ const alternateAddressMsg = (address: string): Message => ({ 'data': address }); +const sendMiningRequest = (newBlock: Block) => ( + write(wsCloud, {'type': MessageType.MINING_REQUEST, 'data': JSON.stringify(newBlock)}) +); + const initErrorHandler = (ws: WebSocket) => { const closeConnection = (myWs: WebSocket) => { @@ -419,12 +425,9 @@ const setModeDew = () => { wsCloud = new WebSocket('ws://' + getCloud()); wsCloud.on('open', () => { console.log('connection with the cloud established'); - //sockets.push(wsCloud); initCloudMessageHandler(wsCloud); resetBlockchain(); - //write(wsCloud, {'type': 5, 'data': null}); - //broadcast(queryChainLengthMsg()); write(wsCloud, queryChainLengthMsg()); //query transactions pool only some time after chain query setTimeout(() => { @@ -444,4 +447,4 @@ const setModeDew = () => { //export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets}; export {connectToPeers, broadcastLatest, broadCastTransactionPool, initP2PServer, getSockets, -setModeLocal, setModeDew, fetchAccounts}; +setModeLocal, setModeDew, fetchAccounts, sendMiningRequest}; diff --git a/dew/src/transaction.ts b/dewcoin-dew/src/transaction.ts similarity index 96% rename from dew/src/transaction.ts rename to dewcoin-dew/src/transaction.ts index 1a41351..b1bdae3 100644 --- a/dew/src/transaction.ts +++ b/dewcoin-dew/src/transaction.ts @@ -96,6 +96,20 @@ class TxHistory { } } +const existAccount = (address: string, accounts: Account[]): boolean => { + //console.log('address: ' + address); + //console.log('accounts: '+ JSON.stringify(accounts)); + return _(accounts).map((acc: Account) => acc.address).includes(address); +} +const createAccount = (address: string, accounts: Account[]): boolean => { + let acc: Account = new Account(address); + accounts.push(acc); + return true; +} +const findAccount = (address: string, accounts: Account[]): Account => { + let account: Account = _.find(accounts, (acc: Account) => {return acc.address == address}); + return account; +} @@ -154,20 +168,6 @@ const validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTx return true; }; */ -const existAccount = (address: string, accounts: Account[]): boolean => { - //console.log('address: ' + address); - //console.log('accounts: '+ JSON.stringify(accounts)); - return _(accounts).map((acc: Account) => acc.address).includes(address); -} -const createAccount = (address: string, accounts: Account[]): boolean => { - let acc: Account = new Account(address); - accounts.push(acc); - return true; -} -const findAccount = (address: string, accounts: Account[]): Account => { - let account: Account = _.find(accounts, (acc: Account) => {return acc.address == address}); - return account; -} const validateTransaction = (transaction: Transaction, accounts: Account[]): boolean => { if (!isValidTransactionStructure(transaction)) { @@ -681,25 +681,3 @@ export { Account, findAccount, existAccount, createAccount, getCoinbaseTransaction, getPublicKey, hasDuplicates, Transaction }; -// -// -//Transaction -//UnspentTxOut => Account -//-TxIn -//-TxOut -// -//signTxIn = (transaction: Transaction, txInIndex: number, -// privateKey: string, aUnspentTxOuts: UnspentTxOut[]): string => { -//signTransaction = (transaction: Transaction, privateKey: string): string => { -// -//processTransactions = (aTransactions: Transaction[], aUnspentTxOuts: UnspentTxOut[], blockIndex: number) -//processTransactions = (aTransactions: Transaction[], accounts: Account[]) -// -//validateTransaction = (transaction: Transaction, aUnspentTxOuts: UnspentTxOut[]): boolean -//validateTransaction = (transaction: Transaction, accounts: Account[]): boolean -// -//getCoinbaseTransaction = (address: string, blockIndex: number): Transaction -//getCoinbaseTransaction = (miner: string): Transaction -// -//hasDuplicates = (txIns: TxIn[]): boolean -//hasDuplicates = (nums: number[]): boolean diff --git a/cloud/src/transactionPool.ts b/dewcoin-dew/src/transactionPool.ts similarity index 97% rename from cloud/src/transactionPool.ts rename to dewcoin-dew/src/transactionPool.ts index 66333df..4d20902 100644 --- a/cloud/src/transactionPool.ts +++ b/dewcoin-dew/src/transactionPool.ts @@ -131,8 +131,6 @@ const isValidTxForPool = (tx: Transaction, aTtransactionPool: Transaction[]): bo const isValidTxForPool = (tx: Transaction, aTransactionPool: Transaction[], accounts: Account[]): boolean => { let accSender: Account; -//console.log('isValidForPool: a Pool: ' + JSON.stringify(aTransactionPool)); -//console.log('tx: ' + JSON.stringify(tx)); for(let i=0; i < accounts.length; i++){ accounts[i].available = accounts[i].balance; } diff --git a/dew/src/util.ts b/dewcoin-dew/src/util.ts similarity index 100% rename from dew/src/util.ts rename to dewcoin-dew/src/util.ts diff --git a/dew/src/wallet.ts b/dewcoin-dew/src/wallet.ts similarity index 98% rename from dew/src/wallet.ts rename to dewcoin-dew/src/wallet.ts index 62d02ae..4760054 100644 --- a/dew/src/wallet.ts +++ b/dewcoin-dew/src/wallet.ts @@ -28,11 +28,11 @@ const generatePrivateKey = (): string => { }; const initWallet = () => { - console.log('an account was created.'); // let's not override existing private keys if (existsSync(privateKeyLocation)) { if (!existAccount(getPublicFromWallet(), getAccounts())) { createAccount(getPublicFromWallet(), getAccounts()); + console.log('an account was created.'); } return; } @@ -42,6 +42,7 @@ const initWallet = () => { console.log('new wallet with private key created to : %s', privateKeyLocation); if (!existAccount(getPublicFromWallet(), getAccounts())) { createAccount(getPublicFromWallet(), getAccounts()); + console.log('an account was created.'); } }; diff --git a/dew/tsconfig.json b/dewcoin-dew/tsconfig.json similarity index 100% rename from dew/tsconfig.json rename to dewcoin-dew/tsconfig.json diff --git a/dew/tslint.json b/dewcoin-dew/tslint.json similarity index 100% rename from dew/tslint.json rename to dewcoin-dew/tslint.json From 7d271552de349524ec7fa39c5c6afe261c68ac28 Mon Sep 17 00:00:00 2001 From: ywang Date: Mon, 13 Aug 2018 16:20:41 -0400 Subject: [PATCH 31/36] handshaking changed --- README.md | 2 ++ dewcoin-cloud/src/config.ts | 5 ++++- dewcoin-cloud/src/p2p.ts | 4 ++++ dewcoin-cloud/src/transaction.ts | 2 ++ dewcoin-dew/README.md | 4 ++-- dewcoin-dew/src/config.ts | 6 +++++- dewcoin-dew/src/p2p.ts | 23 +++++++++++++++++++---- dewcoin-dew/src/transaction.ts | 2 ++ 8 files changed, 40 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d4409f2..1a2c738 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ dewcoin-cloud/src/config.ts Detailed configuration guidelines can be found in these files. +Please notice: if only one machine is involved in testing, default config files are OK. If more than one machine is involved, config files should not use localhost or 127.0.0.1 at all. + ## Package Installation diff --git a/dewcoin-cloud/src/config.ts b/dewcoin-cloud/src/config.ts index 60e1bb0..35a4726 100644 --- a/dewcoin-cloud/src/config.ts +++ b/dewcoin-cloud/src/config.ts @@ -1,6 +1,9 @@ -let dewAddress = '127.0.0.1:6001'; +//let dewAddress = '127.0.0.1:6001'; +let dewAddress = '192.168.1.186:6001'; //let dewAddress = '192.168.1.114:6001'; //If dew address is not correct, it can also be set using HTTP command. See Readme. +//Please notice: if only one machine is involved in testing, default config files are OK. +//If more than one machine is involved, config files should not use localhost or 127.0.0.1 at all. diff --git a/dewcoin-cloud/src/p2p.ts b/dewcoin-cloud/src/p2p.ts index 13c1c8b..d842328 100644 --- a/dewcoin-cloud/src/p2p.ts +++ b/dewcoin-cloud/src/p2p.ts @@ -320,6 +320,10 @@ const initCloudMessageHandler = (ws: WebSocket) => { broadcastLatest(); } break; + case MessageType.ALTERNATE_ADDRESS: + console.log('Alternate address received: %s', message.data); + connectToPeers('ws://' + message.data); + break; } } catch (e) { console.log(e); diff --git a/dewcoin-cloud/src/transaction.ts b/dewcoin-cloud/src/transaction.ts index 1732b17..a050427 100644 --- a/dewcoin-cloud/src/transaction.ts +++ b/dewcoin-cloud/src/transaction.ts @@ -507,6 +507,7 @@ const updateAccounts = (aTransactions: Transaction[], accounts: Account[]): Acco thSender.timestamp = aTransactions[i].timestamp; thSender.prevBalance = accSender.balance; accSender.balance -= amt; + accSender.available = accSender.balance; thSender.afterBalance = accSender.balance; accSender.txHistory = _(accSender.txHistory).filter((th: TxHistory) => {return (th.timestamp < (now + ACCOUNT_PURGE_PERIOD))}).push(thSender).value(); //clean txHistory at the same time. @@ -524,6 +525,7 @@ const updateAccounts = (aTransactions: Transaction[], accounts: Account[]): Acco thReceiver.timestamp = aTransactions[i].timestamp; thReceiver.prevBalance = accReceiver.balance; accReceiver.balance += amt; + accReceiver.available = accReceiver.balance; thReceiver.afterBalance = accReceiver.balance; accReceiver.txHistory = _(accReceiver.txHistory).filter((th: TxHistory) => {return (th.timestamp < (now + ACCOUNT_PURGE_PERIOD))}).push(thReceiver).value(); //clean txHistory at the same time. diff --git a/dewcoin-dew/README.md b/dewcoin-dew/README.md index efab463..14687b0 100644 --- a/dewcoin-dew/README.md +++ b/dewcoin-dew/README.md @@ -137,8 +137,8 @@ curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6001"} ``` For Windows: ``` -curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:6002\"}" http://localhost:3001/addpeer -curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://192.168.1.186:6002\"}" http://localhost:3001/addpeer +curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://localhost:6001\"}" http://localhost:3001/addpeer +curl -H "Content-type:application/json" --data "{\"peer\" : \"ws://192.168.1.114:6001\"}" http://localhost:3001/addpeer ``` #### Stop the server diff --git a/dewcoin-dew/src/config.ts b/dewcoin-dew/src/config.ts index 4745e5d..7716c90 100644 --- a/dewcoin-dew/src/config.ts +++ b/dewcoin-dew/src/config.ts @@ -3,8 +3,12 @@ let mode: string = 'dew'; //If mode is local, it has no connection with the cloud; it will have the complete blockchain. //modes can be switched through HTTP commands. -let cloudAddress = '127.0.0.1:7001'; +//let cloudAddress = '127.0.0.1:7001'; +let cloudAddress = '192.168.1.186:7001'; //let cloudAddress = '192.168.1.114:7001'; +//If dew address is not correct, it can also be set using HTTP command. See Readme. +//Please notice: if only one machine is involved in testing, default config files are OK. +//If more than one machine is involved, config files should not use localhost or 127.0.0.1 at all. diff --git a/dewcoin-dew/src/p2p.ts b/dewcoin-dew/src/p2p.ts index b606a5f..d7761b6 100644 --- a/dewcoin-dew/src/p2p.ts +++ b/dewcoin-dew/src/p2p.ts @@ -73,9 +73,6 @@ const initConnection = (ws: WebSocket) => { sockets.push(ws); initMessageHandler(ws); initErrorHandler(ws); - if(getMode() == 'dew'){ - write(ws, alternateAddressMsg(getCloud())); - } write(ws, queryChainLengthMsg()); // query transactions pool only some time after chain query @@ -196,7 +193,11 @@ const initMessageHandler = (ws: WebSocket) => { break; case MessageType.ALTERNATE_ADDRESS: console.log('Alternate address received: %s', message.data); - connectToPeers('ws://' + message.data); + if(getMode() == 'dew'){ + write(wsCloud, message); + } else { + connectToPeers('ws://' + message.data); + } break; } } catch (e) { @@ -387,9 +388,23 @@ const broadcastLatest = (): void => { broadcast(responseLatestMsg()); }; +/* +const connectToPeers = (newPeer: string): void => { + const ws: WebSocket = new WebSocket(newPeer); + ws.on('open', () => { + initConnection(ws); + }); + ws.on('error', () => { + console.log('connection failed'); + }); +}; +*/ const connectToPeers = (newPeer: string): void => { const ws: WebSocket = new WebSocket(newPeer); ws.on('open', () => { + if(getMode() == 'dew'){ + write(ws, alternateAddressMsg(getCloud())); + } initConnection(ws); }); ws.on('error', () => { diff --git a/dewcoin-dew/src/transaction.ts b/dewcoin-dew/src/transaction.ts index b1bdae3..d286311 100644 --- a/dewcoin-dew/src/transaction.ts +++ b/dewcoin-dew/src/transaction.ts @@ -497,6 +497,7 @@ const updateAccounts = (aTransactions: Transaction[], accounts: Account[]): Acco thSender.timestamp = aTransactions[i].timestamp; thSender.prevBalance = accSender.balance; accSender.balance -= amt; + accSender.available = accSender.balance; thSender.afterBalance = accSender.balance; accSender.txHistory = _(accSender.txHistory).filter((th: TxHistory) => {return (th.timestamp < (now + ACCOUNT_PURGE_PERIOD))}).push(thSender).value(); //clean txHistory at the same time. @@ -514,6 +515,7 @@ const updateAccounts = (aTransactions: Transaction[], accounts: Account[]): Acco thReceiver.timestamp = aTransactions[i].timestamp; thReceiver.prevBalance = accReceiver.balance; accReceiver.balance += amt; + accReceiver.available = accReceiver.balance; thReceiver.afterBalance = accReceiver.balance; accReceiver.txHistory = _(accReceiver.txHistory).filter((th: TxHistory) => {return (th.timestamp < (now + ACCOUNT_PURGE_PERIOD))}).push(thReceiver).value(); //clean txHistory at the same time. From 174471a46ec56239708e3c772de3b68694168c49 Mon Sep 17 00:00:00 2001 From: yingweiwang Date: Mon, 13 Aug 2018 17:09:07 -0400 Subject: [PATCH 32/36] Update Readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1a2c738..57e9323 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Dewcoin is based on Naivecoin. The introduction of Naivecoin can be found in: A ## Package Placement -Dewcoin has two components: the cloud package and the dew package. Ideally, the cloud package should be installed in a computer that is running all the time and has a fixed IP address so that it can be accessed easily. The dew package can be installed in a locally computer. For testing purposes, the cloud package and the dew package can be put in the same computer. +Dewcoin has two components: dewcoin-cloud package and the dewcoin-dew package. Ideally, dewcoin-cloud package should be placed in a computer that is running all the time and has a fixed IP address so that it can be accessed easily; dewcoin-dew package can be placed in a local computer. For testing purposes, dewcoin-cloud package and dewcoin-dew package can be placed in the same computer. ## Package Configuraton @@ -24,7 +24,7 @@ Please notice: if only one machine is involved in testing, default config files ## Package Installation -Both packages should be installed in the Node.js environment. +Both packages should be installed in Node.js environment. Installation command: ``` @@ -36,7 +36,7 @@ npm start ``` ## Dewcoin Operation -Dewcoin system can be operated through an API composed of a group of HTTP commands. These commands can be issued through browsers, designed web forms, HTTP clients such as curl. +Dewcoin system can be operated through an API composed of a group of HTTP commands. These commands can be issued through browsers, designed web forms, or HTTP clients such as curl. We use curl to describe the API, but it does not mean curl is the only way to operate Dewcoin. From 4c8107eba0cc220d47f8464acac724220106e8c2 Mon Sep 17 00:00:00 2001 From: ywang Date: Mon, 13 Aug 2018 18:29:55 -0400 Subject: [PATCH 33/36] Improved mode switching --- dewcoin-dew/src/p2p.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dewcoin-dew/src/p2p.ts b/dewcoin-dew/src/p2p.ts index d7761b6..95a6e8e 100644 --- a/dewcoin-dew/src/p2p.ts +++ b/dewcoin-dew/src/p2p.ts @@ -421,7 +421,7 @@ const setModeLocal = () => { setMode('local'); mode = getMode(); console.log('running on ' + mode + ' mode.'); - + connectToPeers('ws://' + getCloud()); if (typeof wsCloud !== "undefined") { wsCloud.close(); }; From 2d7b9bb59225534d5aec20feafb977f8d26b49f5 Mon Sep 17 00:00:00 2001 From: ywang Date: Mon, 13 Aug 2018 20:27:53 -0400 Subject: [PATCH 34/36] Rename --- .gitignore | 16 ++++++++-------- README.md | 18 +++++++++--------- {dewcoin-cloud => dewblock-cloud}/License.txt | 0 {dewcoin-cloud => dewblock-cloud}/README.md | 4 ++-- .../node/wallet/.gitignore | 0 .../package-lock.json | 0 {dewcoin-cloud => dewblock-cloud}/package.json | 0 .../src/blockchain.ts | 0 .../src/config.ts | 0 {dewcoin-cloud => dewblock-cloud}/src/main.ts | 0 {dewcoin-cloud => dewblock-cloud}/src/p2p.ts | 0 .../src/transaction.ts | 0 .../src/transactionPool.ts | 0 {dewcoin-cloud => dewblock-cloud}/src/util.ts | 0 .../src/wallet.ts | 0 .../tsconfig.json | 0 {dewcoin-cloud => dewblock-cloud}/tslint.json | 0 {dewcoin-dew => dewblock-dew}/License.txt | 0 {dewcoin-dew => dewblock-dew}/README.md | 6 +++--- .../node/wallet/.gitignore | 0 .../package-lock.json | 0 {dewcoin-dew => dewblock-dew}/package.json | 0 .../src/blockchain.ts | 0 {dewcoin-dew => dewblock-dew}/src/config.ts | 0 {dewcoin-dew => dewblock-dew}/src/main.ts | 0 {dewcoin-dew => dewblock-dew}/src/p2p.ts | 0 .../src/transaction.ts | 0 .../src/transactionPool.ts | 0 {dewcoin-dew => dewblock-dew}/src/util.ts | 0 {dewcoin-dew => dewblock-dew}/src/wallet.ts | 0 {dewcoin-dew => dewblock-dew}/tsconfig.json | 0 {dewcoin-dew => dewblock-dew}/tslint.json | 0 32 files changed, 22 insertions(+), 22 deletions(-) rename {dewcoin-cloud => dewblock-cloud}/License.txt (100%) rename {dewcoin-cloud => dewblock-cloud}/README.md (79%) rename {dewcoin-cloud => dewblock-cloud}/node/wallet/.gitignore (100%) rename {dewcoin-cloud => dewblock-cloud}/package-lock.json (100%) rename {dewcoin-cloud => dewblock-cloud}/package.json (100%) rename {dewcoin-cloud => dewblock-cloud}/src/blockchain.ts (100%) rename {dewcoin-cloud => dewblock-cloud}/src/config.ts (100%) rename {dewcoin-cloud => dewblock-cloud}/src/main.ts (100%) rename {dewcoin-cloud => dewblock-cloud}/src/p2p.ts (100%) rename {dewcoin-cloud => dewblock-cloud}/src/transaction.ts (100%) rename {dewcoin-cloud => dewblock-cloud}/src/transactionPool.ts (100%) rename {dewcoin-cloud => dewblock-cloud}/src/util.ts (100%) rename {dewcoin-cloud => dewblock-cloud}/src/wallet.ts (100%) rename {dewcoin-cloud => dewblock-cloud}/tsconfig.json (100%) rename {dewcoin-cloud => dewblock-cloud}/tslint.json (100%) rename {dewcoin-dew => dewblock-dew}/License.txt (100%) rename {dewcoin-dew => dewblock-dew}/README.md (93%) rename {dewcoin-dew => dewblock-dew}/node/wallet/.gitignore (100%) rename {dewcoin-dew => dewblock-dew}/package-lock.json (100%) rename {dewcoin-dew => dewblock-dew}/package.json (100%) rename {dewcoin-dew => dewblock-dew}/src/blockchain.ts (100%) rename {dewcoin-dew => dewblock-dew}/src/config.ts (100%) rename {dewcoin-dew => dewblock-dew}/src/main.ts (100%) rename {dewcoin-dew => dewblock-dew}/src/p2p.ts (100%) rename {dewcoin-dew => dewblock-dew}/src/transaction.ts (100%) rename {dewcoin-dew => dewblock-dew}/src/transactionPool.ts (100%) rename {dewcoin-dew => dewblock-dew}/src/util.ts (100%) rename {dewcoin-dew => dewblock-dew}/src/wallet.ts (100%) rename {dewcoin-dew => dewblock-dew}/tsconfig.json (100%) rename {dewcoin-dew => dewblock-dew}/tslint.json (100%) diff --git a/.gitignore b/.gitignore index e012045..6f781a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ -dewcoin-cloud/node_modules -dewcoin-cloud/npm-debug.log -dewcoin-cloud/src/*.js -dewcoin-cloud/src/*.map -dewcoin-dew/node_modules -dewcoin-dew/npm-debug.log -dewcoin-dew/src/*.js -dewcoin-dew/src/*.map +dewblock-cloud/node_modules +dewblock-cloud/npm-debug.log +dewblock-cloud/src/*.js +dewblock-cloud/src/*.map +dewblock-dew/node_modules +dewblock-dew/npm-debug.log +dewblock-dew/src/*.js +dewblock-dew/src/*.map diff --git a/README.md b/README.md index 6d639b7..3e501c3 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ -# Dewcoin +# Dewblock -Dewcoin is a blockchain cryptocurrency system that is based on dew computing principles. The code is pretty detailed but still not detailed enough for immediate production operation. It is basically a Proof of Concept system. The mechanism of dewcoin will be introduced separately. Some information about dew computing can be found in: http://www.dewcomputing.org/ +Dewblock is a blockchain cryptocurrency system that is based on dew computing principles. The code is pretty detailed but still not detailed enough for immediate production operation. It is basically a Proof of Concept system. The mechanism of dewblock will be introduced separately. Some information about dew computing can be found in: http://www.dewcomputing.org/ -Dewcoin is based on Naivecoin. The introduction of Naivecoin can be found in: A tutorial for building a cryptocurrency https://lhartikk.github.io/ +Dewblock is based on Naivecoin. The introduction of Naivecoin can be found in: A tutorial for building a cryptocurrency https://lhartikk.github.io/ ## Package Placement -Dewcoin has two components: dewcoin-cloud package and the dewcoin-dew package. Ideally, dewcoin-cloud package should be placed in a computer that is running all the time and has a fixed IP address so that it can be accessed easily; dewcoin-dew package can be placed in a local computer. For testing purposes, dewcoin-cloud package and dewcoin-dew package can be placed in the same computer. +Dewblock has two components: dewblock-cloud package and the dewblock-dew package. Ideally, dewblock-cloud package should be placed in a computer that is running all the time and has a fixed IP address so that it can be accessed easily; dewblock-dew package can be placed in a local computer. For testing purposes, dewblock-cloud package and dewblock-dew package can be placed in the same computer. ## Package Configuraton Configuraton files: -dewcoin-dew/src/config.ts -dewcoin-cloud/src/config.ts +dewblock-dew/src/config.ts +dewblock-cloud/src/config.ts Detailed configuration guidelines can be found in these files. @@ -32,9 +32,9 @@ Running command: ``` npm start ``` -## Dewcoin Operation +## Dewblock Operation -Dewcoin system can be operated through an API composed of a group of HTTP commands. These commands can be issued through browsers, designed web forms, or HTTP clients such as curl. +Dewblock system can be operated through an API composed of a group of HTTP commands. These commands can be issued through browsers, designed web forms, or HTTP clients such as curl. -We use curl to describe the API, but it does not mean curl is the only way to operate Dewcoin. +We use curl to describe the API, but it does not mean curl is the only way to operate Dewblock. diff --git a/dewcoin-cloud/License.txt b/dewblock-cloud/License.txt similarity index 100% rename from dewcoin-cloud/License.txt rename to dewblock-cloud/License.txt diff --git a/dewcoin-cloud/README.md b/dewblock-cloud/README.md similarity index 79% rename from dewcoin-cloud/README.md rename to dewblock-cloud/README.md index 735cb80..df9a544 100644 --- a/dewcoin-cloud/README.md +++ b/dewblock-cloud/README.md @@ -1,6 +1,6 @@ -# Dewcoin-cloud Package +# Dewblock-cloud Package -This package has no modes. Dewcoin-cloud behaves like Naivecoin. Especially, it provides the whole blockchain to other nodes to fulfil the responsibility a full blockchain node. It also uses the complete blochchain to garantee the accuracy of all the transactions. +This package has no modes. Dewblock-cloud behaves like Naivecoin. Especially, it provides the whole blockchain to other nodes to fulfil the responsibility a full blockchain node. It also uses the complete blochchain to garantee the accuracy of all the transactions. #### Installation and System Start diff --git a/dewcoin-cloud/node/wallet/.gitignore b/dewblock-cloud/node/wallet/.gitignore similarity index 100% rename from dewcoin-cloud/node/wallet/.gitignore rename to dewblock-cloud/node/wallet/.gitignore diff --git a/dewcoin-cloud/package-lock.json b/dewblock-cloud/package-lock.json similarity index 100% rename from dewcoin-cloud/package-lock.json rename to dewblock-cloud/package-lock.json diff --git a/dewcoin-cloud/package.json b/dewblock-cloud/package.json similarity index 100% rename from dewcoin-cloud/package.json rename to dewblock-cloud/package.json diff --git a/dewcoin-cloud/src/blockchain.ts b/dewblock-cloud/src/blockchain.ts similarity index 100% rename from dewcoin-cloud/src/blockchain.ts rename to dewblock-cloud/src/blockchain.ts diff --git a/dewcoin-cloud/src/config.ts b/dewblock-cloud/src/config.ts similarity index 100% rename from dewcoin-cloud/src/config.ts rename to dewblock-cloud/src/config.ts diff --git a/dewcoin-cloud/src/main.ts b/dewblock-cloud/src/main.ts similarity index 100% rename from dewcoin-cloud/src/main.ts rename to dewblock-cloud/src/main.ts diff --git a/dewcoin-cloud/src/p2p.ts b/dewblock-cloud/src/p2p.ts similarity index 100% rename from dewcoin-cloud/src/p2p.ts rename to dewblock-cloud/src/p2p.ts diff --git a/dewcoin-cloud/src/transaction.ts b/dewblock-cloud/src/transaction.ts similarity index 100% rename from dewcoin-cloud/src/transaction.ts rename to dewblock-cloud/src/transaction.ts diff --git a/dewcoin-cloud/src/transactionPool.ts b/dewblock-cloud/src/transactionPool.ts similarity index 100% rename from dewcoin-cloud/src/transactionPool.ts rename to dewblock-cloud/src/transactionPool.ts diff --git a/dewcoin-cloud/src/util.ts b/dewblock-cloud/src/util.ts similarity index 100% rename from dewcoin-cloud/src/util.ts rename to dewblock-cloud/src/util.ts diff --git a/dewcoin-cloud/src/wallet.ts b/dewblock-cloud/src/wallet.ts similarity index 100% rename from dewcoin-cloud/src/wallet.ts rename to dewblock-cloud/src/wallet.ts diff --git a/dewcoin-cloud/tsconfig.json b/dewblock-cloud/tsconfig.json similarity index 100% rename from dewcoin-cloud/tsconfig.json rename to dewblock-cloud/tsconfig.json diff --git a/dewcoin-cloud/tslint.json b/dewblock-cloud/tslint.json similarity index 100% rename from dewcoin-cloud/tslint.json rename to dewblock-cloud/tslint.json diff --git a/dewcoin-dew/License.txt b/dewblock-dew/License.txt similarity index 100% rename from dewcoin-dew/License.txt rename to dewblock-dew/License.txt diff --git a/dewcoin-dew/README.md b/dewblock-dew/README.md similarity index 93% rename from dewcoin-dew/README.md rename to dewblock-dew/README.md index 14687b0..4f54fac 100644 --- a/dewcoin-dew/README.md +++ b/dewblock-dew/README.md @@ -1,10 +1,10 @@ -# Dewcoin-dew Package +# Dewblock-dew Package This package has two modes: local mode and dew mode. -In local mode, dewcoin behaves like Naivecoin. +In local mode, dewblock behaves like Naivecoin. -In dew mode, dewcoin behaves like Naivecoin without the blockchain. Thus, dewcoin-dew does not need huge memory like a normal blockchain system. +In dew mode, dewblock behaves like Naivecoin without the blockchain. Thus, dewblock-dew does not need huge memory like a normal blockchain system. #### Installation and System Start diff --git a/dewcoin-dew/node/wallet/.gitignore b/dewblock-dew/node/wallet/.gitignore similarity index 100% rename from dewcoin-dew/node/wallet/.gitignore rename to dewblock-dew/node/wallet/.gitignore diff --git a/dewcoin-dew/package-lock.json b/dewblock-dew/package-lock.json similarity index 100% rename from dewcoin-dew/package-lock.json rename to dewblock-dew/package-lock.json diff --git a/dewcoin-dew/package.json b/dewblock-dew/package.json similarity index 100% rename from dewcoin-dew/package.json rename to dewblock-dew/package.json diff --git a/dewcoin-dew/src/blockchain.ts b/dewblock-dew/src/blockchain.ts similarity index 100% rename from dewcoin-dew/src/blockchain.ts rename to dewblock-dew/src/blockchain.ts diff --git a/dewcoin-dew/src/config.ts b/dewblock-dew/src/config.ts similarity index 100% rename from dewcoin-dew/src/config.ts rename to dewblock-dew/src/config.ts diff --git a/dewcoin-dew/src/main.ts b/dewblock-dew/src/main.ts similarity index 100% rename from dewcoin-dew/src/main.ts rename to dewblock-dew/src/main.ts diff --git a/dewcoin-dew/src/p2p.ts b/dewblock-dew/src/p2p.ts similarity index 100% rename from dewcoin-dew/src/p2p.ts rename to dewblock-dew/src/p2p.ts diff --git a/dewcoin-dew/src/transaction.ts b/dewblock-dew/src/transaction.ts similarity index 100% rename from dewcoin-dew/src/transaction.ts rename to dewblock-dew/src/transaction.ts diff --git a/dewcoin-dew/src/transactionPool.ts b/dewblock-dew/src/transactionPool.ts similarity index 100% rename from dewcoin-dew/src/transactionPool.ts rename to dewblock-dew/src/transactionPool.ts diff --git a/dewcoin-dew/src/util.ts b/dewblock-dew/src/util.ts similarity index 100% rename from dewcoin-dew/src/util.ts rename to dewblock-dew/src/util.ts diff --git a/dewcoin-dew/src/wallet.ts b/dewblock-dew/src/wallet.ts similarity index 100% rename from dewcoin-dew/src/wallet.ts rename to dewblock-dew/src/wallet.ts diff --git a/dewcoin-dew/tsconfig.json b/dewblock-dew/tsconfig.json similarity index 100% rename from dewcoin-dew/tsconfig.json rename to dewblock-dew/tsconfig.json diff --git a/dewcoin-dew/tslint.json b/dewblock-dew/tslint.json similarity index 100% rename from dewcoin-dew/tslint.json rename to dewblock-dew/tslint.json From 28afbccb2e65200a9e124d9b9e7a542014c434e6 Mon Sep 17 00:00:00 2001 From: ywang Date: Mon, 13 Aug 2018 20:31:20 -0400 Subject: [PATCH 35/36] config files --- dewblock-cloud/src/config.ts | 4 ++-- dewblock-dew/src/config.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dewblock-cloud/src/config.ts b/dewblock-cloud/src/config.ts index 35a4726..4fa71da 100644 --- a/dewblock-cloud/src/config.ts +++ b/dewblock-cloud/src/config.ts @@ -1,5 +1,5 @@ -//let dewAddress = '127.0.0.1:6001'; -let dewAddress = '192.168.1.186:6001'; +let dewAddress = '127.0.0.1:6001'; +//let dewAddress = '192.168.1.186:6001'; //let dewAddress = '192.168.1.114:6001'; //If dew address is not correct, it can also be set using HTTP command. See Readme. //Please notice: if only one machine is involved in testing, default config files are OK. diff --git a/dewblock-dew/src/config.ts b/dewblock-dew/src/config.ts index 7716c90..2d204f5 100644 --- a/dewblock-dew/src/config.ts +++ b/dewblock-dew/src/config.ts @@ -3,8 +3,8 @@ let mode: string = 'dew'; //If mode is local, it has no connection with the cloud; it will have the complete blockchain. //modes can be switched through HTTP commands. -//let cloudAddress = '127.0.0.1:7001'; -let cloudAddress = '192.168.1.186:7001'; +let cloudAddress = '127.0.0.1:7001'; +//let cloudAddress = '192.168.1.186:7001'; //let cloudAddress = '192.168.1.114:7001'; //If dew address is not correct, it can also be set using HTTP command. See Readme. //Please notice: if only one machine is involved in testing, default config files are OK. From fd6dc57822f1a95ff5cb354f142b28de6067324d Mon Sep 17 00:00:00 2001 From: Yingwei Wang Date: Sat, 8 Sep 2018 07:55:57 -0300 Subject: [PATCH 36/36] Change package names --- .gitignore | 16 ++++++++-------- .../License.txt | 0 .../README.md | 12 +++++------- .../node/wallet/.gitignore | 0 .../package-lock.json | 0 .../package.json | 0 .../src/blockchain.ts | 0 .../src/config.ts | 0 .../src/main.ts | 0 .../src/p2p.ts | 0 .../src/transaction.ts | 0 .../src/transactionPool.ts | 0 .../src/util.ts | 0 .../src/wallet.ts | 0 .../tsconfig.json | 0 .../tslint.json | 0 .../License.txt | 0 {dewblock-dew => Dewblock-dew-server}/README.md | 12 ++++++------ .../node/wallet/.gitignore | 0 .../package-lock.json | 0 .../package.json | 0 .../src/blockchain.ts | 0 .../src/config.ts | 0 .../src/main.ts | 0 {dewblock-dew => Dewblock-dew-server}/src/p2p.ts | 0 .../src/transaction.ts | 0 .../src/transactionPool.ts | 0 .../src/util.ts | 0 .../src/wallet.ts | 0 .../tsconfig.json | 0 .../tslint.json | 0 README.md | 9 ++++----- 32 files changed, 23 insertions(+), 26 deletions(-) rename {dewblock-cloud => Dewblock-cloud-server}/License.txt (100%) rename {dewblock-cloud => Dewblock-cloud-server}/README.md (66%) rename {dewblock-cloud => Dewblock-cloud-server}/node/wallet/.gitignore (100%) rename {dewblock-cloud => Dewblock-cloud-server}/package-lock.json (100%) rename {dewblock-cloud => Dewblock-cloud-server}/package.json (100%) rename {dewblock-cloud => Dewblock-cloud-server}/src/blockchain.ts (100%) rename {dewblock-cloud => Dewblock-cloud-server}/src/config.ts (100%) rename {dewblock-cloud => Dewblock-cloud-server}/src/main.ts (100%) rename {dewblock-cloud => Dewblock-cloud-server}/src/p2p.ts (100%) rename {dewblock-cloud => Dewblock-cloud-server}/src/transaction.ts (100%) rename {dewblock-cloud => Dewblock-cloud-server}/src/transactionPool.ts (100%) rename {dewblock-cloud => Dewblock-cloud-server}/src/util.ts (100%) rename {dewblock-cloud => Dewblock-cloud-server}/src/wallet.ts (100%) rename {dewblock-cloud => Dewblock-cloud-server}/tsconfig.json (100%) rename {dewblock-cloud => Dewblock-cloud-server}/tslint.json (100%) rename {dewblock-dew => Dewblock-dew-server}/License.txt (100%) rename {dewblock-dew => Dewblock-dew-server}/README.md (83%) rename {dewblock-dew => Dewblock-dew-server}/node/wallet/.gitignore (100%) rename {dewblock-dew => Dewblock-dew-server}/package-lock.json (100%) rename {dewblock-dew => Dewblock-dew-server}/package.json (100%) rename {dewblock-dew => Dewblock-dew-server}/src/blockchain.ts (100%) rename {dewblock-dew => Dewblock-dew-server}/src/config.ts (100%) rename {dewblock-dew => Dewblock-dew-server}/src/main.ts (100%) rename {dewblock-dew => Dewblock-dew-server}/src/p2p.ts (100%) rename {dewblock-dew => Dewblock-dew-server}/src/transaction.ts (100%) rename {dewblock-dew => Dewblock-dew-server}/src/transactionPool.ts (100%) rename {dewblock-dew => Dewblock-dew-server}/src/util.ts (100%) rename {dewblock-dew => Dewblock-dew-server}/src/wallet.ts (100%) rename {dewblock-dew => Dewblock-dew-server}/tsconfig.json (100%) rename {dewblock-dew => Dewblock-dew-server}/tslint.json (100%) diff --git a/.gitignore b/.gitignore index 6f781a8..30bd7e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ -dewblock-cloud/node_modules -dewblock-cloud/npm-debug.log -dewblock-cloud/src/*.js -dewblock-cloud/src/*.map -dewblock-dew/node_modules -dewblock-dew/npm-debug.log -dewblock-dew/src/*.js -dewblock-dew/src/*.map +Dewblock-cloud-server/node_modules +Dewblock-cloud-server/npm-debug.log +Dewblock-cloud-server/src/*.js +Dewblock-cloud-server/src/*.map +Dewblock-dew-server/node_modules +Dewblock-dew-server/npm-debug.log +Dewblock-dew-server/src/*.js +Dewblock-dew-server/src/*.map diff --git a/dewblock-cloud/License.txt b/Dewblock-cloud-server/License.txt similarity index 100% rename from dewblock-cloud/License.txt rename to Dewblock-cloud-server/License.txt diff --git a/dewblock-cloud/README.md b/Dewblock-cloud-server/README.md similarity index 66% rename from dewblock-cloud/README.md rename to Dewblock-cloud-server/README.md index df9a544..9052e1f 100644 --- a/dewblock-cloud/README.md +++ b/Dewblock-cloud-server/README.md @@ -1,6 +1,6 @@ -# Dewblock-cloud Package +# Dewblock-cloud-server Package -This package has no modes. Dewblock-cloud behaves like Naivecoin. Especially, it provides the whole blockchain to other nodes to fulfil the responsibility a full blockchain node. It also uses the complete blochchain to garantee the accuracy of all the transactions. +This package has no modes. Dewblock-cloud-server behaves like Naivecoin. Especially, it provides the whole blockchain to other nodes to fulfil the responsibility a full blockchain node. It also uses the complete blochchain to garantee the accuracy of all the transactions. #### Installation and System Start @@ -10,21 +10,19 @@ npm install npm start ``` -##### Set Dew Address +##### Set Dew Server Address ``` -curl -H "Content-type:application/json" --data '{"address" : "192.168.1.186"}' http://localhost:3001/SetDewAddress +curl -H "Content-type:application/json" --data '{"address" : "192.168.1.186"}' http://localhost:3001/setdewaddress ``` For Windows: ``` -curl -H "Content-type:application/json" --data "{\"address\" : \"192.168.1.186\"}" http://localhost:3001/SetDewAddress +curl -H "Content-type:application/json" --data "{\"address\" : \"192.168.1.186\"}" http://localhost:3001/setdewaddress ``` ##### Query the whole blockchain ``` curl http://localhost:3001/blocks ``` -In dew mode, the blockchain has only the genesis block. - ##### Query all accounts diff --git a/dewblock-cloud/node/wallet/.gitignore b/Dewblock-cloud-server/node/wallet/.gitignore similarity index 100% rename from dewblock-cloud/node/wallet/.gitignore rename to Dewblock-cloud-server/node/wallet/.gitignore diff --git a/dewblock-cloud/package-lock.json b/Dewblock-cloud-server/package-lock.json similarity index 100% rename from dewblock-cloud/package-lock.json rename to Dewblock-cloud-server/package-lock.json diff --git a/dewblock-cloud/package.json b/Dewblock-cloud-server/package.json similarity index 100% rename from dewblock-cloud/package.json rename to Dewblock-cloud-server/package.json diff --git a/dewblock-cloud/src/blockchain.ts b/Dewblock-cloud-server/src/blockchain.ts similarity index 100% rename from dewblock-cloud/src/blockchain.ts rename to Dewblock-cloud-server/src/blockchain.ts diff --git a/dewblock-cloud/src/config.ts b/Dewblock-cloud-server/src/config.ts similarity index 100% rename from dewblock-cloud/src/config.ts rename to Dewblock-cloud-server/src/config.ts diff --git a/dewblock-cloud/src/main.ts b/Dewblock-cloud-server/src/main.ts similarity index 100% rename from dewblock-cloud/src/main.ts rename to Dewblock-cloud-server/src/main.ts diff --git a/dewblock-cloud/src/p2p.ts b/Dewblock-cloud-server/src/p2p.ts similarity index 100% rename from dewblock-cloud/src/p2p.ts rename to Dewblock-cloud-server/src/p2p.ts diff --git a/dewblock-cloud/src/transaction.ts b/Dewblock-cloud-server/src/transaction.ts similarity index 100% rename from dewblock-cloud/src/transaction.ts rename to Dewblock-cloud-server/src/transaction.ts diff --git a/dewblock-cloud/src/transactionPool.ts b/Dewblock-cloud-server/src/transactionPool.ts similarity index 100% rename from dewblock-cloud/src/transactionPool.ts rename to Dewblock-cloud-server/src/transactionPool.ts diff --git a/dewblock-cloud/src/util.ts b/Dewblock-cloud-server/src/util.ts similarity index 100% rename from dewblock-cloud/src/util.ts rename to Dewblock-cloud-server/src/util.ts diff --git a/dewblock-cloud/src/wallet.ts b/Dewblock-cloud-server/src/wallet.ts similarity index 100% rename from dewblock-cloud/src/wallet.ts rename to Dewblock-cloud-server/src/wallet.ts diff --git a/dewblock-cloud/tsconfig.json b/Dewblock-cloud-server/tsconfig.json similarity index 100% rename from dewblock-cloud/tsconfig.json rename to Dewblock-cloud-server/tsconfig.json diff --git a/dewblock-cloud/tslint.json b/Dewblock-cloud-server/tslint.json similarity index 100% rename from dewblock-cloud/tslint.json rename to Dewblock-cloud-server/tslint.json diff --git a/dewblock-dew/License.txt b/Dewblock-dew-server/License.txt similarity index 100% rename from dewblock-dew/License.txt rename to Dewblock-dew-server/License.txt diff --git a/dewblock-dew/README.md b/Dewblock-dew-server/README.md similarity index 83% rename from dewblock-dew/README.md rename to Dewblock-dew-server/README.md index 4f54fac..4d50331 100644 --- a/dewblock-dew/README.md +++ b/Dewblock-dew-server/README.md @@ -1,10 +1,10 @@ -# Dewblock-dew Package +# Dewblock-dew-server Package -This package has two modes: local mode and dew mode. +This package has two modes: local mode and cloud-dew mode (for short from now on we refer it as dew mode). -In local mode, dewblock behaves like Naivecoin. +In local mode, Dewblock behaves like Naivecoin. -In dew mode, dewblock behaves like Naivecoin without the blockchain. Thus, dewblock-dew does not need huge memory like a normal blockchain system. +In dew mode, Dewblock behaves like Naivecoin without the blockchain. Thus, Dewblock-dew-server does not need huge memory like a normal blockchain system. #### Installation and System Start @@ -26,9 +26,9 @@ curl http://localhost:3001/setmodedew ##### Fetch Accounts -Send dew accounts to the cloud for verification. If consistent, nothing the cloud will do; if not consistent, the cloud accounts will be fetched to the dew and replace the dew accounts. +Send dew server accounts to the cloud server for verification. If consistent, the cloud server will do nothing; if not consistent, the cloud server accounts will be fetched to the dew server and replace the dew server accounts. ``` -curl http://localhost:3001/fetchAccounts +curl http://localhost:3001/fetchaccounts ``` diff --git a/dewblock-dew/node/wallet/.gitignore b/Dewblock-dew-server/node/wallet/.gitignore similarity index 100% rename from dewblock-dew/node/wallet/.gitignore rename to Dewblock-dew-server/node/wallet/.gitignore diff --git a/dewblock-dew/package-lock.json b/Dewblock-dew-server/package-lock.json similarity index 100% rename from dewblock-dew/package-lock.json rename to Dewblock-dew-server/package-lock.json diff --git a/dewblock-dew/package.json b/Dewblock-dew-server/package.json similarity index 100% rename from dewblock-dew/package.json rename to Dewblock-dew-server/package.json diff --git a/dewblock-dew/src/blockchain.ts b/Dewblock-dew-server/src/blockchain.ts similarity index 100% rename from dewblock-dew/src/blockchain.ts rename to Dewblock-dew-server/src/blockchain.ts diff --git a/dewblock-dew/src/config.ts b/Dewblock-dew-server/src/config.ts similarity index 100% rename from dewblock-dew/src/config.ts rename to Dewblock-dew-server/src/config.ts diff --git a/dewblock-dew/src/main.ts b/Dewblock-dew-server/src/main.ts similarity index 100% rename from dewblock-dew/src/main.ts rename to Dewblock-dew-server/src/main.ts diff --git a/dewblock-dew/src/p2p.ts b/Dewblock-dew-server/src/p2p.ts similarity index 100% rename from dewblock-dew/src/p2p.ts rename to Dewblock-dew-server/src/p2p.ts diff --git a/dewblock-dew/src/transaction.ts b/Dewblock-dew-server/src/transaction.ts similarity index 100% rename from dewblock-dew/src/transaction.ts rename to Dewblock-dew-server/src/transaction.ts diff --git a/dewblock-dew/src/transactionPool.ts b/Dewblock-dew-server/src/transactionPool.ts similarity index 100% rename from dewblock-dew/src/transactionPool.ts rename to Dewblock-dew-server/src/transactionPool.ts diff --git a/dewblock-dew/src/util.ts b/Dewblock-dew-server/src/util.ts similarity index 100% rename from dewblock-dew/src/util.ts rename to Dewblock-dew-server/src/util.ts diff --git a/dewblock-dew/src/wallet.ts b/Dewblock-dew-server/src/wallet.ts similarity index 100% rename from dewblock-dew/src/wallet.ts rename to Dewblock-dew-server/src/wallet.ts diff --git a/dewblock-dew/tsconfig.json b/Dewblock-dew-server/tsconfig.json similarity index 100% rename from dewblock-dew/tsconfig.json rename to Dewblock-dew-server/tsconfig.json diff --git a/dewblock-dew/tslint.json b/Dewblock-dew-server/tslint.json similarity index 100% rename from dewblock-dew/tslint.json rename to Dewblock-dew-server/tslint.json diff --git a/README.md b/README.md index 3e501c3..f28ba73 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,17 @@ Dewblock is based on Naivecoin. The introduction of Naivecoin can be found in: A ## Package Placement -Dewblock has two components: dewblock-cloud package and the dewblock-dew package. Ideally, dewblock-cloud package should be placed in a computer that is running all the time and has a fixed IP address so that it can be accessed easily; dewblock-dew package can be placed in a local computer. For testing purposes, dewblock-cloud package and dewblock-dew package can be placed in the same computer. +Dewblock has two components: Dewblock-cloud-server package and Dewblock-dew-server package. Ideally, Dewblock-cloud-server package should be deployed in a cloud service or a computer that is running all the time and has a fixed IP address so that it can be accessed easily; Dewblock-dew-server package can be deployed in a local computer, such as a desktop/laptop computer or a mobile device. Dewblock-cloud-server package and Dewblock-dew-server package could be stay in the same computer for testing. Different nodes cannot be deployed into the same computer because each node needs to have its unique IP address. ## Package Configuraton Configuraton files: -dewblock-dew/src/config.ts -dewblock-cloud/src/config.ts +Dewblock-dew-server/src/config.ts +Dewblock-cloud-server/src/config.ts Detailed configuration guidelines can be found in these files. -Please notice: if only one machine is involved in testing, default config files are OK. If more than one machine is involved, config files should not use localhost or 127.0.0.1 at all. +Please notice: If more than one machine is involved, config files should use actual IP addresses, not use localhost or 127.0.0.1 at all. ## Package Installation @@ -37,4 +37,3 @@ npm start Dewblock system can be operated through an API composed of a group of HTTP commands. These commands can be issued through browsers, designed web forms, or HTTP clients such as curl. We use curl to describe the API, but it does not mean curl is the only way to operate Dewblock. -