Browse Source

Refactored application to use PcData struct as data in block, rewrote server following https://mycoralhealth.medium.com/code-your-own-blockchain-in-less-than-200-lines-of-go-e296282bcffc

main
gryffyn 5 months ago
parent
commit
aa4ec26957
Signed by: gryffyn GPG Key ID: 6948DD6514D02BEF
  1. 28
      chain/chain.go
  2. 1
      go.mod
  3. 2
      go.sum
  4. 45
      paperchain.go
  5. 1
      paperchain_test.go
  6. 111
      server/server.go
  7. 2
      utils/types.go
  8. 48
      utils/utils.go

28
chain/chain.go

@ -1,6 +1,7 @@
package chain
import (
"encoding/json"
"errors"
"strings"
"time"
@ -11,7 +12,8 @@ import (
var _DIFFICULTY = "7063"
func calcBlockHash(block utils.Block) string {
record := string(rune(block.Index)) + block.Timestamp.String() + block.Data + block.PrevHash
js, _ := json.Marshal(block.Data)
record := string(rune(block.Index)) + block.Timestamp.String() + string(js) + block.PrevHash
return utils.Hash(record)
}
@ -30,19 +32,35 @@ func calcPOWHash(index int, timestamp time.Time, data, oldhash string) (string,
return hash, nonce
}
func GenerateBlock(oldBlock utils.Block, data string) (utils.Block, error) {
func GenerateBlock(oldBlock utils.Block, data utils.PcData) (utils.Block, error) {
t := time.Now()
js, _ := json.Marshal(data)
var newBlock utils.Block
hash := calcHash(oldBlock.Index+1, t, data, oldBlock.Hash)
hash := calcHash(oldBlock.Index+1, t, string(js), oldBlock.Hash)
newBlock = utils.Block{PrevHash: oldBlock.Hash, Index: oldBlock.Index + 1, Timestamp: t, Data: data, Hash: hash}
return newBlock, nil
}
func GenesisBlock() (utils.Block, error) {
t := time.Now()
gendata := utils.PcData{
Case: utils.PcCase{
ID: "Genesis",
Name: "",
},
Examiner: utils.PcExaminer{
ID: "",
Name: "",
Phone: "",
Email: "",
Org: "",
},
NoteID: 0,
Nonce: 0,
}
var newBlock utils.Block
hash := calcHash(0, t, "Genesis", "0000000000000000000000000000000000000000000000000000000000000000")
newBlock = utils.Block{PrevHash: "0000000000000000000000000000000000000000000000000000000000000000", Timestamp: t, Data: "Genesis", Hash: hash}
newBlock = utils.Block{PrevHash: "0000000000000000000000000000000000000000000000000000000000000000", Timestamp: t, Data: gendata, Hash: hash}
return newBlock, nil
}
@ -65,7 +83,7 @@ func ReplaceChain(newBlocks []utils.Block) {
}
}
func GenAndAppendBlock(data string) error {
func GenAndAppendBlock(data utils.PcData) error {
block, _ := GenerateBlock(utils.Blockchain[len(utils.Blockchain)-1], data)
if IsBlockValid(block, utils.Blockchain[len(utils.Blockchain)-1]) {
utils.Blockchain = append(utils.Blockchain, block)

1
go.mod

@ -4,6 +4,7 @@ go 1.15
require (
github.com/andskur/argon2-hashing v0.1.3
github.com/gorilla/mux v1.8.0
github.com/joho/godotenv v1.3.0
gitlab.com/tslocum/cview v1.5.2
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee // indirect

2
go.sum

@ -5,6 +5,8 @@ github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo
github.com/gdamore/tcell/v2 v2.0.0-dev/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
github.com/gdamore/tcell/v2 v2.0.1-0.20201109052606-7d87d8188c8d h1:C1FQEuzw5kUUveSXpZp3v0+qOR+VEnzHsQ7K6n39LsM=
github.com/gdamore/tcell/v2 v2.0.1-0.20201109052606-7d87d8188c8d/go.mod h1:vSVL/GV5mCSlPC6thFP5kfOFdM9MGZcalipmpTxTgQA=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=

45
paperchain.go

@ -2,52 +2,23 @@ package main
import (
"fmt"
"log"
"paperchain.cc/paperchain/chain"
"paperchain.cc/paperchain/server"
"paperchain.cc/paperchain/utils"
)
func main() {
// env := utils.LoadEnv()
/* go func() {
t := time.Now()
genesisBlock := chain.Block{Timestamp: t}
chain.Blockchain = append(chain.Blockchain, genesisBlock)
}() */
env := utils.LoadEnv()
genblock, _ := chain.GenesisBlock()
chain.AppendBlock(genblock)
block1, _ := chain.GenerateBlock(utils.Blockchain[len(utils.Blockchain)-1], "Test 1")
chain.AppendBlock(block1)
_ = chain.GenAndAppendBlock("Test 2")
_ = chain.GenAndAppendBlock("Test 3")
for _, num := range utils.Blockchain {
fmt.Println(num)
println("")
}
test := utils.PcData{
Case: utils.PcCase{
ID: "TEST01",
Name: "Test Case",
},
Examiner: utils.PcExaminer{
ID: "TEST01_user",
Name: "Test User",
Phone: "01",
Email: "user@test.com",
Org: "Test Inc.",
},
NoteID: 0,
Nonce: 0,
fmt.Println("Serving on " + env["PAPERCHAIN_ADDR"] + ":" + env["PAPERCHAIN_PORT"] + "...")
err := server.Serve(env["PAPERCHAIN_ADDR"], env["PAPERCHAIN_PORT"])
if err != nil {
log.Fatal(err)
}
teststr := utils.HashStruct(test)
fmt.Println(teststr)
//fmt.Println("Serving on " + env["PAPERCHAIN_ADDR"] + ":" + env["PAPERCHAIN_PORT"] + "...")
//server.Serve(env["PAPERCHAIN_ADDR"], env["PAPERCHAIN_PORT"])
// loginUi()
//if authLogin() {
// fmt.Println("Valid login.")
//}
}

1
paperchain_test.go

@ -22,6 +22,7 @@ func TestHashStruct(t *testing.T) {
NoteID: 0,
Nonce: 0,
}
str := utils.HashStruct(test)
if str != "4cd7b1862d242647981e3076a12004870ac262f88838a1d0a466a14ac6260e7f" {
t.Error()

111
server/server.go

@ -1,67 +1,78 @@
package server
import (
"bufio"
"fmt"
"encoding/json"
"io"
"log"
"net"
"net/http"
"time"
"github.com/gorilla/mux"
"paperchain.cc/paperchain/chain"
"paperchain.cc/paperchain/utils"
)
var bcServer chan []utils.Block
func Serve(addr string, port string) {
server, err := net.Listen("tcp", addr+":"+port)
if server == nil {
panic("couldn't start listening: " + err.Error())
func Serve(addr, port string) error {
handlr := makeMuxRouter()
s := &http.Server{
Addr: addr + ":" + port,
Handler: handlr,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
defer server.Close()
conns := clientConns(server)
for {
go handleConn(<-conns)
if err := s.ListenAndServe(); err != nil {
return err
}
return nil
}
func clientConns(listener net.Listener) chan net.Conn {
ch := make(chan net.Conn)
i := 0
go func() {
for {
client, err := listener.Accept()
if client == nil {
fmt.Printf("couldn't accept: " + err.Error())
continue
}
i++
fmt.Printf("%d: %v <-> %v\n", i, client.LocalAddr(), client.RemoteAddr())
ch <- client
}
}()
return ch
func makeMuxRouter() http.Handler {
muxRouter := mux.NewRouter()
muxRouter.HandleFunc("/", handleGetBlockchain).Methods("GET")
muxRouter.HandleFunc("/", handleWriteBlock).Methods("POST")
return muxRouter
}
func handleConn(conn net.Conn) {
defer conn.Close()
_, _ = io.WriteString(conn, "Enter a new note:")
scanner := bufio.NewScanner(conn)
go func() {
for scanner.Scan() {
note := scanner.Text()
newBlock, err := chain.GenerateBlock(utils.Blockchain[len(utils.Blockchain)-1], note)
if err != nil {
log.Println(err)
continue
}
if chain.IsBlockValid(newBlock, utils.Blockchain[len(utils.Blockchain)-1]) {
newBlockchain := append(utils.Blockchain, newBlock)
chain.ReplaceChain(newBlockchain)
}
func handleGetBlockchain(w http.ResponseWriter, r *http.Request) {
bytes, err := json.MarshalIndent(utils.Blockchain, "", " ")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
io.WriteString(w, string(bytes))
}
func handleWriteBlock(w http.ResponseWriter, r *http.Request) {
var m utils.PcData
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&m); err != nil {
respondWithJSON(w, r, http.StatusBadRequest, r.Body)
return
}
defer r.Body.Close()
newBlock, err := chain.GenerateBlock(utils.Blockchain[len(utils.Blockchain)-1], m)
if err != nil {
respondWithJSON(w, r, http.StatusInternalServerError, m)
return
}
if chain.IsBlockValid(newBlock, utils.Blockchain[len(utils.Blockchain)-1]) {
chain.AppendBlock(newBlock)
}
respondWithJSON(w, r, http.StatusCreated, newBlock)
bcServer <- utils.Blockchain
_, _ = io.WriteString(conn, "\nEnter a new note:")
}
}()
}
func respondWithJSON(w http.ResponseWriter, r *http.Request, code int, payload interface{}) {
response, err := json.MarshalIndent(payload, "", " ")
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("HTTP 500: Internal Server Error"))
return
}
w.WriteHeader(code)
w.Write(response)
}

2
utils/types.go

@ -28,7 +28,7 @@ type Block struct {
PrevHash string
Index int
Timestamp time.Time
Data string
Data PcData
Hash string
}

48
utils/utils.go

@ -1,7 +1,6 @@
package utils
import (
"encoding/base64"
"encoding/hex"
"fmt"
"log"
@ -10,15 +9,6 @@ import (
"lukechampine.com/blake3"
)
func b64e(data string) string {
return base64.StdEncoding.EncodeToString([]byte(data))
}
func b64d(data string) string {
dec, _ := base64.StdEncoding.DecodeString(data)
return string(dec)
}
func LoadEnv() map[string]string {
var env map[string]string
env, err := godotenv.Read()
@ -28,44 +18,6 @@ func LoadEnv() map[string]string {
return env
}
func DataToB64(data PcData) PcData {
b64data := PcData{
Case: PcCase{
ID: b64e(data.Case.ID),
Name: b64e(data.Case.Name),
},
Examiner: PcExaminer{
ID: b64e(data.Examiner.ID),
Name: b64e(data.Examiner.Name),
Phone: b64e(data.Examiner.Phone),
Email: b64e(data.Examiner.Email),
Org: b64e(data.Examiner.Org),
},
NoteID: data.NoteID,
Nonce: data.Nonce,
}
return b64data
}
func DataFromB64(data PcData) PcData {
b64data := PcData{
Case: PcCase{
ID: b64d(data.Case.ID),
Name: b64d(data.Case.Name),
},
Examiner: PcExaminer{
ID: b64d(data.Examiner.ID),
Name: b64d(data.Examiner.Name),
Phone: b64d(data.Examiner.Phone),
Email: b64d(data.Examiner.Email),
Org: b64d(data.Examiner.Org),
},
NoteID: data.NoteID,
Nonce: data.Nonce,
}
return b64data
}
func Hash(data string) string {
h := blake3.New(32, nil)
_, _ = h.Write([]byte(data))

Loading…
Cancel
Save