You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

148 lines
3.1 KiB

package core
import (
"bytes"
"crypto/ecdsa"
"errors"
"fmt"
"github.com/arnaucube/slowlorisdb/db"
)
type PoA struct {
AuthMiners []*ecdsa.PublicKey
}
type Blockchain struct {
Id []byte // Id allows to have multiple blockchains
Difficulty uint64
Genesis Hash
LastBlock *Block
blockdb *db.Db
txdb *db.Db
PoA PoA
}
func NewBlockchain(database *db.Db, dif uint64) *Blockchain {
blockchain := &Blockchain{
Id: []byte{},
Difficulty: dif,
Genesis: HashBytes([]byte("genesis")),
LastBlock: &Block{},
blockdb: database,
PoA: PoA{},
}
return blockchain
}
func NewPoABlockchain(database *db.Db, authNodes []*ecdsa.PublicKey) *Blockchain {
poa := PoA{
AuthMiners: authNodes,
}
blockchain := &Blockchain{
Id: []byte{},
Difficulty: uint64(0),
Genesis: HashBytes([]byte("genesis")), // tmp
LastBlock: &Block{},
blockdb: database,
PoA: poa,
}
return blockchain
}
func (bc *Blockchain) GetHeight() uint64 {
return bc.LastBlock.Height
}
func (bc *Blockchain) GetLastBlock() *Block {
return bc.LastBlock
}
func (bc *Blockchain) AddBlock(block *Block) error {
bc.LastBlock = block
err := bc.blockdb.Put(block.Hash[:], block.Bytes())
return err
}
func (bc *Blockchain) GetBlock(hash Hash) (*Block, error) {
v, err := bc.blockdb.Get(hash[:])
if err != nil {
return nil, err
}
block, err := BlockFromBytes(v)
if err != nil {
return nil, err
}
return block, nil
}
func (bc *Blockchain) GetPrevBlock(hash Hash) (*Block, error) {
currentBlock, err := bc.GetBlock(hash)
if err != nil {
return nil, err
}
if currentBlock.PrevHash.IsZero() {
return nil, errors.New("This was the oldest block")
}
prevBlock, err := bc.GetBlock(currentBlock.PrevHash)
if err != nil {
return nil, err
}
return prevBlock, nil
}
func (bc *Blockchain) verifyBlockSignature(block *Block) bool {
// check if the signer is one of the blockchain.AuthMiners
signerIsMiner := false
for _, pubK := range bc.PoA.AuthMiners {
if bytes.Equal(PackPubK(pubK), block.Miner[:]) {
signerIsMiner = true
}
}
if !signerIsMiner && len(bc.PoA.AuthMiners) > 0 {
return false
}
// get the signature
sig, err := SignatureFromBytes(block.Signature)
if err != nil {
return false
}
// check if the signature is by the miner
return VerifySignature(block.MinerPubK, block.Hash[:], *sig)
}
func (bc *Blockchain) VerifyBlock(block *Block) bool {
// verify block signature
if !bc.verifyBlockSignature(block) {
return false
}
// verify timestamp
// verify prev hash
// check that the block.PrevHash is the blockchain current last block
fmt.Println(block.PrevHash)
fmt.Println(bc.LastBlock.Hash)
if !bytes.Equal(block.PrevHash[:], bc.LastBlock.Hash[:]) {
return false
}
// verify block height
// check that the block height is the last block + 1
if block.Height != bc.LastBlock.Height+1 {
return false
}
// verify block transactions
return true
}
// func (bc *Blockchain) Mint(toAddr Address, amount uint64) error {
// fromAddr := Address(HashBytes([]byte("mint")))
// out :=
// tx := NewTx(fromAddr, toAddr, []Input, )
// }