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

  1. package core
  2. import (
  3. "bytes"
  4. "crypto/ecdsa"
  5. "errors"
  6. "fmt"
  7. "github.com/arnaucube/slowlorisdb/db"
  8. )
  9. type PoA struct {
  10. AuthMiners []*ecdsa.PublicKey
  11. }
  12. type Blockchain struct {
  13. Id []byte // Id allows to have multiple blockchains
  14. Difficulty uint64
  15. Genesis Hash
  16. LastBlock *Block
  17. blockdb *db.Db
  18. txdb *db.Db
  19. PoA PoA
  20. }
  21. func NewBlockchain(database *db.Db, dif uint64) *Blockchain {
  22. blockchain := &Blockchain{
  23. Id: []byte{},
  24. Difficulty: dif,
  25. Genesis: HashBytes([]byte("genesis")),
  26. LastBlock: &Block{},
  27. blockdb: database,
  28. PoA: PoA{},
  29. }
  30. return blockchain
  31. }
  32. func NewPoABlockchain(database *db.Db, authNodes []*ecdsa.PublicKey) *Blockchain {
  33. poa := PoA{
  34. AuthMiners: authNodes,
  35. }
  36. blockchain := &Blockchain{
  37. Id: []byte{},
  38. Difficulty: uint64(0),
  39. Genesis: HashBytes([]byte("genesis")), // tmp
  40. LastBlock: &Block{},
  41. blockdb: database,
  42. PoA: poa,
  43. }
  44. return blockchain
  45. }
  46. func (bc *Blockchain) GetHeight() uint64 {
  47. return bc.LastBlock.Height
  48. }
  49. func (bc *Blockchain) GetLastBlock() *Block {
  50. return bc.LastBlock
  51. }
  52. func (bc *Blockchain) AddBlock(block *Block) error {
  53. bc.LastBlock = block
  54. err := bc.blockdb.Put(block.Hash[:], block.Bytes())
  55. return err
  56. }
  57. func (bc *Blockchain) GetBlock(hash Hash) (*Block, error) {
  58. v, err := bc.blockdb.Get(hash[:])
  59. if err != nil {
  60. return nil, err
  61. }
  62. block, err := BlockFromBytes(v)
  63. if err != nil {
  64. return nil, err
  65. }
  66. return block, nil
  67. }
  68. func (bc *Blockchain) GetPrevBlock(hash Hash) (*Block, error) {
  69. currentBlock, err := bc.GetBlock(hash)
  70. if err != nil {
  71. return nil, err
  72. }
  73. if currentBlock.PrevHash.IsZero() {
  74. return nil, errors.New("This was the oldest block")
  75. }
  76. prevBlock, err := bc.GetBlock(currentBlock.PrevHash)
  77. if err != nil {
  78. return nil, err
  79. }
  80. return prevBlock, nil
  81. }
  82. func (bc *Blockchain) verifyBlockSignature(block *Block) bool {
  83. // check if the signer is one of the blockchain.AuthMiners
  84. signerIsMiner := false
  85. for _, pubK := range bc.PoA.AuthMiners {
  86. if bytes.Equal(PackPubK(pubK), block.Miner[:]) {
  87. signerIsMiner = true
  88. }
  89. }
  90. if !signerIsMiner && len(bc.PoA.AuthMiners) > 0 {
  91. return false
  92. }
  93. // get the signature
  94. sig, err := SignatureFromBytes(block.Signature)
  95. if err != nil {
  96. return false
  97. }
  98. // check if the signature is by the miner
  99. return VerifySignature(block.MinerPubK, block.Hash[:], *sig)
  100. }
  101. func (bc *Blockchain) VerifyBlock(block *Block) bool {
  102. // verify block signature
  103. if !bc.verifyBlockSignature(block) {
  104. return false
  105. }
  106. // verify timestamp
  107. // verify prev hash
  108. // check that the block.PrevHash is the blockchain current last block
  109. fmt.Println(block.PrevHash)
  110. fmt.Println(bc.LastBlock.Hash)
  111. if !bytes.Equal(block.PrevHash[:], bc.LastBlock.Hash[:]) {
  112. return false
  113. }
  114. // verify block height
  115. // check that the block height is the last block + 1
  116. if block.Height != bc.LastBlock.Height+1 {
  117. return false
  118. }
  119. // verify block transactions
  120. return true
  121. }
  122. // func (bc *Blockchain) Mint(toAddr Address, amount uint64) error {
  123. // fromAddr := Address(HashBytes([]byte("mint")))
  124. // out :=
  125. // tx := NewTx(fromAddr, toAddr, []Input, )
  126. // }