Commit 3de63508 authored by Frédéric Bapst's avatar Frédéric Bapst
Browse files

add tiny JUnit test to s29

parent a042c589
package s29;
import java.util.ArrayList;
import java.util.List;
public class BolivarBlockchainV2 {
// This can be changed to simulate harder Proof-of-Work!
private static int DEFAULT_DIFFICULTY = 3;
private static int DEFAULT_N_TRANSACTIONS_PER_BLOCK = 2; // ~100 would be more reasonable
private final List<Block> chainOfBlocks = new ArrayList<>();
private final List<Transaction> committedTransactions = new ArrayList<>();
private final List<Transaction> pendingTransactions = new ArrayList<>();
private final int difficulty;
private final int nTransactionsPerBlock;
public BolivarBlockchainV2() {
this(DEFAULT_DIFFICULTY, DEFAULT_N_TRANSACTIONS_PER_BLOCK);
}
public BolivarBlockchainV2(int difficulty, int nTransactionsPerBlock) {
this.difficulty = difficulty;
this.nTransactionsPerBlock = nTransactionsPerBlock;
Block genesis = new Block(0, "", "Genesis");
genesis.mineBlock(difficulty);
chainOfBlocks.add(genesis);
}
private void addNewStuff(Block newBlock, List<Transaction> newTransactions) {
chainOfBlocks.add(newBlock);
committedTransactions.addAll(newTransactions);
System.out.println("Added a new block!");
System.out.println(newBlock.toReadableString());
}
public void handleNewTransaction(Transaction t) throws BadTransactionException, BadBlockchainException {
t.checkSignature();
checkSubmission(t);
pendingTransactions.add(t);
// Now t would be broadcasted to every participant in the network...
if(pendingTransactions.size() < nTransactionsPerBlock) return;
// Ok, there are enough transactions to forge a block. Let's try!
Transaction[] tt = new Transaction[nTransactionsPerBlock];
tt = pendingTransactions.toArray(tt);
Block b = newBlockForTransactions(tt);
b.mineBlock(difficulty);
// Now, provided that we "won" the competition and that our block b has been
// elected by consensus, b would be broadcasted to every participant in
// the network...
addNewStuff(b, pendingTransactions);
pendingTransactions.clear();
}
public void checkSubmission(Transaction t) throws BadTransactionException {
List<Transaction> all = new ArrayList<>(committedTransactions);
all.addAll(pendingTransactions);
all.add(t);
BolivarBlockchainV2.checkFullStory(all);
}
private Block newBlockForTransactions(Transaction[] ts) {
if(ts.length != nTransactionsPerBlock)
throw new IllegalArgumentException("bad number of transactions");
String digest = Transaction.combinedDigest(ts);
int nBlocks = chainOfBlocks.size();
Block lastBlock = chainOfBlocks.get(nBlocks-1);
Block newBlock = new Block(nBlocks, lastBlock.sha256(), digest);
return newBlock;
}
private void checkBlocksAgainstTransactions() throws BadBlockchainException {
int nb = chainOfBlocks.size() - 1; // the genesis block is special
if(committedTransactions.size() != nb * nTransactionsPerBlock)
throw new BadBlockchainException("number of commited transactions is not a multiple of "+nTransactionsPerBlock);
for(int j=1; j<=nb; j++) {
Block b = chainOfBlocks.get(j);
int from = (j-1)*nTransactionsPerBlock, to = from + nTransactionsPerBlock;
List<Transaction> tl = committedTransactions.subList(from, to);
Transaction[] tt = new Transaction[nTransactionsPerBlock];
tt = tl.toArray(tt);
if(!b.data.equals(Transaction.combinedDigest(tt)))
throw new BadBlockchainException("The data digest in a block doesn't match the transactions"+b);
}
}
private void checkBlockchain() throws BadBlockchainException {
Block prev = null;
for(Block crt: chainOfBlocks) {
crt.checkValidity(difficulty, prev);
prev = crt;
}
}
public static void checkFullStory(List<Transaction> ts) throws BadTransactionException {
BolivarBank tb = new BolivarBank();
tb.runFullStory(ts);
}
/** Returns the current state of the "machine" or
* throws an exception if anything is invalid */
public BolivarBank bank() throws BadTransactionException, BadBlockchainException {
throw new UnsupportedOperationException(); // TODO
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for(Block b: chainOfBlocks) {
sb.append("Block: \n").append(b.toReadableString()).append("\n");
}
return sb.toString();
}
}
package s29;
import java.security.KeyPair;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class BolivarTestJU {
KeyPair john, kurt, mary;
String johnAccount, kurtAccount, maryAccount;
@Before
public void prepareThreeAccounts() {
john = CryptoUtils.newRsaKeyPair();
kurt = CryptoUtils.newRsaKeyPair();
mary = CryptoUtils.newRsaKeyPair();
johnAccount = CryptoUtils.stringFromPublicKey(john.getPublic());
kurtAccount = CryptoUtils.stringFromPublicKey(kurt.getPublic());
maryAccount = CryptoUtils.stringFromPublicKey(mary.getPublic());
}
@Test(expected=BadTransactionException.class)
public void signedByWrongPerson() throws BadTransactionException, BadBlockchainException {
BolivarBlockchainV2 bbc = new BolivarBlockchainV2(3, 1);
MoneyTransfer johnToMary = new MoneyTransfer(1, johnAccount, maryAccount);
Transaction tr0 = Transaction.signedTransaction(johnToMary, 0, mary.getPrivate());
bbc.handleNewTransaction(tr0);
System.out.println("oops " + bbc.bank());
}
@Test
public void aCoupleOfValidTransactions() throws BadTransactionException, BadBlockchainException {
BolivarBlockchainV2 bbc = new BolivarBlockchainV2(3, 1);
MoneyTransfer johnToKurt = new MoneyTransfer(7, johnAccount, kurtAccount);
MoneyTransfer johnToMary1 = new MoneyTransfer(8, johnAccount, maryAccount);
MoneyTransfer maryToKurt = new MoneyTransfer(3, maryAccount, kurtAccount);
MoneyTransfer johnToMary2 = new MoneyTransfer(6, johnAccount, maryAccount);
MoneyTransfer kurtToMary = new MoneyTransfer(5, kurtAccount, maryAccount);
MoneyTransfer johnToMary3 = new MoneyTransfer(4, johnAccount, maryAccount);
List<Transaction> tl = List.of(
Transaction.signedTransaction(johnToKurt, 0, john.getPrivate()),
Transaction.signedTransaction(johnToMary1, 1, john.getPrivate()),
Transaction.signedTransaction(maryToKurt, 0, mary.getPrivate()),
Transaction.signedTransaction(johnToMary2, 2, john.getPrivate()),
Transaction.signedTransaction(kurtToMary, 0, kurt.getPrivate()),
Transaction.signedTransaction(johnToMary3, 3, john.getPrivate())
);
for(Transaction t: tl) {
bbc.handleNewTransaction(t);
}
BolivarBank bank = bbc.bank();
assertEquals( 75, bank.moneyOf(johnAccount));
assertEquals(105, bank.moneyOf(kurtAccount));
assertEquals(120, bank.moneyOf(maryAccount));
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment