Skip to content

Commit

Permalink
Set up validTransactionData tests
Browse files Browse the repository at this point in the history
  • Loading branch information
15Dkatz committed Nov 15, 2018
1 parent 04db7d5 commit e915ea1
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 4 deletions.
52 changes: 52 additions & 0 deletions blockchain/index.test.js
@@ -1,6 +1,8 @@
const Blockchain = require('./index');
const Block = require('./block');
const { cryptoHash } = require('../util');
const Wallet = require('../wallet');
const Transaction = require('../wallet/transaction');

describe('Blockchain', () => {
let blockchain, newChain, originalChain;
Expand Down Expand Up @@ -151,4 +153,54 @@ describe('Blockchain', () => {
});
});
});

describe('validTransactionData()', () => {
let transaction, rewardTransaction, wallet;

beforeEach(() => {
wallet = new Wallet();
transaction = wallet.createTransaction({ recipient: 'foo-address', amount: 65 });
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);
});
});

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

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

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

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

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

describe('and the transaction is a reward transaction', () => {
it('returns false', () => {});
});
});

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

describe('and a block contains multiple identical transactions', () => {
it('returns false', () => {});
});
});
});
15 changes: 14 additions & 1 deletion index.js
Expand Up @@ -43,7 +43,11 @@ app.post('/api/transact', (req, res) => {
if (transaction) {
transaction.update({ senderWallet: wallet, recipient, amount });
} else {
transaction = wallet.createTransaction({ recipient, amount });
transaction = wallet.createTransaction({
recipient,
amount,
chain: blockchain.chain
});
}
} catch(error) {
return res.status(400).json({ type: 'error', message: error.message });
Expand All @@ -66,6 +70,15 @@ app.get('/api/mine-transactions', (req, res) => {
res.redirect('/api/blocks');
});

app.get('/api/wallet-info', (req, res) => {
const address = wallet.publicKey;

res.json({
address,
balance: Wallet.calculateBalance({ chain: blockchain.chain, address })
});
});

const syncWithRootState = () => {
request({ url: `${ROOT_NODE_ADDRESS}/api/blocks` }, (error, response, body) => {
if (!error && response.statusCode === 200) {
Expand Down
22 changes: 19 additions & 3 deletions wallet/index.js
Expand Up @@ -15,7 +15,14 @@ class Wallet {
return this.keyPair.sign(cryptoHash(data))
}

createTransaction({ recipient, amount }) {
createTransaction({ recipient, amount, chain }) {
if (chain) {
this.balance = Wallet.calculateBalance({
chain,
address: this.publicKey
});
}

if (amount > this.balance) {
throw new Error('Amount exceeds balance');
}
Expand All @@ -24,21 +31,30 @@ class Wallet {
}

static calculateBalance({ chain, address }) {
let hasConductedTransaction = false;
let outputsTotal = 0;

for (let i=1; i<chain.length; i++) {
for (let i=chain.length-1; i>0; i--) {
const block = chain[i];

for (let transaction of block.data) {
if (transaction.input.address === address) {
hasConductedTransaction = true;
}

const addressOutput = transaction.outputMap[address];

if (addressOutput) {
outputsTotal = outputsTotal + addressOutput;
}
}

if (hasConductedTransaction) {
break;
}
}

return STARTING_BALANCE + outputsTotal;
return hasConductedTransaction ? outputsTotal : STARTING_BALANCE + outputsTotal;
}
};

Expand Down
77 changes: 77 additions & 0 deletions wallet/index.test.js
Expand Up @@ -72,6 +72,26 @@ describe('Wallet', () => {
expect(transaction.outputMap[recipient]).toEqual(amount);
});
});

describe('and a chain is passed', () => {
it('calls `Wallet.calculateBalance`', () => {
const calculateBalanceMock = jest.fn();

const originalCalculateBalance = Wallet.calculateBalance;

Wallet.calculateBalance = calculateBalanceMock;

wallet.createTransaction({
recipient: 'foo',
amount: 10,
chain: new Blockchain().chain
});

expect(calculateBalanceMock).toHaveBeenCalled();

Wallet.calculateBalance = originalCalculateBalance;
});
});
});

describe('calculateBalance()', () => {
Expand Down Expand Up @@ -121,6 +141,63 @@ describe('Wallet', () => {
transactionTwo.outputMap[wallet.publicKey]
);
});

describe('and the wallet has made a transaction', () => {
let recentTransaction;


beforeEach(() => {
recentTransaction = wallet.createTransaction({
recipient: 'foo-address',
amount: 30
});

blockchain.addBlock({ data: [recentTransaction] });
});

it('returns the output amount of the recent transaction', () => {
expect(
Wallet.calculateBalance({
chain: blockchain.chain,
address: wallet.publicKey
})
).toEqual(recentTransaction.outputMap[wallet.publicKey]);
});

describe('and there are outputs next to and after the recent transaction', () => {
let sameBlockTransaction, nextBlockTransaction;

beforeEach(() => {
recentTransaction = wallet.createTransaction({
recipient: 'later-foo-address',
amount: 60
});

sameBlockTransaction = Transaction.rewardTransaction({ minerWallet: wallet });

blockchain.addBlock({ data: [recentTransaction, sameBlockTransaction] });

nextBlockTransaction = new Wallet().createTransaction({
recipient: wallet.publicKey, amount: 75
});

blockchain.addBlock({ data: [nextBlockTransaction] });
});

it('includes the output amounts in the returned balance', () => {
expect(
Wallet.calculateBalance({
chain: blockchain.chain,
address: wallet.publicKey
})
).toEqual(
recentTransaction.outputMap[wallet.publicKey] +
sameBlockTransaction.outputMap[wallet.publicKey] +
nextBlockTransaction.outputMap[wallet.publicKey]
);
});
});
});
});
});
});

0 comments on commit e915ea1

Please sign in to comment.