mirror of
https://github.com/yjjnls/awesome-blockchain.git
synced 2024-10-01 00:45:35 -04:00
add persistence and transaction (UTXO)
This commit is contained in:
parent
759114227f
commit
3cf616a1f3
@ -5,13 +5,18 @@ class Account {
|
||||
this.keypair_ = keypair;
|
||||
this.id_ = id;
|
||||
this.amount_ = 0;
|
||||
if (!this.keypair_) { }
|
||||
if (!this.id_) { }
|
||||
if (!this.keypair_) {
|
||||
// load from file
|
||||
}
|
||||
if (!this.id_) {
|
||||
// load from file
|
||||
}
|
||||
}
|
||||
|
||||
get_id() { return this.id_; }
|
||||
get_key() { return this.keypair_; }
|
||||
get_amount() { return this.amount_; }
|
||||
set_amount(amount) {this.amount_ = amount;}
|
||||
}
|
||||
|
||||
module.exports = Account;
|
@ -1,14 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var crypto = require("crypto");
|
||||
var ed = require("ed25519");
|
||||
var Crypto = require("./crypto");
|
||||
|
||||
|
||||
class Block extends EventEmitter {
|
||||
constructor(data, consensus) {
|
||||
super();
|
||||
// body
|
||||
this.transcations_ = data ? data.transactions : [];
|
||||
this.transactions_ = data ? data.transactions : [];
|
||||
// header
|
||||
this.version_ = 0;
|
||||
this.height_ = data ? data.previous_block.height + 1 : -1;
|
||||
@ -37,7 +37,7 @@ class Block extends EventEmitter {
|
||||
get_timestamp() { return this.timestamp_; }
|
||||
get_signature() { return this.block_signature_; }
|
||||
get_publickey() { return this.generator_publickey_; }
|
||||
get_transcations() { return this.transcations_; }
|
||||
get_transactions() { return this.transactions_; }
|
||||
get_consensus_data() { return this.consensus_data_; }
|
||||
set_consensus_data(data) { this.consensus_data_ = data; }
|
||||
toObject() {
|
||||
@ -51,7 +51,7 @@ class Block extends EventEmitter {
|
||||
"hash": this.hash_,
|
||||
"block_signature": this.block_signature_,
|
||||
"consensus_data": this.consensus_data_,
|
||||
"transcations": this.transcations_
|
||||
"transactions": this.transactions_
|
||||
};
|
||||
return block;
|
||||
}
|
||||
@ -65,23 +65,20 @@ class Block extends EventEmitter {
|
||||
this.hash_ = data.hash;
|
||||
this.block_signature_ = data.block_signature;
|
||||
this.consensus_data_ = data.consensus_data;
|
||||
this.transcations_ = data.transactions;
|
||||
this.transactions_ = data.transactions;
|
||||
}
|
||||
|
||||
calc_hash(data) {
|
||||
return crypto.createHash('sha256').update(data).digest('hex');
|
||||
}
|
||||
calc_merkle_hash() {
|
||||
// calc merkle root hash according to the transcations in the block
|
||||
// calc merkle root hash according to the transactions in the block
|
||||
var hashes = [];
|
||||
for (var i = 0; i < this.transcations_.length; ++i) {
|
||||
hashes.push(this.calc_hash(this.transcations_.toString('utf-8')));
|
||||
for (var i = 0; i < this.transactions_.length; ++i) {
|
||||
hashes.push(Crypto.calc_hash(this.transactions_.toString('utf-8')));
|
||||
}
|
||||
while (hashes.length > 1) {
|
||||
var tmp = [];
|
||||
for (var i = 0; i < hashes.length / 2; ++i) {
|
||||
let data = hashes[i * 2] + hashes[i * 2 + 1];
|
||||
tmp.push(this.calc_hash(data));
|
||||
tmp.push(Crypto.calc_hash(data));
|
||||
}
|
||||
if (hashes.length % 2 === 1) {
|
||||
tmp.push(hashes[hashes.length - 1]);
|
||||
@ -93,8 +90,8 @@ class Block extends EventEmitter {
|
||||
|
||||
prepare_data() {
|
||||
let tx = "";
|
||||
for (var i = 0; i < this.transcations_.length; ++i) {
|
||||
tx += this.transcations_[i].toString('utf-8');
|
||||
for (var i = 0; i < this.transactions_.length; ++i) {
|
||||
tx += this.transactions_[i].toString('utf-8');
|
||||
}
|
||||
let data = this.version_.toString()
|
||||
+ this.height_.toString()
|
||||
@ -109,11 +106,11 @@ class Block extends EventEmitter {
|
||||
}
|
||||
// calc the hash of the block
|
||||
calc_block_hash() {
|
||||
return this.calc_hash(this.prepare_data());
|
||||
return Crypto.calc_hash(this.prepare_data());
|
||||
}
|
||||
sign(keypair) {
|
||||
var hash = this.calc_block_hash();
|
||||
return ed.Sign(Buffer.from(hash, 'utf-8'), keypair).toString('hex');
|
||||
return Crypto.sign(keypair, hash);
|
||||
}
|
||||
make_proof(consensus, keypair) {
|
||||
let self = this;
|
||||
@ -128,13 +125,7 @@ class Block extends EventEmitter {
|
||||
|
||||
static verify_signature(block) {
|
||||
var hash = block.hash;
|
||||
var res = ed.Verify(Buffer.from(hash, 'utf8'), Buffer.from(block.block_signature, 'hex'), Buffer.from(block.generator_publickey, 'hex'));
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
static get_address_by_publickey(publicKey) {
|
||||
|
||||
return Crypto.verify_signature(hash, block.block_signature, block.generator_publickey);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,17 +4,22 @@ var Block = require("./block");
|
||||
const genesis_block = require("./genesis_block.json");
|
||||
var Node = require("./network");
|
||||
var Account = require("./account");
|
||||
var Transaction = require("./transaction");
|
||||
var Transaction = require("./transaction").Transaction;
|
||||
var TxInput = require("./transaction").TxInput;
|
||||
var TxOutput = require("./transaction").TxOutput;
|
||||
var Msg = require("./message");
|
||||
var MessageType = require("./message").type;
|
||||
var Promise = require("bluebird");
|
||||
var level = require("level");
|
||||
var Crypto = require("./crypto");
|
||||
|
||||
var Pbft = require("./consensus/pbft");
|
||||
let pbft = true;
|
||||
let pbft = false;
|
||||
class BlockChain {
|
||||
constructor(Consensus, keypair, id, is_bad = false) {
|
||||
// todo
|
||||
this.pending_block_ = {};
|
||||
this.tx_pool = {};
|
||||
this.chain_ = [];
|
||||
|
||||
this.is_bad_ = is_bad;
|
||||
@ -22,14 +27,26 @@ class BlockChain {
|
||||
|
||||
// ///////////////////////////////////////
|
||||
this.genesis_block_ = genesis_block;
|
||||
this.last_block_ = genesis_block;
|
||||
this.save_last_block();
|
||||
|
||||
|
||||
this.account_ = new Account(keypair, id);
|
||||
this.consensus_ = new Consensus(this);
|
||||
this.node_ = null;
|
||||
}
|
||||
start() {
|
||||
async start() {
|
||||
this.db_ = level(`/tmp/data_${this.get_account_id()}`);
|
||||
try {
|
||||
// load blocks
|
||||
let last = await this.db_.get("last_block");
|
||||
this.last_block_ = JSON.parse(last);
|
||||
console.log(`node: ${this.get_account_id()} last block: ${this.last_block_.height}`);
|
||||
} catch (err) {
|
||||
// empty chain
|
||||
this.last_block_ = genesis_block;
|
||||
this.save_last_block();
|
||||
console.log(`node: ${this.get_account_id()} empty`);
|
||||
}
|
||||
|
||||
this.node_ = new Node(this.get_account_id());
|
||||
this.node_.on("message", this.on_data.bind(this));
|
||||
this.node_.start();
|
||||
@ -57,18 +74,40 @@ class BlockChain {
|
||||
cb();
|
||||
}
|
||||
|
||||
save_last_block() {
|
||||
async save_last_block() {
|
||||
// query from db via hash
|
||||
// if not exist, write into db, else do nothing
|
||||
// todo(tx is also need to store?)
|
||||
if (this.pending_block_[this.last_block_.hash]) {
|
||||
delete this.pending_block_[this.last_block_.hash];
|
||||
}
|
||||
this.chain_.push(this.last_block_);
|
||||
await this.db_.put(this.last_block_.hash, JSON.stringify(this.last_block_));
|
||||
await this.db_.put("last_block", JSON.stringify(this.last_block_));
|
||||
// console.log(`save block: ${this.last_block_.hash} to db`);
|
||||
|
||||
// tx
|
||||
if (!this.last_block_.transactions) {
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < this.last_block_.transactions.length; ++i) {
|
||||
let tx = this.last_block_.transactions[i];
|
||||
if (this.tx_pool[tx.id]) {
|
||||
delete this.tx_pool[tx.id];
|
||||
// console.log(`node ${this.get_account_id()} delete tx ${tx.id}`);
|
||||
}
|
||||
await this.db_.put(tx.id, JSON.stringify(tx));
|
||||
}
|
||||
}
|
||||
generate_block(keypair, cb) {
|
||||
// load transcations
|
||||
var tx = [];
|
||||
// load transactions
|
||||
var tx = [this.create_coinbase()];
|
||||
var i = 0;
|
||||
for (let key in this.tx_pool) {
|
||||
if (i == 10)
|
||||
break;
|
||||
tx.push(this.tx_pool[key]);
|
||||
i++;
|
||||
console.log(`node ${this.get_account_id()} load tx ${key}`);
|
||||
}
|
||||
// create block
|
||||
let block = new Block({
|
||||
"keypair": keypair,
|
||||
@ -79,7 +118,7 @@ class BlockChain {
|
||||
let self = this;
|
||||
block.on('block completed', (data) => {
|
||||
if (data.height == self.last_block_.height + 1) {
|
||||
console.log("block completed");
|
||||
// console.log("block completed");
|
||||
self.commit_block(data);
|
||||
|
||||
self.broadcast(Msg.block(data));
|
||||
@ -113,16 +152,33 @@ class BlockChain {
|
||||
get_height() {
|
||||
return this.last_block_.height;
|
||||
}
|
||||
get_block(hash) {
|
||||
async get_from_db(hash) {
|
||||
// query block with hash value
|
||||
// todo
|
||||
for (var i = 0; i < this.chain_.length; ++i) {
|
||||
if (this.chain_[i] == hash) {
|
||||
return this.chain_[i];
|
||||
}
|
||||
}
|
||||
try {
|
||||
let block_data = await this.db_.get(hash);
|
||||
let block = JSON.parse(block_data);
|
||||
return block;
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
async iterator_back(cb, hash) {
|
||||
if (!hash) {
|
||||
return;
|
||||
}
|
||||
let block = await this.get_from_db(hash);
|
||||
let res = cb(block);
|
||||
if (res)
|
||||
await this.iterator_back(cb, block.previous_hash);
|
||||
}
|
||||
async iterator_forward(cb, hash) {
|
||||
if (!hash) {
|
||||
return;
|
||||
}
|
||||
let block = await this.get_from_db(hash);
|
||||
await this.iterator_forward(cb, block.previous_hash);
|
||||
cb(block);
|
||||
}
|
||||
get_last_block() {
|
||||
return this.last_block_;
|
||||
}
|
||||
@ -140,41 +196,89 @@ class BlockChain {
|
||||
get_account_keypair() {
|
||||
return this.account_.get_key();
|
||||
}
|
||||
get_public_key() {
|
||||
return this.get_account_keypair().publicKey.toString('hex');
|
||||
}
|
||||
broadcast(data) {
|
||||
this.node_.broadcast(data);
|
||||
}
|
||||
list_peers() {
|
||||
return this.node_.list_peers();
|
||||
}
|
||||
async verify_transaction(tx) {
|
||||
let input_amount = 0;
|
||||
for (var i = 0; i < tx.input.length; ++i) {
|
||||
let input = tx.input[i];
|
||||
// coinbase
|
||||
if (input.id == null) {
|
||||
// todo check milestone
|
||||
if (tx.output[0].amount == 50) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let vout = null;
|
||||
if (this.tx_pool[input.id]) {
|
||||
vout = this.tx.tx_pool[input.id];
|
||||
} else {
|
||||
vout = await this.get_from_db(input.id);
|
||||
}
|
||||
if (!vout) {
|
||||
// invalid vout
|
||||
return false;
|
||||
}
|
||||
vout = vout.output[input.index];
|
||||
let res = Crypto.verify_signature(JSON.stringify(vout), input.ScriptSig, vout.ScriptPubKey);
|
||||
if (!res) {
|
||||
return false;
|
||||
}
|
||||
input_amount += vout.amount;
|
||||
}
|
||||
let output_amount = 0;
|
||||
for (i = 0; i < tx.output.length; ++i) {
|
||||
output_amount += tx.output[i].amount;
|
||||
}
|
||||
if (input_amount < output_amount) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// verify the block is valid
|
||||
verify(block) {
|
||||
async verify(block) {
|
||||
// verify the block signature
|
||||
if (!Block.verify_signature(block))
|
||||
return false;
|
||||
// verify consensus
|
||||
if (!this.consensus_.verify(block))
|
||||
return false;
|
||||
// verify transcations
|
||||
let tx = block.transcations;
|
||||
// verify transactions
|
||||
let tx = block.transactions;
|
||||
if (tx) {
|
||||
for (var i = 0; i < tx.length; ++i) {
|
||||
// todo (check tx is exist and valid)
|
||||
if (!Transaction.verify(tx[i]))
|
||||
if (!await this.verify_transaction(tx[i]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
on_data(msg) {
|
||||
async on_data(msg) {
|
||||
switch (msg.type) {
|
||||
case MessageType.Block:
|
||||
{
|
||||
let block = msg.data;
|
||||
// console.log(`node: ${this.get_account_id()} receive block: height ${block.height}`);
|
||||
// check if exist
|
||||
if (this.pending_block_[block.hash] || this.get_block(block.hash))
|
||||
let query = await this.get_from_db(block.hash);
|
||||
if (this.pending_block_[block.hash] || query) {
|
||||
// console.log("block already exists");
|
||||
return;
|
||||
}
|
||||
// verify
|
||||
if (!this.verify(block))
|
||||
if (!await this.verify(block)) {
|
||||
// console.log("verify failed");
|
||||
return;
|
||||
}
|
||||
|
||||
this.pending_block_[block.hash] = block;
|
||||
|
||||
@ -195,6 +299,22 @@ class BlockChain {
|
||||
case MessageType.Transaction:
|
||||
{
|
||||
// check if exist(pending or in chain) verify, store(into pending) and broadcast
|
||||
let tx = msg.data;
|
||||
if (this.tx_pool[tx.id]) {
|
||||
// already exists
|
||||
return;
|
||||
}
|
||||
this.tx_pool[tx.id] = tx;
|
||||
// verify transaction
|
||||
let res = await this.verify_transaction(tx);
|
||||
if (!res) {
|
||||
delete this.tx_pool[tx.id];
|
||||
} else {
|
||||
// console.log(`node ${this.get_account_id()} store tx ${tx.id}`);
|
||||
}
|
||||
|
||||
// broadcast
|
||||
this.broadcast(msg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -218,7 +338,7 @@ class BlockChain {
|
||||
}
|
||||
async fork() {
|
||||
console.log('----------fork----------');
|
||||
// load transcations
|
||||
// load transactions
|
||||
var tx1 = [{
|
||||
amount: 1000,
|
||||
recipient: 'bob',
|
||||
@ -242,7 +362,7 @@ class BlockChain {
|
||||
});
|
||||
});
|
||||
|
||||
// load transcations
|
||||
// load transactions
|
||||
var tx2 = [{
|
||||
amount: 1000,
|
||||
recipient: 'cracker',
|
||||
@ -279,6 +399,91 @@ class BlockChain {
|
||||
console.log("fork");
|
||||
this.commit_block(block_data1);
|
||||
}
|
||||
create_coinbase() {
|
||||
let input = new TxInput(null, -1, `${new Date()} node: ${this.get_account_id()} coinbase tx`);
|
||||
let output = new TxOutput(50, this.get_public_key());
|
||||
let tx = new Transaction([input], [output]);
|
||||
return tx;
|
||||
}
|
||||
|
||||
async get_utxo(cb) {
|
||||
let publicKey = this.get_public_key();
|
||||
let spentTXOs = {};
|
||||
await this.iterator_back((block) => {
|
||||
let txs = block.transactions;
|
||||
// tx
|
||||
for (var i = 0; i < txs.length; ++i) {
|
||||
let tx = txs[i];
|
||||
let transaction_id = tx.id;
|
||||
// output
|
||||
for (var j = 0; j < tx.output.length; ++j) {
|
||||
let output = tx.output[j];
|
||||
// owns
|
||||
if (output.ScriptPubKey == publicKey) {
|
||||
// not spent
|
||||
if (spentTXOs.hasOwnProperty(transaction_id) &&
|
||||
spentTXOs[transaction_id].hasOwnProperty(j)) {
|
||||
continue;
|
||||
} else {
|
||||
if (!cb(transaction_id, j, output)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// input
|
||||
for (j = 0; j < tx.input.length; ++j) {
|
||||
let input = tx.input[j];
|
||||
// not coinbase
|
||||
if (input.id != null && input.index != -1) {
|
||||
if (!spentTXOs[input.id]) {
|
||||
spentTXOs[input.id] = [];
|
||||
}
|
||||
spentTXOs[input.id].push(input.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
this.get_last_block().hash);
|
||||
}
|
||||
async get_balance() {
|
||||
let value = 0;
|
||||
await this.get_utxo((transaction_id, index, vout) => {
|
||||
value += vout.amount;
|
||||
return true;
|
||||
});
|
||||
return value;
|
||||
}
|
||||
async create_transaction(to, amount) {
|
||||
let value = 0;
|
||||
let input = [];
|
||||
let output = [];
|
||||
let self = this;
|
||||
let tx = null;
|
||||
await this.get_utxo((transaction_id, index, vout) => {
|
||||
value += vout.amount;
|
||||
let signature = Crypto.sign(self.get_account_keypair(), JSON.stringify(vout));
|
||||
input.push(new TxInput(transaction_id, index, signature));
|
||||
if (value >= amount) {
|
||||
output.push(new TxOutput(amount, to));
|
||||
if (value > amount)
|
||||
output.push(new TxOutput(value - amount, self.get_public_key()));
|
||||
tx = new Transaction(input, output);
|
||||
// stop
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (value < amount) {
|
||||
throw new Error("amount is not enough!");
|
||||
}
|
||||
if (tx == null) {
|
||||
throw new Error("create transaction failed!");
|
||||
}
|
||||
this.tx_pool[tx.id] = tx;
|
||||
this.broadcast(Msg.transaction(tx));
|
||||
|
||||
return tx;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BlockChain;
|
23
src/js/crypto.js
Normal file
23
src/js/crypto.js
Normal file
@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
var crypto = require("crypto");
|
||||
var ed = require("ed25519");
|
||||
|
||||
function calc_hash(data) {
|
||||
return crypto.createHash('sha256').update(data).digest('hex');
|
||||
}
|
||||
|
||||
function sign(keypair, data) {
|
||||
return ed.Sign(Buffer.from(data, 'utf-8'), keypair).toString('hex');
|
||||
}
|
||||
|
||||
function verify_signature(data, signature, publickey) {
|
||||
var res = ed.Verify(Buffer.from(data, 'utf-8'), Buffer.from(signature, 'hex'), Buffer.from(publickey, 'hex'));
|
||||
return res;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
calc_hash,
|
||||
sign,
|
||||
verify_signature
|
||||
};
|
@ -8,5 +8,5 @@
|
||||
"hash": "d611edb9fd86ee234cdc08d9bf382330d6ccc721cd5e59cf2a01b0a2a8decfff",
|
||||
"block_signature": "603b61b14348fb7eb087fe3267e28abacadf3932f0e33958fb016ab60f825e3124bfe6c7198d38f8c91b0a3b1f928919190680e44fbe7289a4202039ffbb2109",
|
||||
"consensus_data": {},
|
||||
"transcations": []
|
||||
"transactions": []
|
||||
}
|
@ -15,5 +15,6 @@ module.exports = {
|
||||
block: (data) => { return { type: MessageType.Block, data: data }; },
|
||||
preprepare: (data) => { return { type: MessageType.PrePrepare, data: data }; },
|
||||
prepare: (data) => { return { type: MessageType.Prepare, data: data }; },
|
||||
commit: (data) => { return { type: MessageType.Commit, data: data }; }
|
||||
commit: (data) => { return { type: MessageType.Commit, data: data }; },
|
||||
transaction: (data)=>{return { type: MessageType.Transaction, data: data }; }
|
||||
};
|
@ -9,7 +9,8 @@
|
||||
"ed25519": "0.0.4",
|
||||
"eslint": "^5.13.0",
|
||||
"eslint-plugin-html": "^5.0.0",
|
||||
"js-sha256": "^0.9.0"
|
||||
"js-sha256": "^0.9.0",
|
||||
"level": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"scripts": {
|
||||
|
@ -18,12 +18,12 @@ let genesis = {
|
||||
"hash": null,
|
||||
"block_signature": null,
|
||||
"consensus_data": {},
|
||||
"transcations": []
|
||||
"transactions": []
|
||||
};
|
||||
|
||||
function prepare_data() {
|
||||
let tx = "";
|
||||
genesis.transcations.forEach(val => {
|
||||
genesis.transactions.forEach(val => {
|
||||
tx += val.toString('utf8');
|
||||
});
|
||||
let data = genesis.version.toString()
|
||||
|
34
src/js/test/db.js
Normal file
34
src/js/test/db.js
Normal file
@ -0,0 +1,34 @@
|
||||
'use strict';
|
||||
|
||||
var crypto = require('crypto');
|
||||
var ed = require('ed25519');
|
||||
var BlockChain = require("../blockchain");
|
||||
var Consensus = require("../consensus/dpos");
|
||||
|
||||
var password = 'I am tester!';
|
||||
|
||||
var hash = crypto.createHash('sha256').update(password).digest();
|
||||
var keypair = ed.MakeKeypair(hash);
|
||||
|
||||
let blockchains = [];
|
||||
for (var i = 0; i < 20; ++i) {
|
||||
let blockchain = new BlockChain(Consensus, keypair, i);
|
||||
blockchain.start();
|
||||
blockchains.push(blockchain);
|
||||
}
|
||||
|
||||
// setTimeout(() => {
|
||||
// for (var i = 0; i < 20; ++i) {
|
||||
// console.log(`${i} --> ${blockchains[i].list_peers()}`);
|
||||
// }
|
||||
// }, 3000);
|
||||
|
||||
setTimeout(async () => {
|
||||
console.log("=================");
|
||||
await blockchains[0].iterator_forward((block) => {
|
||||
console.log("-----------------");
|
||||
console.log(block.height);
|
||||
console.log(block.hash);
|
||||
return true;
|
||||
}, blockchains[0].get_last_block().hash);
|
||||
}, 5000);
|
40
src/js/test/transaction.js
Normal file
40
src/js/test/transaction.js
Normal file
@ -0,0 +1,40 @@
|
||||
'use strict';
|
||||
|
||||
var crypto = require('crypto');
|
||||
var ed = require('ed25519');
|
||||
var BlockChain = require("../blockchain");
|
||||
var Consensus = require("../consensus/dpos");
|
||||
|
||||
|
||||
let blockchains = [];
|
||||
for (var i = 0; i < 20; ++i) {
|
||||
|
||||
var password = `I am tester ${i}!`;
|
||||
var hash = crypto.createHash('sha256').update(password).digest();
|
||||
var keypair = ed.MakeKeypair(hash);
|
||||
console.log(`node ${i} address: ${keypair.publicKey.toString('hex')}`);
|
||||
|
||||
let blockchain = new BlockChain(Consensus, keypair, i);
|
||||
blockchain.start();
|
||||
blockchains.push(blockchain);
|
||||
}
|
||||
|
||||
// setTimeout(() => {
|
||||
// for (var i = 0; i < 20; ++i) {
|
||||
// console.log(`${i} --> ${blockchains[i].list_peers()}`);
|
||||
// }
|
||||
// }, 3000);
|
||||
|
||||
setTimeout(() => {
|
||||
let address = blockchains[6].get_public_key();
|
||||
blockchains[0].create_transaction(address, 30);
|
||||
}, 3000);
|
||||
|
||||
async function get_balance() {
|
||||
let amount = await blockchains[0].get_balance();
|
||||
console.log(`node 0 balance: ${amount}`);
|
||||
amount = await blockchains[6].get_balance();
|
||||
console.log(`node 6 balance: ${amount}`);
|
||||
}
|
||||
|
||||
setInterval(get_balance, 10000);
|
@ -1,13 +1,64 @@
|
||||
'use strict';
|
||||
var Crypto = require("./crypto");
|
||||
|
||||
class TxOutput {
|
||||
constructor(amount, ScriptPubKey) {
|
||||
this.amount_ = amount;
|
||||
this.script_pubkey_ = ScriptPubKey;
|
||||
}
|
||||
toObject() {
|
||||
let output = {
|
||||
"amount": this.amount_,
|
||||
"ScriptPubKey": this.script_pubkey_
|
||||
};
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
class TxInput {
|
||||
constructor(id, index, ScriptSig) {
|
||||
this.id_ = id;
|
||||
this.index_ = index;
|
||||
this.script_sig_ = ScriptSig;
|
||||
}
|
||||
toObject() {
|
||||
let input = {
|
||||
"id": this.id_,
|
||||
"index": this.index_,
|
||||
"ScriptSig": this.script_sig_
|
||||
};
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
class Transaction {
|
||||
constructor() {
|
||||
|
||||
constructor(input, output) {
|
||||
this.input_ = [];
|
||||
for (i = 0; i < input.length; ++i) {
|
||||
this.input_.push(input[i].toObject());
|
||||
}
|
||||
|
||||
static verify(tx) {
|
||||
return true;
|
||||
this.output_ = [];
|
||||
for (var i = 0; i < output.length; ++i) {
|
||||
this.output_.push(output[i].toObject());
|
||||
}
|
||||
this.id_ = Crypto.calc_hash(JSON.stringify(this.input_) + JSON.stringify(this.output_));
|
||||
return this.toObject();
|
||||
}
|
||||
get_id() { return this.id_; }
|
||||
get_input() { return this.input_; }
|
||||
get_output() { return this.output_; }
|
||||
toObject() {
|
||||
let tx = {
|
||||
"id": this.id_,
|
||||
"input": this.input_,
|
||||
"output": this.output_
|
||||
};
|
||||
return tx;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Transaction;
|
||||
module.exports = {
|
||||
TxOutput,
|
||||
TxInput,
|
||||
Transaction
|
||||
};
|
Loading…
Reference in New Issue
Block a user