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	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 (not if the block is the genesis block)
147	if !bytes.Equal(block.Txs[0].TxId[:], GenesisHashTxInput[:]) {
148		for _, tx := range block.Txs {
149			txVerified := CheckTx(&tx)
150			if !txVerified {
151				fmt.Println("tx could not be verified")
152				return false
153			}
154		}
155	}
156
157	// TODO in --> out0
158	//          -> out1
159	//          -> ...
160
161	return true
162}
163
164// func (bc *Blockchain) Mint(toAddr Address, amount uint64) error {
165//         fromAddr := Address(HashBytes([]byte("mint")))
166//         out :=
167//         tx := NewTx(fromAddr, toAddr, []Input, )
168// }