Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
SlideShare a Scribd company logo
Let’s build a blockchain... in 40 minutes!
@MichelSchudel
michel@craftsmen.nl
Amsterdam | April 2-3, 2019
Let's build a blockchain.... in 40 minutes!
Let's build a blockchain.... in 40 minutes!
Let's build a blockchain.... in 40 minutes!
Let's build a blockchain.... in 40 minutes!
transactiontransaction
Central
authority
Ledger
transactiontransaction
transaction
transation
Distributed
ledger
Distributed
ledger
Distributed
ledger
Distributed
ledger
@MichelSchudel
1. A Blockchain is an implementation of a distributed ledger
t1t2t3
t1t2t3
t1t2t3
t1t2t3
t1t2t3
t1t2t4
@MichelSchudel
2. A Blockchain is an sequential, immutable chain of records
called Blocks
Block
transactiontransactiontransaction
Block
transactiontransactiontransaction
Block
transactiontransactiontransaction
@MichelSchudel
index : 2
previous hash
payload
transaction
transaction
transaction
3. Immutability is implemented by hashing
index : 1
previous hash: 0
Genesis block
transaction
index : 3
previous hash
payload
transaction
transaction
transaction
@MichelSchudel
Let’s build a Blockchain, then!
@MichelSchudel
Let’s build a Blockchain, then!
BlockchainRestController
Blockchain TransactionPool
BlockBlockBlockBlock
TransactionTransactionTransactionTransaction
Manages Manages
Has Has
API
GET /api/blockchain
POST /api/createtransaction
GET /api/pendingtransactions
POST /api/mine
Network
Interacts
with
@MichelSchudel
Step 1: Create the initial blockchain
index : 1
previous hash: 0
Genesis block
@MichelSchudel
Kudo’s (from, to, kudos)
Pool of transactions
Out of scope:
• Transaction integrity (signing)
• Transaction inputs and outputs
Transaction pool
transaction
transaction
transaction
Step 2: Create something to store in
the blocks
@MichelSchudel
• New block should contain hash of
previous block (immutability, trust)
• Creating a block requires proof-of-
work / stake (supports consensus)
• Creating a block should give a reward
(incentive, generation transaction)
index : 2
previous hash
payload
transaction
transaction
transaction
index : 1
previous hash: 0
Genesis block
Step 3: making (mining) a new block
@MichelSchudel
Proof-of-work
• It should be hard to create a new
block
• Makes cheating unattractive
• It should be easy to verify a new
block
@MichelSchudel
Remember this Nonce thingy?
“(new block)” “00005c3d2d...”SHA256 hash
“(new block with nonce x)” “00005c3df8...”SHA256 hash
X = 100
Creating a proof-of-work (hard)
Verifying proof-of-work (easy)
@MichelSchudel
• The longest blockchain that is valid “wins”
• A blockchain is valid when
• Previous hash field of each block matches hash of previous block
• Proof-of-work (nonce) is verified and correct for each block
Step 4: consensus with other nodes
@MichelSchudel
Step 5: Implementing decentralization
• Transactions are propagated
• Everybody should have the chance to mine
• Blocks are propagated
• Validation is performed before accepting
• This could prevent downloading all chains
@MichelSchudel
Summary
We created a blockchain in 40 minutes with:
• Blocks
• Transactions
• Mining
• Reaching consensus
• Propagation
Now go and build one yourself!
https://gitlab.com/craftsmen/workshop-blockchain
@MichelSchudel
https://gitlab.com/craftsmen/workshop-blockchain
@MichelSchudel
michel@craftsmen.nl
Code slides
(in case you didn’t see the demo)
Create the block structure
public class Block {
private long index;
private Set<Transaction> transactions = new HashSet<>();
private String previousHash;
private long nonce;
…getters, setters, toString etc.
}
Making the initial chain
public class Blockchain {
private LinkedList<Block> blocks = new LinkedList<>();
static Blockchain create() {
Blockchain blockchain = new Blockchain();
Block block = new Block();
block.setIndex(1);
block.setPreviousHash("0");
block.setNonce(0);
blockchain.blocks.add(block);
return blockchain;
}
}
Creating a transaction
public class Transaction {
private String id;
private String from;
private String to;
private int kudos;
..getters, setters…
… equals and hashcode based on id only!
}
Creating a transaction pool
public class TransactionPool {
private Set<Transaction> transactions = new HashSet<>();
public void addTransaction(Transaction transaction) {
transactions.add(transaction);
}
public void clearTransactions() {
transactions.clear();
}
public Set<Transaction> getAllTransactions() {
return new HashSet<>(transactions);
}
}
Creating a transaction
@PostMapping("/api/createtransaction")
public long createTransaction(@RequestBody Transaction transaction) {
//give the transaction an id
transaction.setId(UUID.randomUUID().toString());
//add the transaction to the pool
transactionPool.addTransaction(transaction);
//return the height of the next block
return blockchain.height() + 1;
}
Mining a new block
@PostMapping("/api/mine")
public Block mine() {
Block block = getBlockchain().mine(transactionPool.getAllTransactions());
transactionPool.clearTransactions();
return block;
}
Mining a new block
public class Blockchain {
...
public Block mine(Set<Transaction> allTransactions) {
Block block = new Block();
block.setIndex(this.blocks.size() + 1);
block.setPreviousHash(DigestUtils.sha256Hex(blocks.getLast().toString()));
block.setTransactions(allTransactions);
//create reward
Transaction reward = new Transaction();
reward.setId(UUID.randomUUID().toString());
reward.setFrom("");
reward.setTo(“Michel for creating this block");
reward.setKudos(3);
allTransactions.add(reward);
block.calculateProofOfWork();
blocks.add(block);
return block;
}
}
Proof of work
public class Block {
…
public void calculateProofOfWork() {
this.nonce = 0;
while (!DigestUtils.sha256Hex(this.toString()).startsWith("0000")) {
this.nonce++;
}
}
}
Comparing with other blockchains
In your service…
public void init() {
this.blockchain = Blockchain.create();
this.blockchain = network.retrieveBlockchainsFromPeers()
.stream()
.filter(b -> b.isValid())
.filter(b -> b.height() > this.blockchain.height())
.max(Comparator.comparing(Blockchain::height))
.orElse(this.blockchain);
}
Comparing with other blockchains
public boolean isValid() {
for (int i = blocks.size() - 1; i > 0; i--) {
Block currentBlock = blocks.get(i);
Block previousBlock = blocks.get(i - 1);
if (!previousHashMatches(previousBlock, currentBlock)) {
System.out.println("previous hash doesn't match!");
return false;
}
if (!currentBlock.isValid()) {
System.out.println("proof of work is invalid");
return false;
}
}
return true;
}
private boolean previousHashMatches(Block previousBlock, Block currentBlock) {
return currentBlock.getPreviousHash()
.equals(DigestUtils.sha256Hex(previousBlock.toString()));
}
Comparing with other blockchains
public class Block {
…
boolean isValid() {
return DigestUtils.sha256Hex(this.toString()).startsWith("0000");
}
…
}
Propagating transactions
@PostMapping("/api/createtransaction")
public long createTransaction(@RequestBody Transaction transaction) {
…create transaction…
network.notifyPeersOfNewTransaction(transaction);
}
Receiving transactions from the network
@PostMapping("/api/addtransaction")
public void newTransactionReceived(@RequestBody Transaction transaction) {
if (!transactionPool.getAllTransactions().contains(transaction)) {
transactionPool.addTransaction(transaction);
network.notifyPeersOfNewTransaction(transaction);
}
}
Propagating blocks
@PostMapping("/api/mine")
public Block mine() {
Block block = getBlockchain().mine(transactionPool.getAllTransactions());
transactionPool.clearTransactions();
//propgate transaction
network.notifyPeersOfNewBlock(block);
return block;
}
Receiving blocks from the network
@PostMapping("/api/addblock")
public void newBlockReceived(@RequestBody Block block) {
//only add block if it is valid
if (blockchain.isValid(block)) {
blockchain.addBlock(block);
//clear all transactions that are already in the block
transactionPool.clearTransactions(block.getTransactions());
//propagate block through the network
network.notifyPeersOfNewBlock(block);
}
}
Receiving blocks from the network
public class Blockchain {
...
private boolean previousHashMatches(Block previousBlock, Block currentBlock) {
return currentBlock.getPreviousHash()
.equals(DigestUtils.sha256Hex(previousBlock.toString()));
}
public boolean isValid(Block block) {
return block.isValid() && previousHashMatches(blocks.getLast(), block);
}
public void addBlock(Block block) {
blocks.add(block);
}
}

More Related Content

Let's build a blockchain.... in 40 minutes!

  • 1. Let’s build a blockchain... in 40 minutes! @MichelSchudel michel@craftsmen.nl Amsterdam | April 2-3, 2019
  • 7. 1. A Blockchain is an implementation of a distributed ledger t1t2t3 t1t2t3 t1t2t3 t1t2t3 t1t2t3 t1t2t4 @MichelSchudel
  • 8. 2. A Blockchain is an sequential, immutable chain of records called Blocks Block transactiontransactiontransaction Block transactiontransactiontransaction Block transactiontransactiontransaction @MichelSchudel
  • 9. index : 2 previous hash payload transaction transaction transaction 3. Immutability is implemented by hashing index : 1 previous hash: 0 Genesis block transaction index : 3 previous hash payload transaction transaction transaction @MichelSchudel
  • 10. Let’s build a Blockchain, then! @MichelSchudel
  • 11. Let’s build a Blockchain, then! BlockchainRestController Blockchain TransactionPool BlockBlockBlockBlock TransactionTransactionTransactionTransaction Manages Manages Has Has API GET /api/blockchain POST /api/createtransaction GET /api/pendingtransactions POST /api/mine Network Interacts with @MichelSchudel
  • 12. Step 1: Create the initial blockchain index : 1 previous hash: 0 Genesis block @MichelSchudel
  • 13. Kudo’s (from, to, kudos) Pool of transactions Out of scope: • Transaction integrity (signing) • Transaction inputs and outputs Transaction pool transaction transaction transaction Step 2: Create something to store in the blocks @MichelSchudel
  • 14. • New block should contain hash of previous block (immutability, trust) • Creating a block requires proof-of- work / stake (supports consensus) • Creating a block should give a reward (incentive, generation transaction) index : 2 previous hash payload transaction transaction transaction index : 1 previous hash: 0 Genesis block Step 3: making (mining) a new block @MichelSchudel
  • 15. Proof-of-work • It should be hard to create a new block • Makes cheating unattractive • It should be easy to verify a new block @MichelSchudel
  • 16. Remember this Nonce thingy? “(new block)” “00005c3d2d...”SHA256 hash “(new block with nonce x)” “00005c3df8...”SHA256 hash X = 100 Creating a proof-of-work (hard) Verifying proof-of-work (easy) @MichelSchudel
  • 17. • The longest blockchain that is valid “wins” • A blockchain is valid when • Previous hash field of each block matches hash of previous block • Proof-of-work (nonce) is verified and correct for each block Step 4: consensus with other nodes @MichelSchudel
  • 18. Step 5: Implementing decentralization • Transactions are propagated • Everybody should have the chance to mine • Blocks are propagated • Validation is performed before accepting • This could prevent downloading all chains @MichelSchudel
  • 19. Summary We created a blockchain in 40 minutes with: • Blocks • Transactions • Mining • Reaching consensus • Propagation Now go and build one yourself! https://gitlab.com/craftsmen/workshop-blockchain @MichelSchudel
  • 21. Code slides (in case you didn’t see the demo)
  • 22. Create the block structure public class Block { private long index; private Set<Transaction> transactions = new HashSet<>(); private String previousHash; private long nonce; …getters, setters, toString etc. }
  • 23. Making the initial chain public class Blockchain { private LinkedList<Block> blocks = new LinkedList<>(); static Blockchain create() { Blockchain blockchain = new Blockchain(); Block block = new Block(); block.setIndex(1); block.setPreviousHash("0"); block.setNonce(0); blockchain.blocks.add(block); return blockchain; } }
  • 24. Creating a transaction public class Transaction { private String id; private String from; private String to; private int kudos; ..getters, setters… … equals and hashcode based on id only! }
  • 25. Creating a transaction pool public class TransactionPool { private Set<Transaction> transactions = new HashSet<>(); public void addTransaction(Transaction transaction) { transactions.add(transaction); } public void clearTransactions() { transactions.clear(); } public Set<Transaction> getAllTransactions() { return new HashSet<>(transactions); } }
  • 26. Creating a transaction @PostMapping("/api/createtransaction") public long createTransaction(@RequestBody Transaction transaction) { //give the transaction an id transaction.setId(UUID.randomUUID().toString()); //add the transaction to the pool transactionPool.addTransaction(transaction); //return the height of the next block return blockchain.height() + 1; }
  • 27. Mining a new block @PostMapping("/api/mine") public Block mine() { Block block = getBlockchain().mine(transactionPool.getAllTransactions()); transactionPool.clearTransactions(); return block; }
  • 28. Mining a new block public class Blockchain { ... public Block mine(Set<Transaction> allTransactions) { Block block = new Block(); block.setIndex(this.blocks.size() + 1); block.setPreviousHash(DigestUtils.sha256Hex(blocks.getLast().toString())); block.setTransactions(allTransactions); //create reward Transaction reward = new Transaction(); reward.setId(UUID.randomUUID().toString()); reward.setFrom(""); reward.setTo(“Michel for creating this block"); reward.setKudos(3); allTransactions.add(reward); block.calculateProofOfWork(); blocks.add(block); return block; } }
  • 29. Proof of work public class Block { … public void calculateProofOfWork() { this.nonce = 0; while (!DigestUtils.sha256Hex(this.toString()).startsWith("0000")) { this.nonce++; } } }
  • 30. Comparing with other blockchains In your service… public void init() { this.blockchain = Blockchain.create(); this.blockchain = network.retrieveBlockchainsFromPeers() .stream() .filter(b -> b.isValid()) .filter(b -> b.height() > this.blockchain.height()) .max(Comparator.comparing(Blockchain::height)) .orElse(this.blockchain); }
  • 31. Comparing with other blockchains public boolean isValid() { for (int i = blocks.size() - 1; i > 0; i--) { Block currentBlock = blocks.get(i); Block previousBlock = blocks.get(i - 1); if (!previousHashMatches(previousBlock, currentBlock)) { System.out.println("previous hash doesn't match!"); return false; } if (!currentBlock.isValid()) { System.out.println("proof of work is invalid"); return false; } } return true; } private boolean previousHashMatches(Block previousBlock, Block currentBlock) { return currentBlock.getPreviousHash() .equals(DigestUtils.sha256Hex(previousBlock.toString())); }
  • 32. Comparing with other blockchains public class Block { … boolean isValid() { return DigestUtils.sha256Hex(this.toString()).startsWith("0000"); } … }
  • 33. Propagating transactions @PostMapping("/api/createtransaction") public long createTransaction(@RequestBody Transaction transaction) { …create transaction… network.notifyPeersOfNewTransaction(transaction); }
  • 34. Receiving transactions from the network @PostMapping("/api/addtransaction") public void newTransactionReceived(@RequestBody Transaction transaction) { if (!transactionPool.getAllTransactions().contains(transaction)) { transactionPool.addTransaction(transaction); network.notifyPeersOfNewTransaction(transaction); } }
  • 35. Propagating blocks @PostMapping("/api/mine") public Block mine() { Block block = getBlockchain().mine(transactionPool.getAllTransactions()); transactionPool.clearTransactions(); //propgate transaction network.notifyPeersOfNewBlock(block); return block; }
  • 36. Receiving blocks from the network @PostMapping("/api/addblock") public void newBlockReceived(@RequestBody Block block) { //only add block if it is valid if (blockchain.isValid(block)) { blockchain.addBlock(block); //clear all transactions that are already in the block transactionPool.clearTransactions(block.getTransactions()); //propagate block through the network network.notifyPeersOfNewBlock(block); } }
  • 37. Receiving blocks from the network public class Blockchain { ... private boolean previousHashMatches(Block previousBlock, Block currentBlock) { return currentBlock.getPreviousHash() .equals(DigestUtils.sha256Hex(previousBlock.toString())); } public boolean isValid(Block block) { return block.isValid() && previousHashMatches(blocks.getLast(), block); } public void addBlock(Block block) { blocks.add(block); } }

Editor's Notes

  1. So why this session? I’ll explain. Does anyone have any cryptocurrency? How’s it going so far? Well, I started to get really exited about all these crypto currencies and the technology behind them. So I started looking for articles. Problem was, the articles were either like this:
  2. …or this, way too complex examples that also pulled in signing, double spending etc.
  3. In essence, a blockchain is…. Each block contains one or more transactions, and each block has some kind of backreference to the previous block. This will give the blockchain its immutability. Furthermore, a blockchain is distributed. So each participant in the network has the same copy of the blockchain. So if you’re the odd one out, you won’t be accepted as having a valid blockchain.
  4. Important point to discuss is that immutabilty is implemented by hashing. Each block contains a hash of the previous block. You can imagine that if you change a transaction in block 2, all subsequent block’s hashes will change as well. So you’ll have to recalculate all these hashes as well. Apart from convincing everyone your blockchain is the correct one, making new blocks or changing existing blocks is not easy. It requires something called proof-of-work, which we will see when we’re going to build the blockchain.
  5. So, let’s get started with an initial block! Not to worry about this hashing thingy, let’s just set up the model, right?