Skip to content

Commit

Permalink
Valid Transaction Data | Code
Browse files Browse the repository at this point in the history
  • Loading branch information
15Dkatz committed Sep 29, 2022
1 parent 4bda317 commit 5167c4d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 15 deletions.
35 changes: 32 additions & 3 deletions blockchain/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const Block = require('./block');
const Transaction = require('../wallet/transaction');
const { cryptoHash } = require('../util');
const { REWARD_INPUT, MINING_REWARD } = require('../config');

class Blockchain {
constructor() {
Expand All @@ -18,22 +20,49 @@ class Blockchain {
replaceChain(chain, onSuccess) {
if (chain.length <= this.chain.length) {
console.error('The incoming chain must be longer');

return;
}

if (!Blockchain.isValidChain(chain)) {
console.error('The incoming chain must be valid');

return;
}

if (onSuccess) onSuccess();

console.log('replacing chain with', chain);
this.chain = chain;
}

validTransactionData({ chain }) {
for (let i=1; i<chain.length; i++) {
const block = chain[i];
let rewardTransactionCount = 0;

for (let transaction of block.data) {
if (transaction.input.address === REWARD_INPUT.address) {
rewardTransactionCount += 1;

if (rewardTransactionCount > 1) {
console.error('Miner rewards exceeds limit');
return false;
}

if (Object.values(transaction.outputMap)[0] !== MINING_REWARD) {
console.error('Miner reward amount is invalid');
return false;
}
} else {
if (!Transaction.validTransaction(transaction)) {
console.error('Invalid transaction');
return false;
}
}
}
}

return true;
}

static isValidChain(chain) {
if(JSON.stringify(chain[0]) !== JSON.stringify(Block.genesis())) return false;

Expand Down
34 changes: 22 additions & 12 deletions blockchain/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ const Wallet = require('../wallet');
const Transaction = require('../wallet/transaction');

describe('Blockchain', () => {
let blockchain, newChain, originalChain;
let blockchain, newChain, originalChain, errorMock;

beforeEach(() => {
blockchain = new Blockchain();
newChain = new Blockchain();
errorMock = jest.fn();

originalChain = blockchain.chain;
global.console.error = errorMock;
});

it('contains a `chain` Array instance', () => {
Expand Down Expand Up @@ -91,13 +93,11 @@ describe('Blockchain', () => {
});

describe('replaceChain()', () => {
let errorMock, logMock;
let logMock;

beforeEach(() => {
errorMock = jest.fn();
logMock = jest.fn();

global.console.error = errorMock;
global.console.log = logMock;
});

Expand Down Expand Up @@ -164,47 +164,57 @@ describe('Blockchain', () => {
beforeEach(() => {
wallet = new Wallet();
transaction = wallet.createTransaction({ recipient: 'foo-address', amount: 65 });
rewardTransaction = Transaction.rewardTransaction({ address: wallet.publicKey });
rewardTransaction = Transaction.rewardTransaction({ minerWallet: wallet });
});

describe('and the transaction data is valid', () => {
it('returns true', () => {
newChain.addBlock({ data: [transaction, rewardTransaction] });

expect(blockchain.validTransactionData({ chain: newChain.chain }).toBe(true);
expect(blockchain.validTransactionData({ chain: newChain.chain })).toBe(true);
expect(errorMock).not.toHaveBeenCalled();
});
});

describe('and the transaction data has multiple rewards', () => {
it('returns false', () => {
it('returns false and logs an error', () => {
newChain.addBlock({ data: [transaction, rewardTransaction, rewardTransaction] });

expect(blockchain.validTransactionData({ chain: newChain.chain })).toBe(false);
expect(errorMock).toHaveBeenCalled();
});
});

describe('and the transaction data has at least one malformed outputMap', () => {
describe('and the transaction is not a reward transaction', () => {
it('returns false', () => {
it('returns false and logs an error', () => {
transaction.outputMap[wallet.publicKey] = 999999;

newChain.addBlock({ data: [transaction, rewardTransaction ]});

expect(blockchain.validTransactionData({ chain: newChain.chain })).toBe(false);
expect(errorMock).toHaveBeenCalled();
});
});

derscribe('and the transaction is a reward transaciton', () => {
it('returns false', () => {});
describe('and the transaction is a reward transaciton', () => {
it('returns false and logs an error', () => {
rewardTransaction.outputMap[wallet.publicKey] = 999999;

newChain.addBlock({ data: [transaction, rewardTransaction] });

expect(blockchain.validTransactionData({ chain: newChain.chain })).toBe(false);
expect(errorMock).toHaveBeenCalled();
});
});
});

describe('and the transaction data has at least one malformed input', () => {
it('returns false', () => {});
it('returns false and logs an error', () => {});
});

describe('and a block contains multiple identical transactions', () => {
it('returns false', () => {});
it('returns false and logs an error', () => {});
});
});
});

0 comments on commit 5167c4d

Please sign in to comment.