miner mines continuously,
moved to an account model, transactions working, querying working, more checking of valid data
This commit is contained in:
parent
59bb42be11
commit
9847b2056b
12 changed files with 663 additions and 365 deletions
|
@ -5,9 +5,9 @@ const ChainUtil = require('../chain-util');
|
|||
|
||||
class Wallet {
|
||||
constructor(keyPair) {
|
||||
this.balance = INITIAL_BALANCE;
|
||||
this.keyPair = keyPair;
|
||||
this.publicKey = this.keyPair.getPublic().encode('hex');
|
||||
this.counter = 0;
|
||||
}
|
||||
|
||||
toString() {
|
||||
|
@ -20,63 +20,72 @@ class Wallet {
|
|||
return this.keyPair.sign(dataHash);
|
||||
}
|
||||
|
||||
createTransaction(recipient, amount, blockchain, transactionPool) {
|
||||
this.balance = this.calculateBalance(blockchain);
|
||||
createTransaction(recipient, amount, blockchain) {
|
||||
const balance = blockchain.getBalanceCopy(this.publicKey);
|
||||
|
||||
if (amount > this.balance) {
|
||||
console.log(`Amount: ${amount} exceceds current balance: ${this.balance}`);
|
||||
if (balance.counter > this.counter) {
|
||||
this.counter = balance.counter;
|
||||
}
|
||||
|
||||
if (amount > balance.balance) {
|
||||
console.log(`Amount: ${amount} exceceds current balance: ${balance.balance}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
return Transaction.newTransaction(this, recipient, amount);
|
||||
const counterToUse = this.counter + 1;
|
||||
this.counter++;
|
||||
|
||||
const newTransaction = new Transaction(this.publicKey, counterToUse, [Transaction.createOutput(recipient, amount)]);
|
||||
newTransaction.addSignature(this.sign(Transaction.hashToSign(newTransaction)));
|
||||
return newTransaction;
|
||||
}
|
||||
|
||||
createMetadata(SSNmetadata) {
|
||||
return Metadata.newMetadata(this, SSNmetadata);
|
||||
}
|
||||
|
||||
calculateBalance(blockchain) {
|
||||
let balance = this.balance;
|
||||
let transactions = [];
|
||||
blockchain.chain.forEach(block => block.data.forEach(transaction => {
|
||||
transactions.push(transaction);
|
||||
}));
|
||||
console.log("transactions of balance")
|
||||
console.log(transactions);
|
||||
const PaymentTransactions = transactions[0];
|
||||
console.log("Payment transactions ")
|
||||
console.log(PaymentTransactions);
|
||||
const walletInputTs = PaymentTransactions.filter(transaction => transaction.input.address === this.publicKey);
|
||||
//calculateBalance(blockchain) {
|
||||
// let balance = this.balance;
|
||||
// let transactions = [];
|
||||
// blockchain.chain.forEach(block => block.data.forEach(transaction => {
|
||||
// transactions.push(transaction);
|
||||
// }));
|
||||
// console.log("transactions of balance")
|
||||
// console.log(transactions);
|
||||
// const PaymentTransactions = transactions[0];
|
||||
// console.log("Payment transactions ")
|
||||
// console.log(PaymentTransactions);
|
||||
// const walletInputTs = PaymentTransactions.filter(transaction => transaction.input.address === this.publicKey);
|
||||
|
||||
let startTime = 0;
|
||||
// let startTime = 0;
|
||||
|
||||
if (walletInputTs.length > 0) {
|
||||
const recentInputT = walletInputTs.reduce(
|
||||
(prev, current) => prev.input.timestamp > current.input.timestamp ? prev : current
|
||||
);
|
||||
// if (walletInputTs.length > 0) {
|
||||
// const recentInputT = walletInputTs.reduce(
|
||||
// (prev, current) => prev.input.timestamp > current.input.timestamp ? prev : current
|
||||
// );
|
||||
|
||||
balance = recentInputT.outputs.find(output => output.address === this.publicKey).amount;
|
||||
startTime = recentInputT.input.timestamp;
|
||||
}
|
||||
// balance = recentInputT.outputs.find(output => output.address === this.publicKey).amount;
|
||||
// startTime = recentInputT.input.timestamp;
|
||||
// }
|
||||
|
||||
PaymentTransactions.forEach(transaction => {
|
||||
if (transaction.input.timestamp > startTime) {
|
||||
transaction.outputs.find(output => {
|
||||
if (output.address === this.publicKey) {
|
||||
balance += output.amount;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// PaymentTransactions.forEach(transaction => {
|
||||
// if (transaction.input.timestamp > startTime) {
|
||||
// transaction.outputs.find(output => {
|
||||
// if (output.address === this.publicKey) {
|
||||
// balance += output.amount;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
|
||||
return balance;
|
||||
}
|
||||
// return balance;
|
||||
//}
|
||||
|
||||
static blockchainWallet() {
|
||||
const blockchainWallet = new this(ChainUtil.genKeyPair());
|
||||
blockchainWallet.address = 'blockchain-wallet';
|
||||
return blockchainWallet;
|
||||
}
|
||||
//static blockchainWallet() {
|
||||
// const blockchainWallet = new this(ChainUtil.genKeyPair());
|
||||
// blockchainWallet.address = 'blockchain-wallet';
|
||||
// return blockchainWallet;
|
||||
//}
|
||||
}
|
||||
|
||||
module.exports = Wallet;
|
||||
|
|
|
@ -18,12 +18,14 @@ describe('Wallet', () => {
|
|||
beforeEach(() => {
|
||||
sendAmount = 50;
|
||||
recipient = 'r4nd0m-4ddr355';
|
||||
transaction = wallet.createTransaction(recipient, sendAmount, bc, tp);
|
||||
transaction = wallet.createTransaction(recipient, sendAmount, bc);
|
||||
tp.updateOrAddTransaction(transaction);
|
||||
});
|
||||
|
||||
describe('and doing the same transaction', () => {
|
||||
beforeEach(() => {
|
||||
wallet.createTransaction(recipient, sendAmount, bc, tp);
|
||||
transaction = wallet.createTransaction(recipient, sendAmount, bc);
|
||||
tp.updateOrAddTransaction(transaction);
|
||||
});
|
||||
|
||||
it('doubles the `sendAmount` subtracted from the wallet balance', () => {
|
||||
|
@ -46,7 +48,8 @@ describe('Wallet', () => {
|
|||
addBalance = 100;
|
||||
repeatAdd = 3;
|
||||
for (let i=0; i<repeatAdd; i++) {
|
||||
senderWallet.createTransaction(wallet.publicKey, addBalance, bc, tp);
|
||||
const transaction = senderWallet.createTransaction(wallet.publicKey, addBalance, bc);
|
||||
tp.updateOrAddTransaction(transaction);
|
||||
}
|
||||
bc.addBlock(tp.transactions);
|
||||
});
|
||||
|
@ -66,14 +69,16 @@ describe('Wallet', () => {
|
|||
tp.clear();
|
||||
subtractBalance = 60;
|
||||
recipientBalance = wallet.calculateBalance(bc);
|
||||
wallet.createTransaction(senderWallet.publicKey, subtractBalance, bc, tp);
|
||||
const transaction = wallet.createTransaction(senderWallet.publicKey, subtractBalance, bc);
|
||||
tp.updateOrAddTransaction(transaction);
|
||||
bc.addBlock(tp.transactions);
|
||||
});
|
||||
|
||||
describe('and the sender sends another transaction to the recipient', () => {
|
||||
beforeEach(() => {
|
||||
tp.clear();
|
||||
senderWallet.createTransaction(wallet.publicKey, addBalance, bc, tp);
|
||||
const transaction = senderWallet.createTransaction(wallet.publicKey, addBalance, bc);
|
||||
tp.updateOrAddTransaction(transaction);
|
||||
bc.addBlock(tp.transactions);
|
||||
});
|
||||
|
||||
|
|
|
@ -63,9 +63,7 @@ class Metadata {
|
|||
}
|
||||
|
||||
static newMetadata(senderWallet,SSNmetadata){
|
||||
return Metadata.MetadataOfIoTDevice(senderWallet, SSNmetadata
|
||||
);
|
||||
|
||||
return Metadata.MetadataOfIoTDevice(senderWallet, SSNmetadata);
|
||||
}
|
||||
|
||||
static signMetadata (metadata, senderWallet) {
|
||||
|
@ -76,14 +74,13 @@ class Metadata {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static verifyMetadata(metadata) {
|
||||
return ChainUtil.verifySignature(
|
||||
metadata.Signiture.address,
|
||||
metadata.Signiture.signature,
|
||||
ChainUtil.hash(metadata.SSNmetadata)
|
||||
);
|
||||
}
|
||||
static verifyMetadata(metadata) {
|
||||
return ChainUtil.verifySignature(
|
||||
metadata.Signiture.address,
|
||||
metadata.Signiture.signature,
|
||||
ChainUtil.hash(metadata.SSNmetadata)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Metadata;
|
|
@ -1,5 +1,6 @@
|
|||
const Transaction = require('../wallet/transaction');
|
||||
const Metadata = require('../wallet/metadata')
|
||||
const Metadata = require('../wallet/metadata');
|
||||
const Block = require('../blockchain/block');
|
||||
|
||||
const Return = {
|
||||
add: 1,
|
||||
|
@ -10,16 +11,16 @@ const Return = {
|
|||
class TransactionPool {
|
||||
constructor() {
|
||||
this.transactions = [];
|
||||
this.metadataS =[];
|
||||
this.metadatas = [];
|
||||
}
|
||||
|
||||
//returns true on update, false on add
|
||||
updateOrAddTransaction(transaction) {
|
||||
if (!Transaction.verifyTransaction(transaction)) {
|
||||
if (!Transaction.verify(transaction)) {
|
||||
console.log("Couldn't update or add transaction, transaction couldn't be verified");
|
||||
return Return.error;
|
||||
}
|
||||
const foundIndex = this.transactions.findIndex(t => t.id === transaction.id);
|
||||
const foundIndex = this.transactions.findIndex(t => t.input === transaction.input && t.counter === transaction.counter);
|
||||
|
||||
if (foundIndex !== -1) {
|
||||
this.transactions[foundIndex] = transaction;
|
||||
|
@ -36,13 +37,13 @@ class TransactionPool {
|
|||
return Return.error;
|
||||
}
|
||||
|
||||
const foundIndex = this.metadataS.findIndex(t => t.id === metadata.id);
|
||||
const foundIndex = this.metadatas.findIndex(t => t.id === metadata.id);
|
||||
|
||||
if (foundIndex !== -1) {
|
||||
this.metadataS[foundIndex] = metadata;
|
||||
this.metadatas[foundIndex] = metadata;
|
||||
return Return.update;
|
||||
} else {
|
||||
this.metadataS.push(metadata);
|
||||
this.metadatas.push(metadata);
|
||||
return Return.add;
|
||||
}
|
||||
}
|
||||
|
@ -52,62 +53,41 @@ class TransactionPool {
|
|||
}
|
||||
|
||||
existingMetadata(address) {
|
||||
return this.metadataS.find(t => t.Signiture.address === address);
|
||||
return this.metadatas.find(t => t.Signiture.address === address);
|
||||
}
|
||||
|
||||
validTransactions() {
|
||||
return this.transactions.filter(transaction => {
|
||||
const outputTotal = transaction.outputs.reduce((total, output) => {
|
||||
return total + output.amount;
|
||||
}, 0);
|
||||
|
||||
if (transaction.input.amount !== outputTotal) {
|
||||
console.log(`Invalid transaction from ${transaction.input.address}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Transaction.verifyTransaction(transaction)) {
|
||||
console.log(`Invalid signature from ${transaction.input.address}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
return transaction;
|
||||
});
|
||||
//we could check for possible double spends here
|
||||
validTransactionsCopy() {
|
||||
return [...this.transactions];
|
||||
}
|
||||
|
||||
validMetadataS(){
|
||||
return this.metadataS.filter(metadata => {
|
||||
if (!Metadata.verifyMetadata(metadata)) {
|
||||
console.log(`Invalid signature from ${metadata.Signiture.address}.`);
|
||||
return;
|
||||
}
|
||||
return metadata;
|
||||
});
|
||||
validMetadatasCopy(){
|
||||
return [...this.metadatas];
|
||||
}
|
||||
|
||||
clearFromBlock(block) {
|
||||
const transactions = block.data[0];
|
||||
const metadatas = block.data[1];
|
||||
for (const transaction of transactions) {
|
||||
const blockTransactions = Block.getTransactions(block);
|
||||
const blockMetadatas = Block.getMetadatas(block);
|
||||
|
||||
for (const transaction of blockTransactions) {
|
||||
const foundTransaction = this.transactions.findIndex(t => t.id === transaction.id);
|
||||
|
||||
if (foundTransaction !== -1) {
|
||||
this.transactions.splice(foundTransaction, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (const metadata of metadatas) {
|
||||
const foundMetadata = this.metadataS.findIndex(m => m.id === metadata.id);
|
||||
for (const metadata of blockMetadatas) {
|
||||
const foundMetadata = this.metadatas.findIndex(m => m.id === metadata.id);
|
||||
|
||||
if (foundMetadata !== -1) {
|
||||
this.metadataS.splice(foundMetadata, 1);
|
||||
this.metadatas.splice(foundMetadata, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clearAll() {
|
||||
this.transactions = [];
|
||||
this.metadataS = [];
|
||||
this.metadatas = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,66 +2,77 @@ const ChainUtil = require('../chain-util');
|
|||
const { MINING_REWARD } = require('../config');
|
||||
|
||||
class Transaction {
|
||||
constructor() {
|
||||
this.id = ChainUtil.id();
|
||||
this.input = null;
|
||||
this.outputs = [];
|
||||
constructor(senderPublicKey, counter, outputs) {
|
||||
this.input = senderPublicKey;
|
||||
this.signature = null;
|
||||
this.counter = counter;
|
||||
this.outputs = outputs;
|
||||
}
|
||||
|
||||
update(senderWallet, recipient, amount) {
|
||||
const senderOutput = this.outputs.find(output => output.address === senderWallet.publicKey);
|
||||
addSignature(signature) {
|
||||
if (!ChainUtil.verifySignature(
|
||||
this.input,
|
||||
signature,
|
||||
Transaction.hashToSign(this))) {
|
||||
console.log("Tried to add an invalid signature to a transaction");
|
||||
throw new Error("Tried to add an invalid signature to a transaction");
|
||||
}
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
if (amount > senderOutput.amount) {
|
||||
console.log(`Amount: ${amount} exceeds balance.`);
|
||||
return;
|
||||
static hashToSign(transaction) {
|
||||
return ChainUtil.hash({
|
||||
counter: transaction.counter,
|
||||
outputs: transaction.outputs
|
||||
});
|
||||
}
|
||||
|
||||
static createOutput(recipient, amount) {
|
||||
return {
|
||||
publicKey: recipient,
|
||||
amount: amount
|
||||
};
|
||||
}
|
||||
|
||||
//update(senderWallet, recipients) {
|
||||
// const senderOutput = this.outputs.find(output => output.address === senderWallet.publicKey);
|
||||
|
||||
// if (amount > senderOutput.amount) {
|
||||
// console.log(`Amount: ${amount} exceeds balance.`);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// senderOutput.amount = senderOutput.amount - amount;
|
||||
// this.outputs.push({ amount, address: recipient });
|
||||
// Transaction.signTransaction(this, senderWallet);
|
||||
|
||||
// return this;
|
||||
//}
|
||||
//static signTransaction(transaction, senderWallet) {
|
||||
// transaction.input = {
|
||||
// timestamp: Date.now(),
|
||||
// address: senderWallet.publicKey,
|
||||
// signature: senderWallet.sign(ChainUtil.hash(transaction.outputs))
|
||||
// }
|
||||
//}
|
||||
|
||||
static verify(transaction) {
|
||||
if (transaction.outputs.length === 0) {
|
||||
return false;
|
||||
}
|
||||
for (const output of transaction.outputs) {
|
||||
if (!output.hasOwnProperty('amount')) {
|
||||
return false;
|
||||
}
|
||||
if (!output.hasOwnProperty('publicKey')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
senderOutput.amount = senderOutput.amount - amount;
|
||||
this.outputs.push({ amount, address: recipient });
|
||||
Transaction.signTransaction(this, senderWallet);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
static transactionWithOutputs(senderWallet, outputs) {
|
||||
const transaction = new this();
|
||||
transaction.outputs.push(...outputs);
|
||||
Transaction.signTransaction(transaction, senderWallet);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
static newTransaction(senderWallet, recipient, amount) {
|
||||
if (amount > senderWallet.balance) {
|
||||
console.log(`Amount: ${amount} exceeds balance.`);
|
||||
return;
|
||||
}
|
||||
|
||||
return Transaction.transactionWithOutputs(senderWallet, [
|
||||
{ amount: senderWallet.balance - amount, address: senderWallet.publicKey },
|
||||
{ amount, address: recipient }
|
||||
]);
|
||||
}
|
||||
|
||||
static rewardTransaction(minerWallet, blockchainWallet) {
|
||||
return Transaction.transactionWithOutputs(blockchainWallet, [{
|
||||
amount: MINING_REWARD, address: minerWallet.publicKey
|
||||
}]);
|
||||
}
|
||||
|
||||
static signTransaction(transaction, senderWallet) {
|
||||
transaction.input = {
|
||||
timestamp: Date.now(),
|
||||
amount: senderWallet.balance,
|
||||
address: senderWallet.publicKey,
|
||||
signature: senderWallet.sign(ChainUtil.hash(transaction.outputs))
|
||||
}
|
||||
}
|
||||
|
||||
static verifyTransaction(transaction) {
|
||||
return ChainUtil.verifySignature(
|
||||
transaction.input.address,
|
||||
transaction.input.signature,
|
||||
ChainUtil.hash(transaction.outputs)
|
||||
transaction.input,
|
||||
transaction.signature,
|
||||
Transaction.hashToSign(transaction)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue