Commit 19dd4221 authored by Michel Schudel's avatar Michel Schudel

stripped solution from master branch.

parent 8ab8f875
......@@ -31,7 +31,8 @@ public class CraftsCoinRestController {
*/
@PostMapping("/api/newtransaction")
public String newTransaction(@RequestBody Transaction transaction) {
long l = blockchainService.createTransaction(transaction.getFrom(), transaction.getTo(), transaction.getAmount());
//call createTransaction on blockchainserviceimplement me
long l = blockchainService.createTransaction(null,null,null);
return "{\"message\": \"new transaction will be added to block " + l + "\"}";
}
......
package nl.craftsmen.blockchain.craftscoinnode.blockchain;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import nl.craftsmen.blockchain.craftscoinnode.transaction.Transaction;
import java.util.HashSet;
import java.util.Set;
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
public class Block {
private long index;
private long timestamp;
private Set<Transaction> transactions;
private long proof;
private String previousHash;
//add fields here
//default constructor needed for json deserialization
@SuppressWarnings({"unused", "WeakerAccess"})
public Block() {
}
Block(long index, long timestamp, Set<Transaction> transactions, long proof, String previousHash) {
this.index = index;
this.timestamp = timestamp;
this.transactions = new HashSet<>(transactions);
this.proof = proof;
this.previousHash = previousHash;
}
public long getIndex() {
return index;
}
//add getters, setters and constructor here
public long getProof() {
return proof;
}
public long getTimestamp() {
return timestamp;
}
public Set<Transaction> getTransactions() {
return transactions;
}
@Override
public String toString() {
return "Block{" +
"index=" + index +
", timestamp=" + timestamp +
", transactions=" + transactions +
", proof=" + proof +
", previousHash='" + previousHash + '\'' +
'}';
}
public String getPreviousHash() {
return previousHash;
}
}
......@@ -4,9 +4,9 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import nl.craftsmen.blockchain.craftscoinnode.transaction.Transaction;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* Implementation of the blockchain.
......@@ -14,7 +14,6 @@ import java.util.stream.Collectors;
@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, isGetterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
public class Blockchain {
private List<Block> chain = new ArrayList<>();
/**
* Factory method to create a new blockchain.
......@@ -22,12 +21,8 @@ public class Blockchain {
* @return a new blockchain containing a genesis block.
*/
public static Blockchain create() {
Blockchain blockchain = new Blockchain();
Block block = new Block(0, Instant
.now()
.toEpochMilli(), Collections.emptySet(), 100, "1");
blockchain.addBlock(block);
return blockchain;
//implement me
return null;
}
//default constructor, needed for json deserialization
......@@ -43,12 +38,8 @@ public class Blockchain {
* @return the new block.
*/
public Block mineNewBlock(Set<Transaction> transactionsToBeIncluded) {
String previousHash = HashUtil.hash(this.getLastBlock());
Block block = new Block(getIndexOfLastBlock() + 1, Instant
.now()
.toEpochMilli(), transactionsToBeIncluded, this.proofOfWork(), previousHash);
chain.add(block);
return block;
//implement me
return null;
}
/**
......@@ -57,7 +48,7 @@ public class Blockchain {
* @param block the block to be added.
*/
public void addBlock(Block block) {
chain.add(block);
//implement me
}
......@@ -67,30 +58,8 @@ public class Blockchain {
* @return index of the block height of the next block.
*/
public long getIndexOfNextBlock() {
return getIndexOfLastBlock() + 1;
}
private long getIndexOfLastBlock() {
Block block = getLastBlock();
return block != null ? block.getIndex() : -1;
}
/**
* Gets the most recent block in the blockchain.
*
* @return the most recent block in the blockchain.
*/
private Block getLastBlock() {
return chain.get(chain.size() - 1);
}
/**
* Returns the blockheight.
*
* @return the blockheight.
*/
private long getBlockHeight() {
return chain.size();
//implement me
return 0;
}
/**
......@@ -99,13 +68,8 @@ public class Blockchain {
* @return all transactions in the blockchain.
*/
public List<Transaction> getAllTransactions() {
return this
.chain
.stream()
.flatMap(block -> block
.getTransactions()
.stream()
).collect(Collectors.toList());
//implement me
return Collections.emptyList();
}
/**
......@@ -115,15 +79,8 @@ public class Blockchain {
* @return transactions in the blockchain for a specific wallet.
*/
public List<Transaction> getTransactionsFor(String walletId) {
return this
.chain
.stream()
.flatMap(block -> block
.getTransactions()
.stream())
.filter(transaction -> transaction.hasParticipant(walletId)
).collect(Collectors.toList());
//implement me
return Collections.emptyList();
}
/**
......@@ -133,15 +90,9 @@ public class Blockchain {
* @return if this blockchain is valid.
*/
public boolean isValid() {
for (int i = chain.size() - 1; i >= 1; i--) {
if (!chain.get(i).getPreviousHash().equals(HashUtil.hash(chain.get(i - 1)))) {
return false;
}
if (!validProof(chain.get(i - 1).getProof(), chain.get(i).getProof())) {
return false;
}
}
//implement me
return true;
}
/**
......@@ -152,8 +103,8 @@ public class Blockchain {
* @return true if the new block is valid, false otherwise.
*/
public boolean isNewBlockValid(Block newBlock) {
Block lastBlock = getLastBlock();
return lastBlock == null || newBlock.getPreviousHash().equals(HashUtil.hash(lastBlock)) && validProof(lastBlock.getProof(), newBlock.getProof());
//implement me
return true;
}
/**
......@@ -163,29 +114,14 @@ public class Blockchain {
* - p is the previous proof, and p' is the new proof
*/
private long proofOfWork() {
long lastProof = getLastBlock().getProof();
long currentProof = 0;
while (!validProof(lastProof, currentProof)) {
currentProof++;
}
return currentProof;
}
private boolean validProof(long previousProof, long currentProof) {
String hash = HashUtil.createHash(previousProof + "" + currentProof);
return hash.startsWith("0000");
//implement me
return 0;
}
public boolean isInferiorTo(Blockchain otherChain) {
return ((otherChainIsHigher(otherChain) || otherChainIsOlder(otherChain)) && otherChain.isValid());
//implement me
return false;
}
private boolean otherChainIsOlder(Blockchain otherChain) {
return Objects.requireNonNull(otherChain.getLastBlock()).getTimestamp() < this.getLastBlock().getTimestamp();
}
private boolean otherChainIsHigher(Blockchain otherChain) {
return otherChain.getBlockHeight() > this.getBlockHeight();
}
}
......@@ -13,7 +13,6 @@ import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
......@@ -49,19 +48,7 @@ public class BlockchainService {
*/
@PostConstruct
public void init() {
network.connectToNetwork();
initializeBlockchain();
reachConsensus();
}
private void initializeBlockchain() {
if (this.blockchain == null) {
this.blockchain = blockchainRepository.loadBlockChain();
if (this.blockchain == null) {
this.blockchain = Blockchain.create();
blockchainRepository.saveBlockChain(this.blockchain);
}
}
//implement me
}
/**
......@@ -70,7 +57,8 @@ public class BlockchainService {
* @return the blockchain of this node.
*/
public Blockchain retrieveBlockChain() {
return this.blockchain;
//implement me
return null;
}
/**
......@@ -82,11 +70,8 @@ public class BlockchainService {
* @return the block height of the block that this transaction will be mined in.
*/
public long createTransaction(String from, String to, BigDecimal amount) {
LOGGER.info("creating new transaction: from: {}, to: {}, amount: {}", from, to, amount);
Transaction transaction = new Transaction(from, to, amount);
transactionPool.addTransaction(transaction);
network.notifyPeersOfNewTransaction(transaction, instanceInfo.getNode());
return this.blockchain.getIndexOfNextBlock();
//implement me
return 0;
}
/**
......@@ -95,7 +80,8 @@ public class BlockchainService {
* @return the pending transactions from the transaction pool.
*/
public Set<Transaction> getPendingTransactions() {
return Collections.unmodifiableSet(transactionPool.getAllTransactions());
//implement me
return Collections.emptySet();
}
/**
......@@ -104,17 +90,8 @@ public class BlockchainService {
* @return the new block that has just been mined.
*/
public Block mine() {
if (this.transactionPool.getAllTransactions().isEmpty()) {
throw new RuntimeException("no pending transactions, nothing to mine.");
}
//reward the miner
Transaction transaction = new Transaction("0", miningWalletId, CRAFTSCOIN_MINING_REWARD);
transactionPool.addTransaction(transaction);
Block newBlock = this.blockchain.mineNewBlock(transactionPool.getAllTransactions());
blockchainRepository.saveBlockChain(this.blockchain);
transactionPool.clearTransactions();
network.notifyPeersOfNewBlock(newBlock, null);
return newBlock;
//implement me
return null;
}
/**
......@@ -122,18 +99,7 @@ public class BlockchainService {
* If another node has a blockchain that is 'better', the blockchain of the current node will be replaced.
*/
private void reachConsensus() {
List<Blockchain> otherChains = network.retrieveBlockchainsFromPeers();
LOGGER.info("blockchains from peers received. Checking...");
for (Blockchain otherChain : otherChains) {
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();
blockchainRepository.saveBlockChain(blockchain);
break;
}
}
//implement me
}
/**
......@@ -145,11 +111,7 @@ public class BlockchainService {
*/
public void newTransactionReceived(Transaction transaction, String sourcePeer) {
LOGGER.info("received transaction: {} from source peer {}", transaction, sourcePeer);
if (!transactionPool.getAllTransactions().contains(transaction)) {
LOGGER.info("transaction {} is new, adding it to the list of pending transactions.", transaction);
transactionPool.addTransaction(transaction);
network.notifyPeersOfNewTransaction(transaction, sourcePeer);
}
//implement me
}
/**
......@@ -160,31 +122,18 @@ public class BlockchainService {
*/
public void newBlockReceived(Block block, String sourcePeer) {
LOGGER.info("received new block: {}", block);
if (blockchain.isNewBlockValid(block)) {
LOGGER.info("block is valid, adding it to the blockchain.");
this.blockchain.addBlock(block);
this.network.notifyPeersOfNewBlock(block, sourcePeer);
blockchainRepository.saveBlockChain(blockchain);
clearConfirmedTransactions();
} else {
LOGGER.info("block is not valid with respect to my blockchain, discarding.");
}
//implement me
}
private void clearConfirmedTransactions() {
LOGGER.info("removing all confirmed transactions from the transaction pool");
transactionPool.clearTransactions(blockchain.getAllTransactions());
}
/**
* Returns if the blockchain on this node is valid.
*
* @return if the blockchain on this node is valid.
*/
public boolean isValid() {
return this.blockchain.isValid();
//implement me
return false;
}
}
......@@ -2,16 +2,11 @@ package nl.craftsmen.blockchain.craftscoinnode.transaction;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import java.math.BigDecimal;
import java.util.UUID;
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
public class Transaction {
private UUID id;
private String from;
private String to;
private BigDecimal amount;
//implement fields
//default public constructor, needed for json deserialization
@SuppressWarnings({"unused", "WeakerAccess"})
......@@ -19,60 +14,6 @@ public class Transaction {
}
public Transaction(String from, String to, BigDecimal amount) {
this.id = UUID.randomUUID();
this.to = to;
this.from = from;
this.amount = amount;
}
public String getFrom() {
return from;
}
public String getTo() {
return to;
}
public BigDecimal getAmount() {
return amount;
}
//implement getters, setters, constructor
public boolean hasParticipant(String walletId) {
return isRecepient(walletId) || isSender(walletId);
}
public boolean isRecepient(String walletId) {
return to.equals(walletId);
}
public boolean isSender(String walletId) {
return from.equals(walletId);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Transaction that = (Transaction) o;
return id != null ? id.equals(that.id) : that.id == null;
}
@Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
@Override
public String toString() {
return "Transaction{" +
"id=" + id +
", from='" + from + '\'' +
", to='" + to + '\'' +
", amount=" + amount +
'}';
}
}
......@@ -6,7 +6,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
......@@ -18,14 +17,12 @@ public class TransactionPool {
private static final Logger LOGGER = LoggerFactory.getLogger(BlockchainService.class);
private Set<Transaction> transactions = new HashSet<>();
/**
* Add a new transaction to this pool.
* @param transaction the transaction.
*/
public void addTransaction(Transaction transaction) {
transactions.add(transaction);
//implement me
LOGGER.info("transaction {} has been added to the pool", transaction);
}
......@@ -33,7 +30,7 @@ public class TransactionPool {
* Removes all transactions from the pool.
*/
public void clearTransactions() {
transactions.clear();
//implement me
LOGGER.info("all transactions have been purged.");
}
......@@ -42,7 +39,7 @@ public class TransactionPool {
* @param transactions the supplied transactions list.
*/
public void clearTransactions(List<Transaction> transactions) {
this.transactions.removeAll(transactions);
//implement me
LOGGER.info("the following transactions have been purged: {}", transactions);
}
......@@ -51,6 +48,7 @@ public class TransactionPool {
* @return sll transactions from the pool.
*/
public Set<Transaction> getAllTransactions() {
return Collections.unmodifiableSet(transactions);
//implement me
return Collections.emptySet();
}
}
package nl.craftsmen.blockchain.craftscoinnode.wallet;
import nl.craftsmen.blockchain.craftscoinnode.transaction.Transaction;
import java.math.BigDecimal;
import java.util.List;
public class Wallet {
private BigDecimal balance;
private List<Transaction> minedTransactions;
private List<Transaction> unconfirmedTransactions;
Wallet(BigDecimal balance, List<Transaction> minedTransactions, List<Transaction> unconfirmedTransactions) {
this.balance = balance;
this.minedTransactions = minedTransactions;
this.unconfirmedTransactions = unconfirmedTransactions;
}
public BigDecimal getBalance() {
return balance;
}
public List<Transaction> getMinedTransactions() {
return minedTransactions;
}
//implement me
public List<Transaction> getUnconfirmedTransactions() {
return unconfirmedTransactions;
}
}
package nl.craftsmen.blockchain.craftscoinnode.wallet;
import nl.craftsmen.blockchain.craftscoinnode.blockchain.BlockchainService;
import nl.craftsmen.blockchain.craftscoinnode.transaction.Transaction;
import nl.craftsmen.blockchain.craftscoinnode.transaction.TransactionPool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
@Component
public class WalletService {
......@@ -28,27 +23,8 @@ public class WalletService {
* @return information about the wallet.
*/
public Wallet getWallet(String walletId) {
BigDecimal balance = BigDecimal.ZERO;
List<Transaction> unconfirmedTransactions = new ArrayList<>();
List<Transaction> confirmedTransactions = blockchainService.retrieveBlockChain().getTransactionsFor(walletId);
for (Transaction transaction : confirmedTransactions) {
if (transaction.isRecepient(walletId)) {
balance = balance.add(transaction.getAmount());
} else if (transaction.isSender(walletId)) {
balance = balance.subtract(transaction.getAmount());
}
}
//unconfirmed transactions
for (Transaction transaction : transactionPool.getAllTransactions()) {
if (!confirmedTransactions.contains(transaction) && transaction.getTo().equals(walletId)) {
balance = balance.add(transaction.getAmount());
unconfirmedTransactions.add(transaction);
} else if (!confirmedTransactions.contains(transaction) && transaction.getFrom().equals(walletId)) {
balance = balance.subtract(transaction.getAmount());
unconfirmedTransactions.add(transaction);
}
}
return new Wallet(balance, confirmedTransactions, unconfirmedTransactions);
//implement me
return null;
}
}
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