Skip to content

Commit

Permalink
#5 Introduce basic REST API
Browse files Browse the repository at this point in the history
  • Loading branch information
ivgag committed Sep 28, 2024
1 parent f85696a commit b84b791
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 11 deletions.
21 changes: 21 additions & 0 deletions cmd/node/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// cmd/myblockchain/main.go
package main

import (
"blockchain/internal/api"
"blockchain/internal/blockchain"
"blockchain/internal/consensus"
"log"
"net/http"
)

func main() {
bc := blockchain.NewBlockchain()

cons := consensus.NewPoWConsensus(&bc)

router := api.NewRouter(&bc, cons)

log.Println("Listening on :8080")
log.Fatal(http.ListenAndServe(":8080", router))
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module blockchain

go 1.23.1

require github.com/gorilla/mux v1.8.1
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
37 changes: 37 additions & 0 deletions internal/api/handlers/block.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package handlers

import (
"encoding/json"
"net/http"
"strconv"

"blockchain/internal/blockchain"

"github.com/gorilla/mux"
)

func GetBlockHandler(bc *blockchain.Blockchain) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
indexStr, ok := vars["index"]
if !ok {
http.Error(w, "Index is required", http.StatusBadRequest)
return
}

index, err := strconv.Atoi(indexStr)
if err != nil {
http.Error(w, "Invalid index format", http.StatusBadRequest)
return
}

block, err := bc.GetBlock(index)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(block)
}
}
19 changes: 19 additions & 0 deletions internal/api/handlers/chain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package handlers

import (
"encoding/json"
"net/http"

"blockchain/internal/blockchain"
)

func GetChainHandler(bc *blockchain.Blockchain) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
response := map[string]interface{}{
"length": len(bc.Blocks()),
"blocks": bc.Blocks(),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
}
20 changes: 20 additions & 0 deletions internal/api/router.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// internal/api/router.go
package api

import (
"blockchain/internal/blockchain"
"blockchain/internal/consensus"

"blockchain/internal/api/handlers"

"github.com/gorilla/mux"
)

func NewRouter(bc *blockchain.Blockchain, cons *consensus.PoWConsensus) *mux.Router {
router := mux.NewRouter()

router.HandleFunc("/chain", handlers.GetChainHandler(bc)).Methods("GET")
router.HandleFunc("/blocks/{index}", handlers.GetBlockHandler(bc)).Methods("GET")

return router
}
43 changes: 38 additions & 5 deletions internal/blockchain/blockchain.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,58 @@
package blockchain

import (
"errors"
"sync"
)

type Blockchain struct {
Blocks []Block
blocks []Block
Difficulty int
mutex sync.Mutex
}

func NewBlockchain() Blockchain {
return Blockchain{
Blocks: []Block{GenesisBlock(2)},
blocks: []Block{GenesisBlock(2)},
Difficulty: 2,
mutex: sync.Mutex{},
}
}

func (bc *Blockchain) Blocks() []Block {
bc.mutex.Lock()
defer bc.mutex.Unlock()

return bc.blocks
}

func (bc *Blockchain) AddBlock(block Block) {
bc.Blocks = append(bc.Blocks, block)
bc.mutex.Lock()
defer bc.mutex.Unlock()

bc.blocks = append(bc.blocks, block)
}

func (bc *Blockchain) FirstBlock() Block {
return bc.Blocks[0]
bc.mutex.Lock()
defer bc.mutex.Unlock()

return bc.blocks[0]
}

func (bc *Blockchain) LastBlock() Block {
return bc.Blocks[len(bc.Blocks)-1]
bc.mutex.Lock()
defer bc.mutex.Unlock()

return bc.blocks[len(bc.blocks)-1]
}

func (bc *Blockchain) GetBlock(index int) (Block, error) {
bc.mutex.Lock()
defer bc.mutex.Unlock()

if index < 0 || index >= len(bc.blocks) {
return Block{}, errors.New("invalid index")
}
return bc.blocks[index], nil
}
2 changes: 1 addition & 1 deletion internal/consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func (c *PoWConsensus) CreateNewBlock(data string) blockchain.Block {
}

func (c *PoWConsensus) AdjustDifficulty() int {
return CalculateNewDifficulty(c.blockchain.Blocks)
return CalculateNewDifficulty(c.blockchain.Blocks())
}

func (c *PoWConsensus) AddNewBlock(block blockchain.Block) error {
Expand Down
2 changes: 1 addition & 1 deletion internal/consensus/consensus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestAddNewBlock(t *testing.T) {
t.Errorf("failed to add block to blockchain: " + result.Error())
}

if result := ValidateBlockChain(bc); result != nil {
if result := ValidateBlockChain(&bc); result != nil {
t.Errorf("failed to validate blockchain: " + result.Error())
}
}
10 changes: 6 additions & 4 deletions internal/consensus/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import (
"strings"
)

func ValidateBlockChain(blockchain blockchain.Blockchain) error {
func ValidateBlockChain(blockchain *blockchain.Blockchain) error {
var blocks = blockchain.Blocks()

// skip genesis block
for i := 1; i < len(blockchain.Blocks); i++ {
block := blockchain.Blocks[i]
previousBlock := blockchain.Blocks[i-1]
for i := 1; i < len(blocks); i++ {
block := blocks[i]
previousBlock := blocks[i-1]

if err := validateBlock(block); err != nil {
return err
Expand Down

0 comments on commit b84b791

Please sign in to comment.