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 if !bc.VerifyBlock(block) {
63 return errors.New("Block could not be verified")
64 }
65 bc.LastBlock = block.Copy()
66 err := bc.blockdb.Put(block.Hash[:], block.Bytes())
67 return err
68}
69
70func (bc *Blockchain) GetBlock(hash Hash) (*Block, error) {
71 v, err := bc.blockdb.Get(hash[:])
72 if err != nil {
73 return nil, err
74 }
75 block, err := BlockFromBytes(v)
76 if err != nil {
77 return nil, err
78 }
79 return block, nil
80}
81
82func (bc *Blockchain) GetPrevBlock(hash Hash) (*Block, error) {
83 currentBlock, err := bc.GetBlock(hash)
84 if err != nil {
85 return nil, err
86 }
87 if currentBlock.PrevHash.IsZero() {
88 return nil, errors.New("This was the oldest block")
89 }
90 prevBlock, err := bc.GetBlock(currentBlock.PrevHash)
91 if err != nil {
92 return nil, err
93 }
94
95 return prevBlock, nil
96}
97
98func (bc *Blockchain) verifyBlockSignature(block *Block) bool {
99 // check if the signer is one of the blockchain.AuthMiners
100 signerIsMiner := false
101 for _, pubK := range bc.PoA.AuthMiners {
102 if bytes.Equal(PackPubK(pubK), PackPubK(block.MinerPubK)) {
103 signerIsMiner = true
104 }
105 }
106 if !signerIsMiner && len(bc.PoA.AuthMiners) > 0 {
107 fmt.Println("signer is not miner")
108 return false
109 }
110
111 // get the signature
112 sig, err := SignatureFromBytes(block.Signature)
113 if err != nil {
114 fmt.Println("error parsing signature")
115 return false
116 }
117
118 // check if the signature is by the miner
119 return VerifySignature(block.MinerPubK, block.Hash[:], *sig)
120}
121
122func (bc *Blockchain) VerifyBlock(block *Block) bool {
123 // verify block signature
124 // TODO for the moment just covered the case of PoA blockchain
125 if !bc.verifyBlockSignature(block) {
126 fmt.Println("signature verification error")
127 return false
128 }
129
130 // verify timestamp
131
132 // verify prev hash
133 // check that the block.PrevHash is the blockchain current last block
134 if !bytes.Equal(block.PrevHash[:], bc.LastBlock.Hash[:]) {
135 fmt.Println("block.PrevHash not equal to last block hash")
136 return false
137 }
138
139 // verify block height
140 // check that the block height is the last block + 1
141 if block.Height != bc.LastBlock.Height+1 {
142 fmt.Println("block.Height error")
143 return false
144 }
145
146 // verify block transactions
147
148 return true
149}
150
151// func (bc *Blockchain) Mint(toAddr Address, amount uint64) error {
152// fromAddr := Address(HashBytes([]byte("mint")))
153// out :=
154// tx := NewTx(fromAddr, toAddr, []Input, )
155// }