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.

241 lines
5.7 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. package core
  2. import (
  3. "bytes"
  4. "crypto/ecdsa"
  5. "encoding/hex"
  6. "errors"
  7. "fmt"
  8. "strconv"
  9. "github.com/arnaucube/slowlorisdb/db"
  10. log "github.com/sirupsen/logrus"
  11. lvldberrors "github.com/syndtr/goleveldb/leveldb/errors"
  12. )
  13. type PoA struct {
  14. AuthMiners []*ecdsa.PublicKey
  15. }
  16. type 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. addressdb *db.Db
  24. walletsdb *db.Db
  25. PoA PoA
  26. }
  27. func NewBlockchain(database *db.Db, dif uint64) *Blockchain {
  28. blockchain := &Blockchain{
  29. Id: []byte{},
  30. Difficulty: dif,
  31. Genesis: HashBytes([]byte("genesis")),
  32. LastBlock: &Block{},
  33. blockdb: database,
  34. PoA: PoA{},
  35. }
  36. return blockchain
  37. }
  38. func NewPoABlockchain(database *db.Db, authNodes []*ecdsa.PublicKey) *Blockchain {
  39. blockDb := database.WithPrefix([]byte("blockDb"))
  40. txDb := database.WithPrefix([]byte("txDb"))
  41. addressDb := database.WithPrefix([]byte("addressDb"))
  42. poa := PoA{
  43. AuthMiners: authNodes,
  44. }
  45. blockchain := &Blockchain{
  46. Id: []byte{},
  47. Difficulty: uint64(0),
  48. Genesis: HashBytes([]byte("genesis")), // tmp
  49. LastBlock: &Block{},
  50. blockdb: blockDb,
  51. txdb: txDb,
  52. addressdb: addressDb,
  53. PoA: poa,
  54. }
  55. return blockchain
  56. }
  57. func (bc *Blockchain) GetHeight() uint64 {
  58. return bc.LastBlock.Height
  59. }
  60. func (bc *Blockchain) GetLastBlock() *Block {
  61. return bc.LastBlock
  62. }
  63. func (bc *Blockchain) AddBlock(block *Block) error {
  64. if !bc.VerifyBlock(block) {
  65. return errors.New("Block could not be verified")
  66. }
  67. bc.LastBlock = block.Copy()
  68. err := bc.blockdb.Put(block.Hash[:], block.Bytes())
  69. if err != nil {
  70. return err
  71. }
  72. // add each tx to txDb & update addressDb balances
  73. for _, tx := range block.Txs {
  74. err = bc.txdb.Put(tx.TxId[:], tx.Bytes())
  75. if err != nil {
  76. return err
  77. }
  78. bc.UpdateWalletsWithNewTx(&tx)
  79. }
  80. return nil
  81. }
  82. func (bc *Blockchain) UpdateWalletsWithNewTx(tx *Tx) error {
  83. for _, in := range tx.Inputs {
  84. balanceBytes, err := bc.addressdb.Get(PackPubK(tx.From))
  85. if err != nil {
  86. return err
  87. }
  88. balance := Uint64FromBytes(balanceBytes)
  89. balance = balance - in.Value
  90. err = bc.addressdb.Put(PackPubK(tx.From), Uint64ToBytes(balance))
  91. if err != nil {
  92. return err
  93. }
  94. log.Info("sent-->: balance of " + hex.EncodeToString(PackPubK(tx.From)[:10]) + ": " + strconv.Itoa(int(balance)))
  95. }
  96. for _, out := range tx.Outputs {
  97. balanceBytes, err := bc.addressdb.Get(PackPubK(tx.To))
  98. if err != nil && err != lvldberrors.ErrNotFound {
  99. return err
  100. }
  101. if err == lvldberrors.ErrNotFound {
  102. balanceBytes = Uint64ToBytes(uint64(0))
  103. }
  104. balance := Uint64FromBytes(balanceBytes)
  105. balance = balance + out.Value
  106. err = bc.addressdb.Put(PackPubK(tx.To), Uint64ToBytes(balance))
  107. if err != nil {
  108. return err
  109. }
  110. log.Info("--> received: balance of " + hex.EncodeToString(PackPubK(tx.To)[:10]) + ": " + strconv.Itoa(int(balance)))
  111. }
  112. return nil
  113. }
  114. func (bc *Blockchain) GetBlock(hash Hash) (*Block, error) {
  115. v, err := bc.blockdb.Get(hash[:])
  116. if err != nil {
  117. return nil, err
  118. }
  119. block, err := BlockFromBytes(v)
  120. if err != nil {
  121. return nil, err
  122. }
  123. return block, nil
  124. }
  125. func (bc *Blockchain) GetBalance(pubK *ecdsa.PublicKey) (uint64, error) {
  126. balanceBytes, err := bc.addressdb.Get(PackPubK(pubK))
  127. if err != nil {
  128. return uint64(0), err
  129. }
  130. balance := Uint64FromBytes(balanceBytes)
  131. return balance, nil
  132. }
  133. func (bc *Blockchain) GetPrevBlock(hash Hash) (*Block, error) {
  134. currentBlock, err := bc.GetBlock(hash)
  135. if err != nil {
  136. return nil, err
  137. }
  138. if currentBlock.PrevHash.IsZero() {
  139. return nil, errors.New("This was the oldest block")
  140. }
  141. prevBlock, err := bc.GetBlock(currentBlock.PrevHash)
  142. if err != nil {
  143. return nil, err
  144. }
  145. return prevBlock, nil
  146. }
  147. func (bc *Blockchain) verifyBlockSignature(block *Block) bool {
  148. // check if the signer is one of the blockchain.AuthMiners
  149. signerIsMiner := false
  150. for _, pubK := range bc.PoA.AuthMiners {
  151. if bytes.Equal(PackPubK(pubK), PackPubK(block.MinerPubK)) {
  152. signerIsMiner = true
  153. }
  154. }
  155. if !signerIsMiner && len(bc.PoA.AuthMiners) > 0 {
  156. log.Error("signer is not miner")
  157. return false
  158. }
  159. // get the signature
  160. sig, err := SignatureFromBytes(block.Signature)
  161. if err != nil {
  162. log.Error("error parsing signature")
  163. return false
  164. }
  165. // check if the signature is by the miner
  166. return VerifySignature(block.MinerPubK, block.Hash[:], *sig)
  167. }
  168. func (bc *Blockchain) VerifyBlock(block *Block) bool {
  169. // verify block signature
  170. // for the moment just covered the case of PoA blockchain
  171. if !bc.verifyBlockSignature(block) {
  172. log.Error("signature verification error")
  173. return false
  174. }
  175. // verify timestamp
  176. if block.Timestamp.Unix() < bc.LastBlock.Timestamp.Unix() {
  177. return false
  178. }
  179. // verify prev hash
  180. // check that the block.PrevHash is the blockchain current last block
  181. if !bytes.Equal(block.PrevHash[:], bc.LastBlock.Hash[:]) {
  182. fmt.Println(block.PrevHash.String())
  183. fmt.Println(bc.LastBlock.Hash.String())
  184. log.Error("block.PrevHash not equal to last block hash")
  185. return false
  186. }
  187. // verify block height
  188. // check that the block height is the last block + 1
  189. if block.Height != bc.LastBlock.Height+1 {
  190. log.Error("block.Height error")
  191. return false
  192. }
  193. // verify block transactions (not if the block is the genesis block)
  194. if !bytes.Equal(block.Txs[0].TxId[:], GenesisHashTxInput[:]) {
  195. for _, tx := range block.Txs {
  196. txVerified := CheckTx(&tx)
  197. if !txVerified {
  198. log.Error("tx could not be verified")
  199. return false
  200. }
  201. }
  202. }
  203. // TODO in --> out0
  204. // -> out1
  205. // -> ...
  206. return true
  207. }
  208. // func (bc *Blockchain) Mint(toAddr Address, amount uint64) error {
  209. // fromAddr := Address(HashBytes([]byte("mint")))
  210. // out :=
  211. // tx := NewTx(fromAddr, toAddr, []Input, )
  212. // }