Java >> Java Tutorial >  >> Tag >> Spring

Erstellen Sie eine Blockchain mit Spring Boot

Also habe ich hier schon früher über Blockchain gesprochen. Ich werde nicht im Detail darauf eingehen, was Blockchain ist. Aber ich werde zeigen, wie man eine Blockchain mit Spring Boot baut.

Was brauchen Sie

  • IntelliJ
  • Java 8
  • Frühlingsstiefel
  • Gradle

Was ist Blockchain?

Kurz gesagt, Blockchain ist eine Kette von Datensätzen, die Blöcke genannt werden und jede Art von Daten oder Transaktionen in diesen Datensätzen enthalten. Sie werden mithilfe von Hashes miteinander verkettet.

Erstellen Sie eine Blockchain

Wir brauchen zwei Modellklassen:jeweils eine für Block und eine für Transaktion. Wir benötigen auch einen Federrest-Controller, um 3 APIs für Mining, Transaktion und Verkettung bereitzustellen. Unser Herzstück dieser Blockchain wird eine Utility-Klasse sein, die uns einen Arbeitsnachweis liefert. Wenn Sie nicht wissen, was ein Arbeitsnachweis ist, können Sie den Artikel, den ich in diesem Beitrag verlinkt habe, erneut lesen, in dem ich den Algorithmus erklärt habe, der beim Aufbau einer Blockchain verwendet wird, heißt Arbeitsnachweis.

Modellklassen

Jeder Block enthält einen Index, einen Zeitstempel, Transaktionen, einen Beweis und einen Hash für den vorherigen Block. Diese Modellklasse sieht wie folgt aus:

package com.betterjavacode.blockchain.model;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.hash.Hashing;

import java.nio.charset.StandardCharsets;
import java.util.List;

public class Block
{

    public Block()
    {

    }
    private Long index;

    private Long timestamp;

    private List<Transaction> transactionList;

    private Long proof;

    private String previousBlockHash;

    public static final Long GENESIS_BLOCK_PROOF = 100L;
    public static final String GENESIS_BLOCK_PREV_HASH = "1";

    public Long getIndex()
    {
        return index;
    }

    public String getPreviousBlockHash()
    {
        return previousBlockHash;
    }

    public Long getProof()
    {
        return proof;
    }

    public List<Transaction> getTransactionList()
    {
        return transactionList;
    }

    public Block(Builder builder)
    {
        this.index = builder.index;
        this.timestamp = builder.timestamp;
        this.transactionList = builder.transactionList;
        this.proof = builder.proof;
        this.previousBlockHash = builder.previousBlockHash;
    }

    public static class Builder
    {
        private Long index;
        private Long timestamp;
        private List<Transaction> transactionList;
        private Long proof;
        private String previousBlockHash;


        public Builder setIndex(Long index)
        {
            this.index = index;
            return this;
        }

        public Builder setTimestamp(Long timestamp)
        {
            this.timestamp = timestamp;
            return this;
        }

        public Builder setTransactionList(List<Transaction> transactionList)
        {
            this.transactionList = transactionList;
            return this;
        }

        public Builder setProof(Long proof)
        {
            this.proof = proof;
            return this;
        }

        public Builder setPreviousBlockHash(String previousBlockHash)
        {
            this.previousBlockHash = previousBlockHash;
            return this;
        }

        public Block build()
        {
            return new Block(this);
        }
    }

    public String hash(ObjectMapper mapper) throws JsonProcessingException
    {
        String json = mapper.writeValueAsString(this);
        return Hashing.sha256().hashString(json, StandardCharsets.UTF_8).toString();
    }
}

Es sieht wie folgt aus, wenn wir eine Transaktion haben


{
  "message": "New Block Added",
  "index": 2,
  "transactionList": [
    {
      "sender": "0",
      "recipient": "ef55403a23af46268fb5dfcee91329ae",
      "amount": 1
    }
  ],
  "proof": 33575,
  "previousHash": "58c63eba6e93523867369a865ee363a0c89a2b76a62c677e8acd27536415daf4"
}

Rest-Controller

Wir werden einen Rest-Controller schreiben, um die Kette abzurufen, zu minen oder eine Transaktion hinzuzufügen. Ein REST-Controller für Transaktionen führt eine POST-Anforderung aus, um eine Transaktion zur Kette hinzuzufügen. Unser REST-Controller sieht wie folgt aus:

package com.betterjavacode.blockchain.controller;


import com.betterjavacode.blockchain.model.Block;
import com.betterjavacode.blockchain.model.Transaction;
import com.betterjavacode.blockchain.response.ChainResponse;
import com.betterjavacode.blockchain.response.MineResponse;
import com.betterjavacode.blockchain.response.TransactionResponse;
import com.betterjavacode.blockchain.service.Blockchain;
import com.betterjavacode.blockchain.util.BlockProofOfWorkGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.UUID;

@RestController
@RequestMapping("/")
public class BlockchainController
{
    @Autowired
    private Blockchain blockchain;

    @Autowired
    private ObjectMapper objectMapper;

    public static final String NODE_ID = UUID.randomUUID().toString().replace("-","");
    public static final String NODE_ACCOUNT_ADDRESS = "0";
    public static final BigDecimal MINING_CASH_REWARDS = BigDecimal.ONE;

    @GetMapping("mine")
    public MineResponse mine() throws JsonProcessingException
    {
        // Calculate Proof of work
        Block lastBlock = blockchain.lastBlock();

        Long lastProof = lastBlock.getProof();

        Long proof = BlockProofOfWorkGenerator.proofOfWork(lastProof);

        // Reward the miner by adding a transaction

        blockchain.addTransaction(NODE_ACCOUNT_ADDRESS, NODE_ID, MINING_CASH_REWARDS);

        // Add the new block to the chain
        Block newBlock = blockchain.createBlock(proof, lastBlock.hash(objectMapper));

        return new MineResponse.Builder().message("New Block Added").index(newBlock.getIndex()).transactions(newBlock.getTransactionList())
                .proof(newBlock.getProof()).previousHash(newBlock.getPreviousBlockHash()).build();
    }

    @GetMapping("chain")
    public ChainResponse fullChain()
    {
        return new ChainResponse.Builder().chain(blockchain.getChain()).length(blockchain.getChain().size()).build();
    }

    @PostMapping("transactions")
    public TransactionResponse newTransaction(@RequestBody @Valid Transaction transaction)
    {
        Long index = blockchain.addTransaction(transaction.getSender(), transaction.getRecipient(), transaction.getAmount());

        return new TransactionResponse.Builder().index(index).build();
    }
}

Der POST-Aufruf der Transaktion fügt die Transaktion grundsätzlich der Liste hinzu und gibt den Index des Blocks zurück, zu dem die Transaktion hinzugefügt wird.

Arbeitsnachweis

Wie wir den Proof of Work umgesetzt haben, werden wir hier besprechen. Dies wird das Herz der gesamten Blockchain sein, die wir aufgebaut haben.

Wenn neue Blöcke in der Blockchain abgebaut werden, wird ein Proof-of-Work-Algorithmus verwendet, um zu überprüfen, ob der Block gerechtfertigt ist. Die einfache Idee von Proof of Work besteht darin, eine Zahl zu finden, die ein Problem löst. Diese Nummer muss schwer zu finden, aber vom Netzwerk leicht zu überprüfen sein.

Beispiel – Der Hash einer Ganzzahl multipliziert mit einer anderen Ganzzahl muss mit einer bestimmten Zahl enden. In unserer Implementierung für diesen Algorithmus verifizieren wir, dass der Beweis wie folgt gültig ist:

public static boolean validProof(Long lastProof, Long proof)
 {
     String s = "" + lastProof + "" + proof;

     String sha256 = Hashing.sha256().hashString(s, StandardCharsets.UTF_8).toString();

     return sha256.endsWith(PROOF_OF_WORK);
 }

Dies ist der Algorithmus, den Miner am schnellsten zu lösen versuchen und wer ihn zuerst und kompakt löst, wird als Teil der Transaktion mit einer Münze belohnt.

Swagger-API

Sobald wir also unsere Implementierung erstellt und die Spring Boot-Anwendung ausgeführt haben, kann ich über Swagger-APIs darauf zugreifen. Diese APIs sind wie folgt:

  1. /transactions – Erstellt eine neue Transaktion im Block
  2. /mine – schürft den neuen Block
  3. /chain – gibt die vollständige Blockchain zurück

Schlussfolgerung

In diesem Beitrag haben wir gezeigt, wie man eine Blockchain versteht, indem man sie in Spring Boot implementiert. Denken Sie daran, eine Sache, die ich nicht beschrieben habe, ist der Konsensalgorithmus zur Überprüfung der Kette, obwohl ich ihn in meiner Klasse Blockchain implementiert habe .

Referenzen

  1. Blockchain erstellen
  2. Blockchain-Github


Java-Tag