-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathblockchain.go
126 lines (107 loc) · 2.75 KB
/
blockchain.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package main
import (
"bytes"
"crypto/sha256"
"errors"
"math"
"math/big"
"strconv"
"time"
)
const diff = 20 //Difficulty
type Block struct {
Index int
Timestamp string
Data string
Hash []byte
PrevHash []byte
Nonce uint64
}
type Blockchain struct {
blocks []*Block
}
func calculateHash(block Block, nonce uint64) []byte {
record := string(rune(block.Index)) + block.Timestamp + block.Data + string(block.PrevHash) + strconv.Itoa(int(nonce))
h := sha256.New()
h.Write([]byte(record))
hashed := h.Sum(nil)
return hashed
}
func generateBlock(index int, prevHash []byte, Data string) Block {
newBlock := Block{
Index: index,
Timestamp: time.Now().String(),
Data: Data,
PrevHash: prevHash,
}
/*
err := newBlock.mineBlock()
if err != nil {
return newBlock, errors.New("error: could not create a block")
}*/
return newBlock
}
func (blk *Block) mineBlock(start uint64, count uint64) error {
target := big.NewInt(1)
target.Lsh(target, uint(256-diff))
nonce := start
for nonce < start+count && nonce < math.MaxUint64 {
hash := calculateHash(*blk, nonce)
hashInt := new(big.Int)
hashInt.SetBytes(hash[:])
if hashInt.Cmp(target) == -1 {
blk.Nonce = nonce
blk.Hash = hash
return nil
} else {
nonce++
}
}
if nonce >= math.MaxUint64 {
return errors.New("error: block has no solution") //Could play around with extra nonce, etc.}
} else {
return errors.New("error: could not find solution within given nonce range")
}
}
func (chain *Blockchain) addBlock(blk *Block) error {
var prevHash []byte
if chain.getSize() == 0 {
var temp [sha256.Size]byte
prevHash = temp[:]
}
if chain.getSize() > 0 {
prevHash = chain.blocks[len(chain.blocks)-1].Hash
}
if err := verify(blk, prevHash); err != nil {
return err
}
chain.blocks = append(chain.blocks, blk)
return nil
}
func (chain *Blockchain) getBlock(index int) (*Block, error) {
if index >= chain.getSize() {
return &Block{}, errors.New("error: index out of range")
}
return chain.blocks[index], nil
}
func verify(newBlock *Block, prevHash []byte) error {
if !bytes.Equal(prevHash, newBlock.PrevHash) {
//fmt.Printf("Hash1: %x\nHash2: %x\n", prevHash, newBlock.PrevHash)
return errors.New("error: previous hash is different")
}
if !bytes.Equal(calculateHash(*newBlock, newBlock.Nonce), newBlock.Hash) {
return errors.New("error: Hash with nonce is invalid")
}
return nil
}
func (chain Blockchain) getSize() int {
return len(chain.blocks)
}
// to be used with multiple chains being received
func (chain Blockchain) replaceChain(newBlocks *Blockchain) error {
if len(newBlocks.blocks) > len(chain.blocks) {
chain.blocks = newBlocks.blocks
return nil
}
return errors.New("error: received chain is shorter than the original chain")
}