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, ) // }