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.

This commit is contained in:
arnaucode
2017-11-25 19:14:20 +01:00
parent 2a01ef0394
commit c5fc0a53a7
12 changed files with 251 additions and 46 deletions

View File

@@ -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
peer/blockchain.go Normal file
View File

@@ -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
}

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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)
}
}
}

67
peer/restRoutes.go Executable file
View File

@@ -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))
}

View File

@@ -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
peer/tests.sh Normal file
View File

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

View File

@@ -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))
}