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.

592 lines
18 KiB

  1. package blockchain
  2. import "os"
  3. import "fmt"
  4. import "sort"
  5. import "sync"
  6. import "bytes"
  7. import "sync/atomic"
  8. import log "github.com/sirupsen/logrus"
  9. import "github.com/romana/rlog"
  10. import "github.com/deroproject/derosuite/config"
  11. import "github.com/deroproject/derosuite/crypto"
  12. import "github.com/deroproject/derosuite/globals"
  13. import "github.com/deroproject/derosuite/storage"
  14. import "github.com/deroproject/derosuite/difficulty"
  15. import "github.com/deroproject/derosuite/crypto/ringct"
  16. // all components requiring access to blockchain must use , this struct to communicate
  17. // this structure must be update while mutex
  18. type Blockchain struct {
  19. store storage.Store // interface to storage layer
  20. Height uint64 // chain height is always 1 more than block
  21. height_seen uint64 // height seen on peers
  22. Top_ID crypto.Hash // id of the top block
  23. Difficulty uint64 // current cumulative difficulty
  24. Mempool *Mempool
  25. sync.RWMutex
  26. }
  27. var logger *log.Entry
  28. // All blockchain activity is store in a single
  29. /* do initialisation , setup storage, put genesis block and chain in store
  30. This is the first component to get up
  31. Global parameters are picked up from the config package
  32. */
  33. func Blockchain_Start(params map[string]interface{}) (*Blockchain, error) {
  34. var err error
  35. var chain Blockchain
  36. logger = globals.Logger.WithFields(log.Fields{"com": "BLKCHAIN"})
  37. logger.Infof("Initialising blockchain")
  38. init_checkpoints() // init some hard coded checkpoints
  39. chain.store = storage.Bolt_backend // setup backend
  40. chain.store.Init(params) // init backend
  41. // genesis block not in chain, add it to chain, together with its miner tx
  42. // make sure genesis is in the store
  43. if !chain.Block_Exists(globals.Config.Genesis_Block_Hash) {
  44. logger.Debugf("Genesis block not in store, add it now")
  45. bl := Generate_Genesis_Block()
  46. chain.Store_BL(&bl)
  47. chain.Store_TOP_ID(globals.Config.Genesis_Block_Hash)
  48. // store height mapping, genesis block is at id
  49. chain.Store_BL_ID_at_Height(0, globals.Config.Genesis_Block_Hash)
  50. }
  51. // load the chain from the disk
  52. chain.Initialise_Chain_From_DB()
  53. // init mempool
  54. chain.Mempool, err = Init_Mempool(params)
  55. _ = err
  56. atomic.AddUint32(&globals.Subsystem_Active, 1) // increment subsystem
  57. // chain.Inject_Alt_Chain()
  58. return &chain, nil
  59. }
  60. // this function is called to read blockchain state from DB
  61. // It is callable at any point in time
  62. func (chain *Blockchain) Initialise_Chain_From_DB() {
  63. chain.Lock()
  64. defer chain.Unlock()
  65. // locate top block
  66. chain.Top_ID = chain.Load_TOP_ID()
  67. chain.Height = (chain.Load_Height_for_BL_ID(chain.Top_ID) + 1)
  68. logger.Infof("Chain Top Block %x Height %d", chain.Top_ID, chain.Height)
  69. }
  70. // before shutdown , make sure p2p is confirmed stopped
  71. func (chain *Blockchain) Shutdown() {
  72. chain.Mempool.Shutdown() // shutdown mempool first
  73. chain.Lock() // take the lock as chain is no longer in unsafe mode
  74. logger.Infof("Stopping Blockchain")
  75. chain.store.Shutdown()
  76. atomic.AddUint32(&globals.Subsystem_Active, ^uint32(0)) // this decrement 1 fom subsystem
  77. }
  78. func (chain *Blockchain) Get_Height() uint64 {
  79. return chain.Height
  80. }
  81. func (chain *Blockchain) Get_Top_ID() crypto.Hash {
  82. return chain.Top_ID
  83. }
  84. func (chain *Blockchain) Get_Difficulty() uint64 {
  85. return chain.Get_Difficulty_At_Block(chain.Top_ID)
  86. }
  87. func (chain *Blockchain) Get_Network_HashRate() uint64 {
  88. return chain.Get_Difficulty_At_Block(chain.Top_ID) / config.BLOCK_TIME
  89. }
  90. // confirm whether the block exist in the data
  91. // this only confirms whether the block has been downloaded
  92. // a separate check is required, whether the block is valid ( satifies PoW and other conditions)
  93. // we will not add a block to store, until it satisfies PoW
  94. func (chain *Blockchain) Block_Exists(h crypto.Hash) bool {
  95. _, err := chain.Load_BL_FROM_ID(h)
  96. if err == nil {
  97. return true
  98. }
  99. return false
  100. }
  101. /* this function will extend the chain and increase the height,
  102. this function trigger checks for the block and transactions for validity, recursively
  103. this is the only function which change chain height and top id
  104. */
  105. func (chain *Blockchain) Chain_Add(bl *Block) (result bool) {
  106. chain.Lock()
  107. defer chain.Unlock()
  108. result = false
  109. block_hash := bl.GetHash()
  110. // make sure that the block refers to some where in the chain
  111. // and also make sure block is not the genesis block
  112. if block_hash == globals.Config.Genesis_Block_Hash {
  113. logger.Debugf("Genesis block already in chain skipping it")
  114. return
  115. }
  116. // check if block already exist skip it
  117. if chain.Block_Exists(block_hash) {
  118. logger.Debugf("block already in chain skipping it %x", block_hash)
  119. return
  120. }
  121. if chain.Height > 16996 {
  122. // os.Exit(0)
  123. }
  124. if chain.Height > 17000 {
  125. //os.Exit(0)
  126. }
  127. if chain.Height > 17010 {
  128. // os.Exit(0)
  129. }
  130. if chain.Height > 16996000 {
  131. os.Exit(0)
  132. }
  133. // make sure prev_hash refers to some point in our our chain
  134. // there is an edge case, where we know child but still donot know parent
  135. // this might be some some corrupted miner or initial sync
  136. if !chain.Block_Exists(bl.Prev_Hash) {
  137. // TODO we must queue this block for say 60 minutes, if parents donot appear it, discard it
  138. logger.Warnf("Prev_Hash no where in the chain, skipping it till we get a parent %x", block_hash)
  139. return
  140. }
  141. PoW := bl.GetPoWHash()
  142. current_difficulty := chain.Get_Difficulty_At_Block(bl.Prev_Hash)
  143. logger.Debugf("Difficulty at height %d is %d", chain.Load_Height_for_BL_ID(bl.Prev_Hash), current_difficulty)
  144. // check if the PoW is satisfied
  145. if !difficulty.CheckPowHash(PoW, current_difficulty) { // if invalid Pow, reject the bloc
  146. logger.Warnf("Block %x has invalid PoW, ignoring it", block_hash)
  147. return false
  148. }
  149. // check we need to extend the chain or do a soft fork
  150. if bl.Prev_Hash == chain.Top_ID {
  151. // we need to extend the chain
  152. //log.Debugf("Extendin chain using block %x", block_hash )
  153. chain.Store_BL(bl)
  154. chain.Store_TOP_ID(block_hash) // make new block top block
  155. //chain.Add_Child(bl.Prev_Hash, block_hash) // add the new block as chil
  156. chain.Store_Block_Child(bl.Prev_Hash, block_hash)
  157. chain.Store_BL_ID_at_Height(chain.Height, block_hash)
  158. // lower the window, where top_id and chain height are different
  159. chain.Height = chain.Height + 1 // increment height
  160. chain.Top_ID = block_hash // set new top block id
  161. logger.Debugf("Chain extended using block %x new height %d", block_hash[:], chain.Height)
  162. // every 10 block print a line
  163. if chain.Height%20 == 0 {
  164. logger.Infof("Chain Height %d using block %x", chain.Height, block_hash[:])
  165. }
  166. } else { // a soft fork is in progress
  167. logger.Debugf("Soft Fork is in progress block due to %x", block_hash)
  168. chain.Chain_Add_And_Reorganise(bl)
  169. }
  170. // fmt.Printf("We should add the block to DB, reorganise if required\n")
  171. return false
  172. }
  173. /* the block we have is NOT at the top, it either belongs to an altchain or is an alternative */
  174. func (chain *Blockchain) Chain_Add_And_Reorganise(bl *Block) (result bool) {
  175. block_hash := bl.GetHash()
  176. // check whether the parent already has a child
  177. parent_has_child := chain.Does_Block_Have_Child(bl.Prev_Hash)
  178. // first lets add ourselves to the chain
  179. chain.Store_BL(bl)
  180. if !parent_has_child {
  181. chain.Store_Block_Child(bl.Prev_Hash, block_hash)
  182. logger.Infof("Adding alternative block %x to alt chain top\n", block_hash)
  183. } else {
  184. logger.Infof("Adding alternative block %x\n", block_hash)
  185. // load existing children, there can be more than 1 in extremely rare case or unknown attacks
  186. children_list := chain.Load_Block_Children(bl.Prev_Hash)
  187. children_list = append(children_list, block_hash) // add ourselves to children list
  188. // store children excluding main child of prev block
  189. chain.Store_Block_Children(bl.Prev_Hash, children_list, chain.Load_Block_Child(bl.Prev_Hash))
  190. }
  191. // now we must trigger the recursive reorganise process from the parent block,
  192. // the recursion should always end at the genesis block
  193. // adding a block can cause chain reorganisation 1 time in 99.99% cases
  194. // but we are prepared for the case, which might occur due to alt-alt-chains
  195. chain.reorganise(block_hash)
  196. return true
  197. }
  198. type chain_data struct {
  199. hash crypto.Hash
  200. cdifficulty uint64
  201. foundat uint64 // when block was found
  202. }
  203. // NOTE: below algorithm is the core and and is used to network consensus
  204. // the best chain found using the following algorithm
  205. // cryptonote protocol algo is below
  206. // compare cdiff, chain with higher diff wins, if diff is same, no reorg, this cause frequent splits
  207. // new algo is this
  208. // compare cdiff, chain with higher diff wins, if diff is same, go below
  209. // compare time stamp, block with lower timestamp wins (since it has probable spread more than other blocks)
  210. // if timestamps are same, block with lower block has (No PoW involved) wins
  211. // block hash cannot be same
  212. type bestChain []chain_data
  213. func (s bestChain) Len() int { return len(s) }
  214. func (s bestChain) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
  215. func (s bestChain) Less(i, j int) bool {
  216. if s[i].cdifficulty > s[j].cdifficulty {
  217. return true
  218. }
  219. if s[i].cdifficulty < s[j].cdifficulty {
  220. return false
  221. }
  222. // we are here of if difficulty are same
  223. if s[i].foundat < s[j].foundat { // check if timestamps are diff
  224. return true
  225. }
  226. if s[i].foundat > s[j].foundat { // check if timestamps are diff
  227. return false
  228. }
  229. if bytes.Compare(s[i].hash[:], s[j].hash[:]) < 0 {
  230. return true
  231. }
  232. return false
  233. }
  234. // this function will recursive reorganise the chain, till the genesis block if required
  235. // we are doing it this way as we can do away with too much book keeping
  236. // this is processor and IO intensive in normal cases
  237. func (chain *Blockchain) reorganise(block_hash crypto.Hash) {
  238. var children_data bestChain
  239. if block_hash == globals.Config.Genesis_Block_Hash {
  240. logger.Infof("Reorganisation completed successfully, we reached genesis block")
  241. return
  242. }
  243. // check if the block mentioned has more than 1 child
  244. block_hash, found := chain.find_parent_with_children(block_hash)
  245. if found {
  246. // reorganise chain at this block
  247. children := chain.Load_Block_Children(block_hash)
  248. if len(children) < 2 {
  249. panic(fmt.Sprintf("Children disappeared for block %x", block_hash))
  250. }
  251. main_chain := chain.Load_Block_Child(block_hash)
  252. _ = main_chain
  253. // choose the best chain and make it parent
  254. for i := range children {
  255. top_hash := chain.Get_Top_Block(children[i])
  256. top_cdiff := chain.Load_Block_Cumulative_Difficulty(top_hash)
  257. timestamp := chain.Load_Block_Timestamp(children[i])
  258. children_data = append(children_data, chain_data{hash: children[i], cdifficulty: top_cdiff, foundat: timestamp})
  259. }
  260. sort.Sort(children_data)
  261. logger.Infof("Choosing best chain\n")
  262. for i := range children {
  263. fmt.Printf("%d %+v\n", i, children_data[i])
  264. }
  265. best_chain := children_data[0].hash
  266. if main_chain == best_chain {
  267. logger.Infof("Main chain is already best, nothing to do")
  268. return
  269. } else {
  270. logger.Infof("Making alt chain -> main chain and vice-versa")
  271. // first lets fix up the connection
  272. chain.Store_Block_Child(block_hash, best_chain) // store main connection
  273. chain.Store_Block_Children(block_hash, children, best_chain) // store remaining child
  274. // setup new height
  275. new_height := chain.Load_Height_for_BL_ID(chain.Get_Top_Block(best_chain)) + 1
  276. // invalidate all transactionw contained within old main chain
  277. // validate all transactions in new main chain
  278. logger.Debugf("Invalidating all transactions with old main chain")
  279. logger.Debugf("Validating all transactions with old alt chain")
  280. logger.Infof("Reorganise old height %d, new height %d", chain.Get_Height(), new_height)
  281. chain.Top_ID = chain.Get_Top_Block(best_chain)
  282. chain.Height = new_height
  283. chain.Store_TOP_ID(chain.Top_ID) // make new block top block
  284. logger.Infof("Reorganise success")
  285. }
  286. // TODO if we need to support alt-alt chains, uncomment the code below
  287. //chain.reorganise(chain.Load_Block_Parent_ID(block_hash))
  288. }
  289. }
  290. /*
  291. func (chain *Blockchain)find_best_chain(list []crypto.Hash) best_child crypto.Hash {
  292. if len(list) < 2 {
  293. panic("Cannot find best child, when child_count = 1")
  294. }
  295. }
  296. */
  297. // find a block with 2 or more child,
  298. // returns false, if we reach genesis block
  299. func (chain *Blockchain) find_parent_with_children(block_hash crypto.Hash) (hash crypto.Hash, found bool) {
  300. // TODO we can also stop on the heighest checkpointed state, to save computing resources and time
  301. if block_hash == globals.Config.Genesis_Block_Hash {
  302. return hash, false // we do not have parent of genesis block
  303. }
  304. for {
  305. // load children
  306. children := chain.Load_Block_Children(block_hash)
  307. if len(children) >= 2 {
  308. return block_hash, true
  309. }
  310. block_hash = chain.Load_Block_Parent_ID(block_hash)
  311. if block_hash == globals.Config.Genesis_Block_Hash {
  312. return hash, false // we do not have parent of genesis block
  313. }
  314. }
  315. }
  316. // make sure the block is valid before we even attempt to add it
  317. func (chain *Blockchain) Is_Block_Valid(height uint64, bl *Block) bool {
  318. return true
  319. }
  320. /*
  321. // Parent's list is appended to add child
  322. func (chain *Blockchain) Add_Child( Parent_Hash, Child_Hash crypto.Hash ){
  323. fmt.Printf("caller %s\n", CallerName())
  324. // child list is only appended and never truncated
  325. // fetch old list
  326. children_list := chain.Load_Chain(Parent_Hash)
  327. if len(children_list) % 32 != 0 {
  328. log.Fatalf("Database corruption has occurred at this hash %x", Parent_Hash[:])
  329. }
  330. if len(children_list) == 0 {
  331. chain.Store_Chain(Parent_Hash, Child_Hash[:])
  332. log.Debugf("%x is a child of %x", Child_Hash, Parent_Hash)
  333. }else{ // we need to sort the children based on Pow
  334. panic("Chain need reorganisation, Sorting on PoW NOT implemented")
  335. }
  336. return
  337. }
  338. */
  339. /* add a transaction to chain,, we are currently not verifying the TX,
  340. its a BUG and disaster, implement it ASAP
  341. */
  342. func (chain *Blockchain) Add_TX(tx *Transaction) {
  343. chain.Store_TX(tx)
  344. }
  345. /* this will only give you access to transactions which have been mined
  346. */
  347. func (chain *Blockchain) Get_TX(hash crypto.Hash) (*Transaction, error) {
  348. tx, err := chain.Load_TX_FROM_ID(hash)
  349. return tx, err
  350. }
  351. // get difficulty at specific height but height must be <= than current block chain height
  352. func (chain *Blockchain) Get_Difficulty_At_Height(Height uint64) uint64 {
  353. if Height > chain.Get_Height() {
  354. logger.Warnf("Difficulty Requested for invalid Height Chain Height %d requested Height %d", chain.Get_Height(), Height)
  355. panic("Difficulty Requested for invalid Height")
  356. }
  357. // get block id at that height
  358. block_id, err := chain.Load_BL_ID_at_Height(Height)
  359. if err != nil {
  360. logger.Warnf("No Block at Height %d , chain height %d\n", Height, chain.Get_Height())
  361. panic("No Block at Height")
  362. }
  363. // we have a block id, now Lets get the difficulty
  364. return chain.Get_Difficulty_At_Block(block_id)
  365. }
  366. // get difficulty at specific block_id, only condition is block must exist and must be connected
  367. func (chain *Blockchain) Get_Difficulty_At_Block(block_id crypto.Hash) uint64 {
  368. var cumulative_difficulties []uint64
  369. var timestamps []uint64
  370. var zero_block crypto.Hash
  371. current_block_id := block_id
  372. // traverse chain from the block referenced, to max 30 blocks ot till genesis block is researched
  373. for i := 0; i < config.DIFFICULTY_BLOCKS_COUNT_V2; i++ {
  374. if current_block_id == globals.Config.Genesis_Block_Hash || current_block_id == zero_block {
  375. rlog.Tracef(2, "Reached genesis block for difficulty calculation %x", block_id[:])
  376. break // break we have reached genesis block
  377. }
  378. // read timestamp of block and cumulative difficulty at that block
  379. timestamp := chain.Load_Block_Timestamp(current_block_id)
  380. cdifficulty := chain.Load_Block_Cumulative_Difficulty(current_block_id)
  381. timestamps = append([]uint64{timestamp}, timestamps...) // prepend timestamp
  382. cumulative_difficulties = append([]uint64{cdifficulty}, cumulative_difficulties...) // prepend timestamp
  383. current_block_id = chain.Load_Block_Parent_ID(current_block_id)
  384. }
  385. return difficulty.Next_Difficulty(timestamps, cumulative_difficulties, config.BLOCK_TIME)
  386. }
  387. // this function return the current top block, if we start at specific block
  388. // this works for any blocks which were added
  389. func (chain *Blockchain) Get_Top_Block(block_id crypto.Hash) crypto.Hash {
  390. for {
  391. // check if the block has child, if not , we are the top
  392. if !chain.Does_Block_Have_Child(block_id) {
  393. return block_id
  394. }
  395. block_id = chain.Load_Block_Child(block_id) // continue searching the new top
  396. }
  397. panic("We can never reach this point")
  398. return block_id // we will never reach here
  399. }
  400. // verifies whether we are lagging
  401. // return true if we need resync
  402. // returns false if we are good
  403. func (chain *Blockchain) IsLagging(peer_cdifficulty, peer_height uint64, peer_top_id crypto.Hash) bool {
  404. top_id := chain.Get_Top_ID()
  405. cdifficulty := chain.Load_Block_Cumulative_Difficulty(top_id)
  406. height := chain.Load_Height_for_BL_ID(top_id) + 1
  407. rlog.Tracef(3, "P_cdiff %d cdiff %d , P_BH %d BH %d, p_top %x top %x",
  408. peer_cdifficulty, cdifficulty,
  409. peer_height, height,
  410. peer_top_id, top_id)
  411. if peer_cdifficulty > cdifficulty{
  412. return true // peer's cumulative difficulty is more than ours , active resync
  413. }
  414. if peer_cdifficulty == cdifficulty && peer_top_id != top_id {
  415. return true // cumulative difficulty is same but tops are different , active resync
  416. }
  417. return false
  418. }
  419. // This function will expand a transaction with all the missing info being reconstitued from the blockchain
  420. // this also increases security since data is coming from the chain or being calculated
  421. // basically this places data for ring signature verification
  422. // REMEMBER to expand key images from the blockchain
  423. func (chain *Blockchain) Expand_Transaction_v2 (tx *Transaction){
  424. if tx.Version != 2 {
  425. panic("TX not version 2")
  426. }
  427. //if rctsignature is null
  428. // fill up the message first
  429. tx.RctSignature.Message = ringct.Key(tx.GetPrefixHash())
  430. // fill up the key images
  431. for i := 0; i < len(tx.Vin);i++{
  432. tx.RctSignature.MlsagSigs[i].II[0]= ringct.Key(tx.Vin[i].(Txin_to_key).K_image)
  433. }
  434. // now we need to fill up the mixring ctkey
  435. }
  436. // this function count all the vouts of the block,
  437. // this function exists here because only the chain knws the tx
  438. //
  439. func (chain *Blockchain) Block_Count_Vout(block_hash crypto.Hash) (count uint64){
  440. count = 1 // miner tx is always present
  441. bl, err := chain.Load_BL_FROM_ID(block_hash)
  442. if err != nil {
  443. panic(fmt.Errorf("Cannot load block for %x err %s", block_hash, err))
  444. }
  445. for i := 0 ; i < len(bl.Tx_hashes);i++{ // load all tx one by one
  446. tx, err := chain.Load_TX_FROM_ID(bl.Tx_hashes[i])
  447. if err != nil{
  448. panic(fmt.Errorf("Cannot load tx for %x err %s", bl.Tx_hashes[i], err))
  449. }
  450. // tx has been loaded, now lets get the vout
  451. vout_count := uint64(len(tx.Vout))
  452. count += vout_count
  453. }
  454. return count
  455. }