Browse Source

implemented the blockchain, implemented the blocks propagation throught peers, implemented REST GetPeers and PostUser (address, pubK). Everything without any kind of blockchain verification. No cryptography yet.

master
arnaucode 6 years ago
parent
commit
c5fc0a53a7
12 changed files with 251 additions and 46 deletions
  1. +1
    -0
      .gitignore
  2. +50
    -0
      peer/README.md
  3. +69
    -0
      peer/blockchain.go
  4. +2
    -1
      peer/connections.go
  5. +11
    -9
      peer/main.go
  6. +8
    -3
      peer/messages.go
  7. +20
    -11
      peer/peers.go
  8. +0
    -0
      peer/restConfig.go
  9. +67
    -0
      peer/restRoutes.go
  10. +0
    -22
      peer/restServerRoutes.go
  11. +1
    -0
      peer/tests.sh
  12. +22
    -0
      peer/utils.go

+ 1
- 0
.gitignore

@ -0,0 +1 @@
tests

+ 50
- 0
peer/README.md

@ -19,3 +19,53 @@ Needs the config.json file:
"serverport": "3000"
}
```
## Peer REST API
- GET /
- Returns the peer.ID (where peer.ID = hash(peer.IP + ":" + peer.Port))
- GET /peers
- Returns the peer outcomingPeersList (the peers which the peer have connection)
```json
{
"PeerID": "VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo=",
"peerslist": [
{
"id": "VOnL-15rFsUiCnRoyGFksKvWKcwNBRz5iarRem0Ilvo=",
"ip": "127.0.0.1",
"port": "3000",
"role": "server",
"conn": null
},
{
"id": "Lk9jEP1YcOAzl51yY61GdWADNe35_g5Teh12JeguHhA=",
"ip": "127.0.0.1",
"port": "3003",
"role": "client",
"conn": {}
},
{
"id": "xj78wuyN2_thFBsXOUXnwij4L8vualxQ9GnVRK6RS4c=",
"ip": "127.0.0.1",
"port": "3005",
"role": "client",
"conn": {}
}
],
"date": "0001-01-01T00:00:00Z"
}
```
- POST /register
- Adds the address (pubK of the user) to the blockchain
## TODO
- When a peer connects to the network, sends his last Block, and receives the new Blocks from this last Block
- Delete the peer from the peers list when the connection is closed
- REST:
- endpoint to get if the address is in the blockchain (to verify users)
- parameters Date or LastUpdate on the structs needs to be updated values

+ 69
- 0
peer/blockchain.go

@ -0,0 +1,69 @@
package main
import (
"errors"
"time"
)
type Block struct {
Hash string `json:"hash"`
Height int64 `json:"height"`
Date time.Time `json:"date"`
PreviousHash string `json:"previoushash"`
NextHash string `json:"nexthash"`
Data []Address `json:"data"`
Emitter string `json:"emitter"` //the ID of the peer that has emmited the block
}
type Blockchain struct {
GenesisBlock string `json:"genesisblock"`
LastUpdate time.Time `json:"lastupdate"`
Blocks []Block `json:"blocks"`
}
var blockchain Blockchain
func (bc *Blockchain) getBlockByHash(hash string) (Block, error) {
for _, block := range bc.Blocks {
if block.Hash == hash {
return block, nil
}
}
var b Block
return b, errors.New("Block Hash not found")
}
func (bc *Blockchain) createBlock(address Address) Block {
var b Block
b.Height = int64(len(bc.Blocks))
if len(bc.Blocks) == 0 {
b.Height = 0
} else {
b.PreviousHash = bc.Blocks[len(bc.Blocks)-1].Hash
}
b.Date = time.Now()
b.Data = append(b.Data, address)
b.Emitter = runningPeer.ID
b.Hash = hashBlock(b)
return b
}
func (bc *Blockchain) blockExists(block Block) bool {
for _, b := range bc.Blocks {
if b.Hash == block.Hash {
return true
}
}
return false
}
func (bc *Blockchain) addBlock(block Block) error {
if len(bc.Blocks) > 0 {
bc.Blocks[len(bc.Blocks)-1].NextHash = block.Hash
} else {
bc.GenesisBlock = block.Hash
}
bc.Blocks = append(bc.Blocks, block)
return nil
}

+ 2
- 1
peer/connections.go

@ -57,7 +57,8 @@ func handleConn(conn net.Conn, connPeer Peer) {
log.Println("handling conn: " + conn.RemoteAddr().String())
//reply to the conn, send the peerList
var msg Msg
msg = msg.construct("PeersList", "here my outcomingPeersList", outcomingPeersList)
msg.construct("PeersList", "here my outcomingPeersList")
msg.PeersList = outcomingPeersList
msgB := msg.toBytes()
_, err := conn.Write(msgB)
check(err)

+ 11
- 9
peer/main.go

@ -5,7 +5,6 @@ import (
"math/rand"
"net"
"os"
"strconv"
"time"
"github.com/fatih/color"
@ -32,9 +31,10 @@ func main() {
//read configuration file
readConfig("config.json")
runningPeer.ID = strconv.Itoa(randInt(1, 1000)) //0 is reserved for server
//runningPeer.ID = strconv.Itoa(randInt(1, 1000)) //0 is reserved for server
runningPeer.IP = config.IP
runningPeer.Port = config.Port
runningPeer.ID = hashPeer(runningPeer)
runningPeer.Role = "client"
go runRestServer()
@ -45,7 +45,8 @@ func main() {
color.Yellow("Running as p2p server")
runningPeer.Role = "server"
runningPeer.Port = config.ServerPort
runningPeer.ID = "0"
runningPeer.ID = hashPeer(runningPeer)
//runningPeer.ID = "0"
}
}
thisPeerID = runningPeer.ID
@ -58,12 +59,13 @@ func main() {
go acceptPeers(runningPeer)
}
if runningPeer.Role == "client" {
var newPeer Peer
newPeer.ID = "0"
newPeer.IP = config.ServerIP
newPeer.Port = config.ServerPort
newPeer.Role = "server"
connectToPeer(newPeer)
var serverPeer Peer
//serverPeer.ID = "0"
serverPeer.IP = config.ServerIP
serverPeer.Port = config.ServerPort
serverPeer.ID = hashPeer(serverPeer)
serverPeer.Role = "server"
connectToPeer(serverPeer)
go acceptPeers(runningPeer)
}

+ 8
- 3
peer/messages.go

@ -14,6 +14,7 @@ type Msg struct {
Date time.Time `json:"date"`
Content string `json:"content"`
PeersList PeersList `json:"peerslist"`
Block Block `json:"block"`
}
func messageHandler(peer Peer, msg Msg) {
@ -57,18 +58,22 @@ func messageHandler(peer Peer, msg Msg) {
*/
printPeersList()
break
case "Block":
if !blockchain.blockExists(msg.Block) {
blockchain.addBlock(msg.Block)
propagateBlock(msg.Block)
}
break
default:
log.Println("Msg.Type not supported")
break
}
}
func (msg Msg) construct(msgtype string, msgcontent string, peersList PeersList) Msg {
func (msg *Msg) construct(msgtype string, msgcontent string) {
msg.Type = msgtype
msg.Content = msgcontent
msg.PeersList = peersList
msg.Date = time.Now()
return msg
}
func (msg Msg) toBytes() []byte {
msgS, err := json.Marshal(msg)

peer/peersList.go → peer/peers.go

@ -74,22 +74,16 @@ func propagatePeersList(p Peer) {
if peer.ID != p.ID && p.ID != "" {
color.Yellow(peer.ID + " - " + p.ID)
var msg Msg
msg = msg.construct("PeersList", "here my outcomingPeersList", outcomingPeersList)
msg.construct("PeersList", "here my outcomingPeersList")
msg.PeersList = outcomingPeersList
msgB := msg.toBytes()
_, err := peer.Conn.Write(msgB)
check(err)
} else {
//to the peer that has sent the peerList, we send our ID
/*
var msg Msg
var pl PeersList
msg = msg.construct("MyID", runningPeer.ID, pl)
msgB := msg.toBytes()
_, err := p.Conn.Write(msgB)
check(err)
*/
//to the peer that has sent the peerList, we send our PeersList
var msg Msg
msg = msg.construct("PeersList_Response", "here my outcomingPeersList", outcomingPeersList)
msg.construct("PeersList_Response", "here my outcomingPeersList")
msg.PeersList = outcomingPeersList
msgB := msg.toBytes()
_, err := peer.Conn.Write(msgB)
check(err)
@ -123,3 +117,18 @@ func printPeersList() {
}
fmt.Println("")
}
//send the block to all the peers of the outcomingPeersList
func propagateBlock(b Block) {
//prepare the msg to send to all connected peers
var msg Msg
msg.construct("Block", "new block")
msg.Block = b
msgB := msg.toBytes()
for _, peer := range outcomingPeersList.Peers {
if peer.Conn != nil {
_, err := peer.Conn.Write(msgB)
check(err)
}
}
}

peer/restServerConfig.go → peer/restConfig.go


+ 67
- 0
peer/restRoutes.go

@ -0,0 +1,67 @@
package main
import (
"encoding/json"
"fmt"
"net/http"
"github.com/fatih/color"
)
type Routes []Route
var routes = Routes{
Route{
"Index",
"GET",
"/",
Index,
},
Route{
"GetPeers",
"GET",
"/peers",
GetPeers,
},
Route{
"PostUser",
"POST",
"/register",
PostUser,
},
}
type Address struct {
Address string `json:"address"` //the pubK of the user, to perform logins
}
func Index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, runningPeer.ID)
}
func GetPeers(w http.ResponseWriter, r *http.Request) {
jResp, err := json.Marshal(outcomingPeersList)
check(err)
fmt.Fprintln(w, string(jResp))
}
func PostUser(w http.ResponseWriter, r *http.Request) {
decoder := json.NewDecoder(r.Body)
var address Address
err := decoder.Decode(&address)
if err != nil {
panic(err)
}
defer r.Body.Close()
fmt.Println(address)
color.Blue(address.Address)
//TODO add the verification of the address, to decide if it's accepted to create a new Block
block := blockchain.createBlock(address)
blockchain.addBlock(block)
go propagateBlock(block)
jResp, err := json.Marshal(blockchain)
check(err)
fmt.Fprintln(w, string(jResp))
}

+ 0
- 22
peer/restServerRoutes.go

@ -1,22 +0,0 @@
package main
import (
"fmt"
"net/http"
)
type Routes []Route
var routes = Routes{
Route{
"Index",
"GET",
"/",
Index,
},
}
func Index(w http.ResponseWriter, r *http.Request) {
//ipFilter(w, r)
fmt.Fprintln(w, runningPeer.ID)
}

+ 1
- 0
peer/tests.sh

@ -0,0 +1 @@
curl -X POST -F address="thisisasampleaddress" http://127.0.0.1:3002/register

+ 22
- 0
peer/utils.go

@ -1,6 +1,9 @@
package main
import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"math/rand"
"net"
"strings"
@ -27,3 +30,22 @@ func randInt(min int, max int) int {
r := rand.Intn(max-min) + min
return r
}
func hashPeer(p Peer) string {
/*peerJson, err := json.Marshal(p)
check(err)
peerString := string(peerJson)*/
peerString := p.IP + ":" + p.Port
h := sha256.New()
h.Write([]byte(peerString))
return base64.URLEncoding.EncodeToString(h.Sum(nil))
}
func hashBlock(b Block) string {
blockJson, err := json.Marshal(b)
check(err)
blockString := string(blockJson)
h := sha256.New()
h.Write([]byte(blockString))
return base64.URLEncoding.EncodeToString(h.Sum(nil))
}

Loading…
Cancel
Save