Advertisement
thecowmilk

Untitled

Jul 28th, 2021
1,212
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Go 8.25 KB | None | 0 0
  1. package main
  2.  
  3. import (
  4.     "bufio"
  5.     "context"
  6.     "crypto/rand"
  7.     "crypto/sha256"
  8.     "encoding/hex"
  9.     "encoding/json"
  10.     "flag"
  11.     "fmt"
  12.     "io"
  13.     "log"
  14.     mrand "math/rand"
  15.     "os"
  16.     "strconv"
  17.     "strings"
  18.     "sync"
  19.     "time"
  20.  
  21.            "github.com/davecgh/go-spew/spew"
  22.     //golog  "go.uber.org/zap/zapcore"
  23.     libp2p "github.com/libp2p/go-libp2p"
  24.     crypto "github.com/libp2p/go-libp2p-crypto"
  25.     host   "github.com/libp2p/go-libp2p-host"
  26.     net    "github.com/libp2p/go-libp2p-core/network"
  27.     peer   "github.com/libp2p/go-libp2p-peer"
  28.     pstore "github.com/libp2p/go-libp2p-peerstore"
  29.     ma     "github.com/multiformats/go-multiaddr"
  30.     //gologging "go.uber.org/zap/zapcore"
  31. )
  32.  
  33. // Block represents each 'item' in the blockchain
  34. type Block struct {
  35.     Index     int
  36.     Timestamp string
  37.     BPM       int
  38.     Hash      string
  39.     PrevHash  string
  40. }
  41.  
  42. // Blockchain is a series of validated Blocks
  43. var Blockchain []Block
  44.  
  45. var mutex = &sync.Mutex{}
  46.  
  47. // makeBasicHost creates a LibP2P host with a random peer ID listening on the
  48. // given multiaddress. It will use secio if secio is true.
  49. func makeBasicHost(listenPort int, secio bool, randseed int64) (host.Host, error) {
  50.  
  51.     // If the seed is zero, use real cryptographic randomness. Otherwise, use a
  52.     // deterministic randomness source to make generated keys stay the same
  53.     // across multiple runs
  54.     var r io.Reader
  55.     if randseed == 0 {
  56.         r = rand.Reader
  57.     } else {
  58.         r = mrand.New(mrand.NewSource(randseed))
  59.     }
  60.  
  61.     // Generate a key pair for this host. We will use it
  62.     // to obtain a valid host ID.
  63.     priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
  64.     if err != nil {
  65.         return nil, err
  66.     }
  67.  
  68.     opts := []libp2p.Option{
  69.         libp2p.ListenAddrStrings(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", listenPort)),
  70.         libp2p.Identity(priv),
  71.     }
  72.  
  73.     basicHost, err := libp2p.New(context.Background(), opts...)
  74.     if err != nil {
  75.         return nil, err
  76.     }
  77.  
  78.     // Build host multiaddress
  79.     hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", basicHost.ID().Pretty()))
  80.  
  81.     // Now we can build a full multiaddress to reach this host
  82.     // by encapsulating both addresses:
  83.     addrs := basicHost.Addrs()
  84.     var addr ma.Multiaddr
  85.     // select the address starting with "ip4"
  86.     for _, i := range addrs {
  87.         if strings.HasPrefix(i.String(), "/ip4") {
  88.             addr = i
  89.             break
  90.         }
  91.     }
  92.     fullAddr := addr.Encapsulate(hostAddr)
  93.     log.Printf("I am %s\n", fullAddr)
  94.     if secio {
  95.         log.Printf("Now run \"go run p2pblock.go -l %d -d %s -secio\" on a different terminal\n", listenPort+1, fullAddr)
  96.     } else {
  97.         log.Printf("Now run \"go run p2pblock.go -l %d -d %s\" on a different terminal\n", listenPort+1, fullAddr)
  98.     }
  99.  
  100.     return basicHost, nil
  101. }
  102.  
  103. func handleStream(s net.Stream) {
  104.  
  105.     log.Println("Got a new stream!")
  106.  
  107.     // Create a buffer stream for non blocking read and write.
  108.     rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s))
  109.  
  110.     go readData(rw)
  111.     go writeData(rw)
  112.  
  113.     // stream 's' will stay open until you close it (or the other side closes it).
  114. }
  115.  
  116. func readData(rw *bufio.ReadWriter) {
  117.  
  118.     for {
  119.         str, err := rw.ReadString('\n')
  120.         if err != nil {
  121.             log.Fatal(err)
  122.         }
  123.  
  124.         if str == "" {
  125.             return
  126.         }
  127.         if str != "\n" {
  128.  
  129.             chain := make([]Block, 0)
  130.             if err := json.Unmarshal([]byte(str), &chain); err != nil {
  131.                 log.Fatal(err)
  132.             }
  133.  
  134.             mutex.Lock()
  135.             if len(chain) > len(Blockchain) {
  136.                 Blockchain = chain
  137.                 bytes, err := json.MarshalIndent(Blockchain, "", "  ")
  138.                 if err != nil {
  139.  
  140.                     log.Fatal(err)
  141.                 }
  142.                 // Green console color:     \x1b[32m
  143.                 // Reset console color:     \x1b[0m
  144.                 fmt.Printf("\x1b[32m%s\x1b[0m> ", string(bytes))
  145.             }
  146.             mutex.Unlock()
  147.         }
  148.     }
  149. }
  150.  
  151. func writeData(rw *bufio.ReadWriter) {
  152.  
  153.     go func() {
  154.         for {
  155.             time.Sleep(5 * time.Second)
  156.             mutex.Lock()
  157.             bytes, err := json.Marshal(Blockchain)
  158.             if err != nil {
  159.                 log.Println(err)
  160.             }
  161.             mutex.Unlock()
  162.  
  163.             mutex.Lock()
  164.             rw.WriteString(fmt.Sprintf("%s\n", string(bytes)))
  165.             rw.Flush()
  166.             mutex.Unlock()
  167.  
  168.         }
  169.     }()
  170.  
  171.     stdReader := bufio.NewReader(os.Stdin)
  172.  
  173.     for {
  174.         fmt.Print("> ")
  175.         sendData, err := stdReader.ReadString('\n')
  176.         if err != nil {
  177.             log.Fatal(err)
  178.         }
  179.  
  180.         sendData = strings.Replace(sendData, "\n", "", -1)
  181.         bpm, err := strconv.Atoi(sendData)
  182.         if err != nil {
  183.             log.Fatal(err)
  184.         }
  185.         newBlock := generateBlock(Blockchain[len(Blockchain)-1], bpm)
  186.  
  187.         if isBlockValid(newBlock, Blockchain[len(Blockchain)-1]) {
  188.             mutex.Lock()
  189.             Blockchain = append(Blockchain, newBlock)
  190.             mutex.Unlock()
  191.         }
  192.  
  193.         bytes, err := json.Marshal(Blockchain)
  194.         if err != nil {
  195.             log.Println(err)
  196.         }
  197.  
  198.         spew.Dump(Blockchain)
  199.  
  200.         mutex.Lock()
  201.         rw.WriteString(fmt.Sprintf("%s\n", string(bytes)))
  202.         rw.Flush()
  203.         mutex.Unlock()
  204.     }
  205.  
  206. }
  207.  
  208. func main() {
  209.     t := time.Now()
  210.     genesisBlock := Block{}
  211.     genesisBlock = Block{0, t.String(), 0, calculateHash(genesisBlock), ""}
  212.  
  213.     Blockchain = append(Blockchain, genesisBlock)
  214.  
  215.     // LibP2P code uses golog to log messages. They log with different
  216.     // string IDs (i.e. "swarm"). We can control the verbosity level for
  217.     // all loggers with:
  218.     //golog.SetAllLoggers(gologging.INFO)Change to DEBUG for extra info
  219.  
  220.  
  221.     // Parse options from the command line
  222.     listenF := flag.Int("l", 0, "wait for incoming connections")
  223.     target := flag.String("d", "", "target peer to dial")
  224.     secio := flag.Bool("secio", false, "enable secio")
  225.     seed := flag.Int64("seed", 0, "set random seed for id generation")
  226.     flag.Parse()
  227.  
  228.     if *listenF == 0 {
  229.         log.Fatal("Please provide a port to bind on with -l")
  230.     }
  231.  
  232.     // Make a host that listens on the given multiaddress
  233.     ha, err := makeBasicHost(*listenF, *secio, *seed)
  234.     if err != nil {
  235.         log.Fatal(err)
  236.     }
  237.  
  238.     if *target == "" {
  239.         log.Println("listening for connections")
  240.         // Set a stream handler on host A. /p2p/1.0.0 is
  241.         // a user-defined protocol name.
  242.         ha.SetStreamHandler("/p2p/1.0.0", handleStream)
  243.  
  244.         select {} // hang forever
  245.         /**** This is where the listener code ends ****/
  246.     } else {
  247.         ha.SetStreamHandler("/p2p/1.0.0", handleStream)
  248.  
  249.         // The following code extracts target's peer ID from the
  250.         // given multiaddress
  251.         ipfsaddr, err := ma.NewMultiaddr(*target)
  252.         if err != nil {
  253.             log.Fatalln(err)
  254.         }
  255.  
  256.         pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS)
  257.         if err != nil {
  258.             log.Fatalln(err)
  259.         }
  260.  
  261.         peerid, err := peer.IDB58Decode(pid)
  262.         if err != nil {
  263.             log.Fatalln(err)
  264.         }
  265.  
  266.         // Decapsulate the /ipfs/<peerID> part from the target
  267.         // /ip4/<a.b.c.d>/ipfs/<peer> becomes /ip4/<a.b.c.d>
  268.         targetPeerAddr, _ := ma.NewMultiaddr(
  269.             fmt.Sprintf("/ipfs/%s", peer.IDB58Encode(peerid)))
  270.         targetAddr := ipfsaddr.Decapsulate(targetPeerAddr)
  271.  
  272.         // We have a peer ID and a targetAddr so we add it to the peerstore
  273.         // so LibP2P knows how to contact it
  274.         ha.Peerstore().AddAddr(peerid, targetAddr, pstore.PermanentAddrTTL)
  275.  
  276.         log.Println("opening stream")
  277.         // make a new stream from host B to host A
  278.         // it should be handled on host A by the handler we set above because
  279.         // we use the same /p2p/1.0.0 protocol
  280.         s, err := ha.NewStream(context.Background(), peerid, "/p2p/1.0.0")
  281.         if err != nil {
  282.             log.Fatalln(err)
  283.         }
  284.         // Create a buffered stream so that read and writes are non blocking.
  285.         rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s))
  286.  
  287.         // Create a thread to read and write data.
  288.         go writeData(rw)
  289.         go readData(rw)
  290.  
  291.         select {} // hang forever
  292.  
  293.     }
  294. }
  295.  
  296. // make sure block is valid by checking index, and comparing the hash of the previous block
  297. func isBlockValid(newBlock, oldBlock Block) bool {
  298.     if oldBlock.Index+1 != newBlock.Index {
  299.         return false
  300.     }
  301.  
  302.     if oldBlock.Hash != newBlock.PrevHash {
  303.         return false
  304.     }
  305.  
  306.     if calculateHash(newBlock) != newBlock.Hash {
  307.         return false
  308.     }
  309.  
  310.     return true
  311. }
  312.  
  313. // SHA256 hashing
  314. func calculateHash(block Block) string {
  315.     record := strconv.Itoa(block.Index) + block.Timestamp + strconv.Itoa(block.BPM) + block.PrevHash
  316.     h := sha256.New()
  317.     h.Write([]byte(record))
  318.     hashed := h.Sum(nil)
  319.     return hex.EncodeToString(hashed)
  320. }
  321.  
  322. // create a new block using previous block's hash
  323. func generateBlock(oldBlock Block, BPM int) Block {
  324.  
  325.     var newBlock Block
  326.  
  327.     t := time.Now()
  328.  
  329.     newBlock.Index = oldBlock.Index + 1
  330.     newBlock.Timestamp = t.String()
  331.     newBlock.BPM = BPM
  332.     newBlock.PrevHash = oldBlock.Hash
  333.     newBlock.Hash = calculateHash(newBlock)
  334.  
  335.     return newBlock
  336. }
  337.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement