arnaucube
arnaucube/slowlorisdbPublic Self-hosted repository
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// }