Commit 0f3f9018 authored by Michel Schudel's avatar Michel Schudel

refactored more into the blockchain.

parent 707d08ca
......@@ -183,24 +183,31 @@ BitCoin gebruikt het HashCash algoritme, wat erg lijkt op bovenstaande algoritme
Nu we een functie hebben gemaakt om het nieuwe proof of work te vinden, is het tijd om een nieuw block te maken.
Implementeer de `mine()` method op de `BlockChainService` class als volgt:
Implementeer de `mineNewBlock(..)` method op de `Blockchain` class, als volgt:
- Bepaal het nieuwe proof-of-work met de method `proofOfWork` die je net geimplementeerd hebt.
- Voeg een nieuw block aan de blockchain toe door de functie `createNewBlock` op de `Blockchain` class te implementeren, en die aan te roepen. Het nieuwe block moet er uiteindelijk als volgt uitzien:
- `index` (long) -> index van het meest recente block in de blockchain + 1.
- `timestamp` (long) -> nu
- lijst van alle transacties in de transactie pool, *plus een reward transactie*:
- `from`: null of "", er is immers geen afzender.
- `to`: gebruik hier het `miningWalletId` veld.
- `amount`: 10
- lijst van transacties (method parameter)
- `previousHash` (string). De hash van het meest recente block. De hash mag je berekenen over de string representatie van dat block. Hiervoor is een utility method in de `HashUtil` class aanwezig: `String hash(Block block)`
- `proof` (long). Het nieuwe proof-of-work.
- Maak de transaction pool leeg middels implementatie van de `clearTransactions()` functie op de `TransactionPool` class. Alle transacties staan nu immers in het nieuwe block.
Implementeer de `mine()` method op de `BlockChainService` bean als volgt:
- Verzamel alle transacties in de transaction pool, plus de volgende, nieuwe, generation transactie:
- `from`: null of "", er is immers geen afzender.
- `to`: gebruik hier het `miningWalletId` veld (jezelf).
- `amount`: 10
- Roep de `mineNewBlock` method op de `Blockchain` class aan die je net hebt gemaakt met de lijst van transacties;
Maak de transaction pool leeg middels implementatie van de `clearTransactions()` functie op de `TransactionPool` class. Alle transacties staan nu immers in het nieuwe block.
Om deze functionaliteit te testen:
- Voeg een transactie toe middels de UI of een POST naar http://localhost:8080/api/newtransaction
......
......@@ -5,10 +5,7 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import nl.craftsmen.blockchain.craftscoinnode.transaction.Transaction;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
/**
......@@ -19,14 +16,16 @@ public class Blockchain {
private List<Block> chain = new ArrayList<>();
/**
* Factory method to create a new blockchain.
* @return a new blockchain containing a genesis block.
*/
public static Blockchain create() {
Blockchain blockchain = new Blockchain();
blockchain.createNewBlock(100, "1", Collections.emptySet());
Block block = new Block(0, Instant
.now()
.toEpochMilli(), Collections.emptySet(), 100, "1");
blockchain.addBlock(block);
return blockchain;
}
......@@ -35,18 +34,16 @@ public class Blockchain {
public Blockchain() {
}
/**
* Creates a new block.
* @param proof proof-of-work of this new block.
* @param previousHash the hash of the previous block.
/**
* Mines a new block.
* @param transactionsToBeIncluded the transactions the be included in the block.
* @return the new block.
*/
public Block createNewBlock(long proof, String previousHash, Set<Transaction> transactionsToBeIncluded) {
public Block mineNewBlock(Set<Transaction> transactionsToBeIncluded) {
String previousHash = HashUtil.hash(this.getLastBlock());
Block block = new Block(getIndexOfLastBlock() + 1, Instant
.now()
.toEpochMilli(), transactionsToBeIncluded, proof, previousHash);
.toEpochMilli(), transactionsToBeIncluded, this.proofOfWork(),previousHash);
chain.add(block);
return block;
}
......@@ -77,15 +74,15 @@ public class Blockchain {
* Gets the most recent block in the blockchain.
* @return the most recent block in the blockchain.
*/
public Block getLastBlock() {
return chain.size() == 0 ? null : chain.get(chain.size() - 1);
private Block getLastBlock() {
return chain.get(chain.size() - 1);
}
/**
* Returns the blockheight.
* @return the blockheight.
*/
public long getBlockHeight() {
private long getBlockHeight() {
return chain.size();
}
......@@ -143,13 +140,13 @@ public class Blockchain {
*/
public boolean isNewBlockValid(Block newBlock) {
Block lastBlock = getLastBlock();
return newBlock.getPreviousHash().equals(HashUtil.hash(lastBlock)) && validProof(lastBlock.getProof(), newBlock.getProof());
return lastBlock == null || newBlock.getPreviousHash().equals(HashUtil.hash(lastBlock)) && validProof(lastBlock.getProof(), newBlock.getProof());
}
/**
* Find the proof of work for the next block.
*/
public long proofOfWork() {
private long proofOfWork() {
long lastProof = getLastBlock().getProof();
/*Simple Proof of Work Algorithm:
- Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
......@@ -166,4 +163,15 @@ public class Blockchain {
return hash.startsWith("0000");
}
public boolean isInferiorTo(Blockchain otherChain) {
return ((otherChainIsHigher(otherChain) || otherChainIsOlder(otherChain)) && otherChain.isValid());
}
private boolean otherChainIsOlder(Blockchain otherChain) {
return Objects.requireNonNull(otherChain.getLastBlock()).getTimestamp() < this.getLastBlock().getTimestamp();
}
private boolean otherChainIsHigher(Blockchain otherChain) {
return otherChain.getBlockHeight() > this.getBlockHeight();
}
}
......@@ -103,13 +103,10 @@ public class BlockchainService {
if (this.transactionPool.getAllTransactions().isEmpty()) {
throw new RuntimeException("no pending transactions, nothing to mine.");
}
long newProof = blockchain.proofOfWork();
//reward the miner
Transaction transaction = new Transaction("0", miningWalletId, CRAFTSCOIN_MINING_REWARD);
transactionPool.addTransaction(transaction);
String previousHash = HashUtil.hash(this.blockchain.getLastBlock());
Block newBlock = this.blockchain.createNewBlock(newProof, previousHash, transactionPool.getAllTransactions());
Block newBlock = this.blockchain.mineNewBlock(transactionPool.getAllTransactions());
blockchainRepository.saveBlockChain(this.blockchain);
transactionPool.clearTransactions();
network.notifyPeersOfNewBlock(newBlock, null);
......@@ -124,7 +121,7 @@ public class BlockchainService {
LOGGER.info("blockchains from peers received. Checking...");
for (Blockchain otherChain : otherChains) {
if (this.blockchain == null || ((otherChainIsHigher(otherChain) || otherChainIsOlder(otherChain)) && otherChain.isValid())) {
if (this.blockchain == null || this.blockchain.isInferiorTo(otherChain)) {
LOGGER.info("received a blockchain that is better than my currect chain. Replacing current chain.");
this.blockchain = otherChain;
clearConfirmedTransactions();
......@@ -134,14 +131,6 @@ public class BlockchainService {
}
}
private boolean otherChainIsOlder(Blockchain otherChain) {
return otherChain.getLastBlock().getTimestamp() < this.blockchain.getLastBlock().getTimestamp();
}
private boolean otherChainIsHigher(Blockchain otherChain) {
return otherChain.getBlockHeight() > this.blockchain.getBlockHeight();
}
/**
* Adds a newly received transaction to the pool and propagates it further into the network.
* @param transaction the new transaction.
......
Markdown is supported
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