slowlorisdb/core/blockchain.go
core/blockchain.goRaw
1package core
2
3import (
4 "bytes"
5 "crypto/ecdsa"
6 "errors"
7 "fmt"
8
9 "github.com/arnaucube/slowlorisdb/db"
10)
11
12type PoA struct {
13 AuthMiners []*ecdsa.PublicKey
14}
15
16type Blockchain struct {
17 Id []byte // Id allows to have multiple blockchains
18 Difficulty uint64
19 Genesis Hash
20 LastBlock *Block
21 blockdb *db.Db
22 txdb *db.Db
23 PoA PoA
24}
25
26func NewBlockchain(database *db.Db, dif uint64) *Blockchain {
27 blockchain := &Blockchain{
28 Id: []byte{},
29 Difficulty: dif,
30 Genesis: HashBytes([]byte("genesis")),
31 LastBlock: &Block{},
32 blockdb: database,
33 PoA: PoA{},
34 }
35 return blockchain
36}
37
38func NewPoABlockchain(database *db.Db, authNodes []*ecdsa.PublicKey) *Blockchain {
39 poa := PoA{
40 AuthMiners: authNodes,
41 }
42 blockchain := &Blockchain{
43 Id: []byte{},
44 Difficulty: uint64(0),
45 Genesis: HashBytes([]byte("genesis")), // tmp
46 LastBlock: &Block{},
47 blockdb: database,
48 PoA: poa,
49 }
50 return blockchain
51}
52
53func (bc *Blockchain) GetHeight() uint64 {
54 return bc.LastBlock.Height
55}
56
57func (bc *Blockchain) GetLastBlock() *Block {
58 return bc.LastBlock
59}
60
61func (bc *Blockchain) AddBlock(block *Block) error {
62 bc.LastBlock = block
63 err := bc.blockdb.Put(block.Hash[:], block.Bytes())
64 return err
65}
66
67func (bc *Blockchain) GetBlock(hash Hash) (*Block, error) {
68 v, err := bc.blockdb.Get(hash[:])
69 if err != nil {
70 return nil, err
71 }
72 block, err := BlockFromBytes(v)
73 if err != nil {
74 return nil, err
75 }
76 return block, nil
77}
78
79func (bc *Blockchain) GetPrevBlock(hash Hash) (*Block, error) {
80 currentBlock, err := bc.GetBlock(hash)
81 if err != nil {
82 return nil, err
83 }
84 if currentBlock.PrevHash.IsZero() {
85 return nil, errors.New("This was the oldest block")
86 }
87 prevBlock, err := bc.GetBlock(currentBlock.PrevHash)
88 if err != nil {
89 return nil, err
90 }
91
92 return prevBlock, nil
93}
94
95func (bc *Blockchain) verifyBlockSignature(block *Block) bool {
96 // check if the signer is one of the blockchain.AuthMiners
97 signerIsMiner := false
98 for _, pubK := range bc.PoA.AuthMiners {
99 if bytes.Equal(PackPubK(pubK), block.Miner[:]) {
100 signerIsMiner = true
101 }
102 }
103 if !signerIsMiner && len(bc.PoA.AuthMiners) > 0 {
104 return false
105 }
106
107 // get the signature
108 sig, err := SignatureFromBytes(block.Signature)
109 if err != nil {
110 return false
111 }
112
113 // check if the signature is by the miner
114 return VerifySignature(block.MinerPubK, block.Hash[:], *sig)
115}
116
117func (bc *Blockchain) VerifyBlock(block *Block) bool {
118 // verify block signature
119 if !bc.verifyBlockSignature(block) {
120 return false
121 }
122
123 // verify timestamp
124
125 // verify prev hash
126 // check that the block.PrevHash is the blockchain current last block
127 fmt.Println(block.PrevHash)
128 fmt.Println(bc.LastBlock.Hash)
129 if !bytes.Equal(block.PrevHash[:], bc.LastBlock.Hash[:]) {
130 return false
131 }
132
133 // verify block height
134 // check that the block height is the last block + 1
135 if block.Height != bc.LastBlock.Height+1 {
136 return false
137 }
138
139 // verify block transactions
140
141 return true
142}
143
144// func (bc *Blockchain) Mint(toAddr Address, amount uint64) error {
145// fromAddr := Address(HashBytes([]byte("mint")))
146// out :=
147// tx := NewTx(fromAddr, toAddr, []Input, )
148// }