github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/blockchain/store.go (about)

     1  // Copyright 2017-2018 DERO Project. All rights reserved.
     2  // Use of this source code in any form is governed by RESEARCH license.
     3  // license can be found in the LICENSE file.
     4  // GPG: 0F39 E425 8C65 3947 702A  8234 08B2 0360 A03A 9DE8
     5  //
     6  //
     7  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
     8  // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     9  // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    10  // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    11  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    12  // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    13  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
    14  // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
    15  // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    16  
    17  package blockchain
    18  
    19  import "fmt"
    20  import "sync"
    21  import "math/big"
    22  
    23  //import "runtime/debug"
    24  import "encoding/binary"
    25  
    26  //import log "github.com/sirupsen/logrus"
    27  import "github.com/golang/groupcache/lru"
    28  
    29  import "github.com/deroproject/derosuite/storage"
    30  import "github.com/deroproject/derosuite/block"
    31  import "github.com/deroproject/derosuite/crypto"
    32  
    33  //import "github.com/deroproject/derosuite/globals"
    34  import "github.com/deroproject/derosuite/transaction"
    35  
    36  /* this file implements the only interface which translates comands  to/from blockchain to storage layer *
    37   *
    38   *
    39   */
    40  
    41  //var TOP_ID = []byte("TOP_ID")  // stores current TOP, only stores single value
    42  
    43  //var BLOCK_ID = []byte("BLOCKS") // stores blocks
    44  //var CHAIN = []byte("CHAIN")    // this stores the actual chain, parents keeps child list, starts from genesis block
    45  
    46  var BLOCKCHAIN_UNIVERSE = []byte("U") //[]byte("BLOCKCHAIN_UNIVERSE") // all block chain data is store in this BLOCKCHAIN_UNIVERSE
    47  
    48  // there are only 8 galaxies
    49  var GALAXY_BLOCK = []byte("GB")
    50  var GALAXY_TRANSACTION = []byte("GTX")           // []byte("TRANSACTION")
    51  var GALAXY_TRANSACTION_VALIDITY = []byte("GTXV") //[]byte("TRANSACTIONVALIDITY")
    52  var GALAXY_KEYIMAGE = []byte("GKI")              //[]byte("KEYIMAGE")
    53  
    54  var GALAXY_TOPOLOGICAL_ORDER = []byte("GT")  // []byte("TOPOLOGICAL")       // stores  block to topo index mapping
    55  var GALAXY_TOPOLOGICAL_INDEX = []byte("GTI") //[]byte("TOPOLOGICAL_INDEX") // stores topological index  to block mapping
    56  
    57  //2 galaxies store inverse mapping
    58  var GALAXY_HEIGHT = []byte("GH")        //[]byte("HEIGHT")             // height to block id mapping
    59  var GALAXY_OUTPUT_INDEX = []byte("GOI") //[]byte("OUTPUT_INDEX") // output index to wallet data for blockchain verification and wallets
    60  
    61  // these store unstructured data
    62  var GALAXY_KEYVALUE = []byte("GKV") //[]byte("KEYVALUE") // used to store simple data
    63  
    64  // the various attributes stored in keyvalue
    65  var TOP_HEIGHT = []byte("TOP_HEIGHT")   // stores current TOP HEIGHT, only stores single value
    66  var TOPO_HEIGHT = []byte("TOPO_HEIGHT") // stores current TOPO HEIGHT, only stores single value
    67  var TIPS = []byte("TIPS")               // this stores tips
    68  
    69  // the unique TXID or block ID becomes the solar system , which is common and saves lot of space
    70  
    71  // individual attributes becomes the planets
    72  // individual attributes should be max  1 or 2 chars long, as they will be repeated millions of times and storing a static string millions of times shows foolishness
    73  // a block table has the following columns/attributes
    74  // CREATE TABLE IF NOT EXISTS BLOCKS (ID CHAR(64) PRIMARY KEY, SERIALIZED BLOB, height BIGINT  default -1, INDEX heighti (height), past TEXT default "", future TEXT default "", SIZE BIGINT default -1, DIFFICULTY DECIMAL(65,0) default 0, CDIFFICULTY DECIMAL(65,0) default 0, TIMESTAMP BIGINT default 1, OUTPUT_INDEX_START BIGINT default 0, OUTPUT_INDEX_END BIGINT default 0, CCOINS DECIMAL(32,0) default 0, BASEREWARD DECIMAL(32,0) default 0, TXFEES DECIMAL(32,0) default 0, TX_COUNT int default 0);
    75  
    76  // A TOPO ordering has the following
    77  //CREATE TABLE IF NOT EXISTS TOPO (ID CHAR(64) PRIMARY KEY,topoheight BIGINT  default -1, INDEX topoheighti (topoheight));
    78  
    79  // KEYVALUE table has the followiing
    80  //CREATE TABLE IF NOT EXISTS KEYVALUE (ID VARCHAR(1024),value BLOB ));
    81  
    82  var PLANET_BLOB = []byte("BLOB")     //it shows serialised block
    83  var PLANET_HEIGHT = []byte("HEIGHT") // contains height
    84  var PLANET_PARENT = []byte("PARENT") // parent of block
    85  var PLANET_PAST = []byte("PAST")     // past of block
    86  var PLANET_FUTURE = []byte("FUTURE") // future of block only 1 level
    87  
    88  //var PLANET_HEIGHT_BUCKET = []byte("H")     // contains all blocks of same height
    89  //var PLANET_SETTLE_STATUS = []byte("S")     // contains whether the block is settled
    90  
    91  var PLANET_SIZE = []byte("SIZE")                      // sum of block + all txs
    92  var PLANET_ALREADY_GENERATED_COINS = []byte("CCOINS") // all coins generated till this block
    93  var PLANET_OUTPUT_INDEX = []byte("OINDEX")            // tx outputs indexing starts from here for this block
    94  var PLANET_OUTPUT_INDEX_END = []byte("OINDEXEND")     // tx outputs indexing ends here ( this is excluded )
    95  var PLANET_CUMULATIVE_DIFFICULTY = []byte("CDIFF")    //[]byte("CDIFFICULTY") // Cumulative difficulty
    96  var PLANET_DIFFICULTY = []byte("DIFF")                //[]byte("DIFFICULTY")             // difficulty
    97  var PLANET_BASEREWARD = []byte("BREWARD")             // base reward of a block  ( new coins generated)
    98  var PLANET_MINERTX_REWARD = []byte("REWARD")          //reward for minertx is stored here ( base reward + collected fees after client protocol run)
    99  
   100  var PLANET_TIMESTAMP = []byte("TS") // []byte("TIMESTAMP")
   101  
   102  // the TX has the following attributes
   103  var PLANET_TX_BLOB = []byte("BLOB")          // contains serialised  TX , this attribute is also found in BLOCK where
   104  var PLANET_TX_MINED_IN_BLOCK = []byte("MBL") //[]byte("MINERBLOCK") // which blocks mined this tx, stores topo height of mined block
   105  var PLANET_TX_MINED = []byte("MIN")          // all blocks where tx is mined in in
   106  var PLANET_TX_SIZE = []byte("SIZE")
   107  
   108  // the universe concept is there, as we bring in smart contracts, we will give each of them a universe to play within
   109  // while communicating with external universe
   110  
   111  /*
   112  func (chain *Blockchain) Store_Main_Chain(parent_id  crypto.Hash, child_id crypto.Hash){
   113     err := chain.store.StoreObject(BLOCKCHAIN_UNIVERSE,GALAXY_BLOCK,parent_id[:],PLANET_CHILD, child_id[:] )
   114       _ = err
   115   }
   116  
   117  func (chain *Blockchain) Load_Main_Chain(parent_id  crypto.Hash) (child_id crypto.Hash ){
   118  	var err error
   119      // store OO to TXID automatically
   120       object_data,err = chain.store.LoadObject(BLOCKCHAIN_UNIVERSE,GALAXY_BLOCK,parent_id[:],PLANET_CHILD )
   121  
   122      if err != nil {
   123      	return child_id,err
   124      }
   125  
   126      if len(object_data) == 0 {
   127      	return child_id, fmt.Errorf("No Block at such Height %d", Height)
   128      }
   129  
   130      if len(object_data) != 32 {
   131      	panic("Database corruption, invalid block hash ")
   132      }
   133  
   134      copy(child_id[:],object_data[:32])
   135  
   136  _ = err
   137  
   138    return child_id
   139  
   140  }
   141  
   142  */
   143  
   144  /*
   145  // check whether the block has a child
   146  func (chain *Blockchain) Does_Block_Have_Child(block_id crypto.Hash) bool {
   147  	var err error
   148  	object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, block_id[:], PLANET_CHILD)
   149  
   150  	if err != nil || len(object_data) == 0 {
   151  		return false
   152  	}
   153  	if len(object_data) != 32 {
   154  		panic("Database corruption, invalid block hash ")
   155  	}
   156  	return true
   157  }
   158  
   159  // load the main child
   160  func (chain *Blockchain) Load_Block_Child(parent_id crypto.Hash) (child_id crypto.Hash) {
   161  	if !chain.Does_Block_Have_Child(parent_id) {
   162  		panic("Block does not have a child")
   163  	}
   164  	object_data, _ := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, parent_id[:], PLANET_CHILD)
   165  
   166  	copy(child_id[:], object_data)
   167  	return
   168  }
   169  
   170  */
   171  
   172  // stores a blocks topological order
   173  func (chain *Blockchain) Store_Block_Topological_order(dbtx storage.DBTX, blid crypto.Hash, index_pos int64) {
   174  	if dbtx == nil {
   175  		panic("TX cannot be nil")
   176  	}
   177  
   178  	// logger.Warnf("Storing topo order %s  %d", blid,index_pos)
   179  
   180  	dbtx.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TOPOLOGICAL_ORDER, GALAXY_TOPOLOGICAL_ORDER, blid[:], uint64(index_pos))
   181  	dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_TOPOLOGICAL_INDEX, GALAXY_TOPOLOGICAL_INDEX, itob(uint64(index_pos)), blid[:])
   182  }
   183  
   184  // since topological order might mutate, instead of doing cleanup, we double check the pointers
   185  func (chain *Blockchain) Is_Block_Topological_order(dbtx storage.DBTX, blid crypto.Hash) bool {
   186  	var err error
   187  	if dbtx == nil {
   188  		dbtx, err = chain.store.BeginTX(false)
   189  		if err != nil {
   190  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   191  			return false
   192  		}
   193  
   194  		defer dbtx.Rollback()
   195  
   196  	}
   197  
   198  	index_pos, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TOPOLOGICAL_ORDER, GALAXY_TOPOLOGICAL_ORDER, blid[:])
   199  	if err != nil || index_pos >= 0x7fffffffffffffff {
   200  		return false
   201  	}
   202  	blid_at_pos, err := chain.Load_Block_Topological_order_at_index(dbtx, int64(index_pos))
   203  
   204  	if err != nil {
   205  		return false
   206  	}
   207  
   208  	if blid == blid_at_pos {
   209  		return true
   210  	}
   211  	return false
   212  }
   213  
   214  func (chain *Blockchain) Load_Block_Topological_order(dbtx storage.DBTX, blid crypto.Hash) int64 {
   215  	/* if !chain.Is_Block_Topological_order(blid) {  // removed as optimisation
   216  	       return 0xffffffffffffffff
   217  	   }
   218  	*/
   219  	// give highest possible topo order for a block, if it does NOT exist
   220  
   221  	var err error
   222  	if dbtx == nil {
   223  		dbtx, err = chain.store.BeginTX(false)
   224  		if err != nil {
   225  			logger.Warnf(" Error opening writable TX, err %s", err)
   226  			return 0x7fffffffffffffff
   227  		}
   228  
   229  		defer dbtx.Rollback()
   230  
   231  	}
   232  
   233  	index_pos, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TOPOLOGICAL_ORDER, GALAXY_TOPOLOGICAL_ORDER, blid[:])
   234  	if err != nil {
   235  		logger.Warnf("%s DOES  NOT HAVE base order stored", blid)
   236  		return 0x7fffffffffffffff
   237  	}
   238  	return int64(index_pos)
   239  }
   240  
   241  func (chain *Blockchain) Load_Block_Topological_order_at_index(dbtx storage.DBTX, index_pos int64) (hash crypto.Hash, err error) {
   242  
   243  	if dbtx == nil {
   244  		dbtx, err = chain.store.BeginTX(false)
   245  		if err != nil {
   246  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   247  			return
   248  		}
   249  
   250  		defer dbtx.Rollback()
   251  
   252  	}
   253  
   254  	object_data, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_TOPOLOGICAL_INDEX, GALAXY_TOPOLOGICAL_INDEX, itob(uint64(index_pos)))
   255  
   256  	if err != nil {
   257  		return hash, err
   258  	}
   259  
   260  	if len(object_data) == 0 {
   261  		return hash, fmt.Errorf("No Block at such topo index %d", index_pos)
   262  	}
   263  
   264  	if len(object_data) != 32 {
   265  		panic("Database corruption, invalid block hash ")
   266  	}
   267  	copy(hash[:], object_data[:32])
   268  	return hash, nil
   269  }
   270  
   271  /*
   272  
   273  // changes  or set child block of a parent
   274  // there can be only 1 child, rest all are alternatives and stored as
   275  func (chain *Blockchain) Store_Block_Child(parent_id crypto.Hash, child_id crypto.Hash) {
   276  	err := chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, parent_id[:], PLANET_CHILD, child_id[:])
   277  
   278  	// load block children
   279  	_ = err
   280  }
   281  
   282  // while store children
   283  func (chain *Blockchain) Store_Block_Children(parent_id crypto.Hash, children []crypto.Hash, exclude_child crypto.Hash) {
   284  	var children_bytes []byte
   285  	for i := range children {
   286  		if children[i] != exclude_child { // exclude main child
   287  			children_bytes = append(children_bytes, children[i][:]...)
   288  		}
   289  	}
   290  	err := chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, parent_id[:], PLANET_CHILDREN, children_bytes)
   291  	_ = err
   292  }
   293  
   294  func (chain *Blockchain) Load_Block_Children(parent_id crypto.Hash) (children []crypto.Hash) {
   295  	var child_hash crypto.Hash
   296  	if !chain.Does_Block_Have_Child(parent_id) { // block doesnot have a child, so it cannot have children
   297  		return
   298  	}
   299  	// we are here means parent does have child
   300  	children = append(children, chain.Load_Block_Child(parent_id))
   301  
   302  	// check for children
   303  	children_bytes, _ := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, parent_id[:], PLANET_CHILDREN)
   304  
   305  	if len(children_bytes)%32 != 0 {
   306  		panic(fmt.Sprintf("parent does not have child hash in multiples of 32, block_hash %s", parent_id))
   307  	}
   308  	for i := 0; i < len(children_bytes); i = i + 32 {
   309  		copy(child_hash[:], children_bytes[i:i+32])
   310  		children = append(children, child_hash)
   311  	}
   312  	return children
   313  }
   314  */
   315  
   316  // store a tx
   317  // this only occurs when a tx has been mined or a a reorganisation is in progress
   318  // stores a height to show at what height it has been mined
   319  func (chain *Blockchain) Store_TX(dbtx storage.DBTX, tx *transaction.Transaction) {
   320  
   321  	if dbtx == nil {
   322  		panic(fmt.Sprintf("Could NOT add TX to chain. Error opening writable TX, err "))
   323  
   324  	}
   325  
   326  	hash := tx.GetHash()
   327  	serialized := tx.Serialize()
   328  	err := dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_BLOB, serialized)
   329  	// store size of tx
   330  	dbtx.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_SIZE, uint64(len(serialized)))
   331  
   332  	//dbtx.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_MINED_IN_BLOCK, uint64(TopoHeight))
   333  
   334  	_ = err
   335  }
   336  
   337  func (chain *Blockchain) Store_TX_Height(dbtx storage.DBTX, txhash crypto.Hash, TopoHeight int64) {
   338  	if dbtx == nil {
   339  		panic(fmt.Sprintf("Could NOT add TX to chain. Error opening writable TX"))
   340  
   341  	}
   342  	dbtx.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, txhash[:], PLANET_TX_MINED_IN_BLOCK, uint64(TopoHeight))
   343  }
   344  
   345  /*
   346  
   347  func (chain *Blockchain) Store_TX_Miner(txhash crypto.Hash, block_id crypto.Hash) {
   348  	// store block id  which mined this tx
   349  	err := chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, txhash[:], PLANET_TX_MINED_IN_BLOCK, block_id[:])
   350  	_ = err
   351  }
   352  */
   353  
   354  func (chain *Blockchain) Load_TX_Size(dbtx storage.DBTX, txhash crypto.Hash) uint64 {
   355  
   356  	var err error
   357  	if dbtx == nil {
   358  		dbtx, err = chain.store.BeginTX(false)
   359  		if err != nil {
   360  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   361  			return 0
   362  		}
   363  
   364  		defer dbtx.Rollback()
   365  
   366  	}
   367  
   368  	// store block id  which mined this tx
   369  	size, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, txhash[:], PLANET_TX_SIZE)
   370  
   371  	if err != nil {
   372  		logger.Warnf("Size not stored for tx %s", txhash)
   373  	}
   374  	return size
   375  }
   376  
   377  // load height at which a specific tx was mined
   378  func (chain *Blockchain) Load_TX_Height(dbtx storage.DBTX, txhash crypto.Hash) int64 {
   379  	var err error
   380  	if dbtx == nil {
   381  		dbtx, err = chain.store.BeginTX(false)
   382  		if err != nil {
   383  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   384  			return -1
   385  		}
   386  
   387  		defer dbtx.Rollback()
   388  
   389  	}
   390  
   391  	height, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, txhash[:], PLANET_TX_MINED_IN_BLOCK)
   392  	if err != nil {
   393  		logger.Warnf("Error while querying height for tx %s", txhash)
   394  	}
   395  	return int64(height)
   396  }
   397  
   398  // BUG we should be able to delete any arbitrary key
   399  // since a tx mined by one block, can be back in pool after chain reorganises
   400  
   401  // TODO the miner tx should be extracted ands stored from somewhere else
   402  // NOTE: before storing a block, its transactions must be stored
   403  func (chain *Blockchain) Store_BL(dbtx storage.DBTX, bl *block.Block) {
   404  
   405  	if dbtx == nil {
   406  		panic(fmt.Sprintf("Could NOT store block to DB.  nil dbtx"))
   407  	}
   408  	// store block height BHID automatically
   409  	hash := bl.GetHash()
   410  
   411  	// we should deserialize the block here
   412  	serialized_bytes := bl.Serialize() // we are storing the miner transactions within
   413  	err := dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_BLOB, serialized_bytes)
   414  
   415  	height := chain.Calculate_Height_At_Tips(dbtx, bl.Tips)
   416  
   417  	// store new height
   418  	dbtx.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_HEIGHT, uint64(height))
   419  
   420  	// this will be ignored by SQL backend as it can be recreated later on
   421  	//dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, append(itob(uint64(height)),PLANET_HEIGHT_BUCKET...) , hash[:], []byte(""))
   422  
   423  	blocks_at_height := chain.Get_Blocks_At_Height(dbtx, height)
   424  	blocks_at_height = append(blocks_at_height, hash)
   425  
   426  	blocks_at_height_bytes := make([]byte, 0, len(blocks_at_height)*32)
   427  	for j := range blocks_at_height {
   428  		blocks_at_height_bytes = append(blocks_at_height_bytes, blocks_at_height[j][:]...)
   429  	}
   430  
   431  	dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_HEIGHT, PLANET_HEIGHT, itob(uint64(height)), blocks_at_height_bytes)
   432  
   433  	// store timestamp separatly is NOT necessary
   434  	dbtx.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_TIMESTAMP, bl.Timestamp)
   435  
   436  	// create empty past and future buckets
   437  	// past will be empty for genesis block
   438  	// future may be empty in case of discarded blocks
   439  	//dbtx.CreateBucket(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, append(hash[:],PLANET_PAST...))
   440  	//dbtx.CreateBucket(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, append(hash[:],PLANET_FUTURE...))
   441  
   442  	// store Past tips into a separate bucket
   443  	// information is stored within the buckets keys itself
   444  	past_bytes := make([]byte, 0, len(bl.Tips)*32)
   445  	for i := range bl.Tips {
   446  		past_bytes = append(past_bytes, bl.Tips[i][:]...)
   447  	}
   448  	dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_PAST, past_bytes)
   449  
   450  	// store future mixed for easier processing later on
   451  	for i := range bl.Tips {
   452  		future := chain.Get_Block_Future(dbtx, bl.Tips[i])
   453  		future = append(future, hash)
   454  
   455  		future_bytes := make([]byte, 0, len(future)*32)
   456  		for j := range future {
   457  			future_bytes = append(future_bytes, future[j][:]...)
   458  		}
   459  
   460  		dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, bl.Tips[i][:], PLANET_FUTURE, future_bytes)
   461  	}
   462  
   463  	// calculate cumulative difficulty at last block
   464  
   465  	if len(bl.Tips) == 0 { // genesis block has no parent
   466  		//cumulative_difficulty = 1
   467  		//difficulty_of_current_block = 1
   468  
   469  		difficulty_of_current_block := new(big.Int).SetUint64(1) // this is never used, as genesis block is a sync block, only its cumulative difficulty is used
   470  		cumulative_difficulty := new(big.Int).SetUint64(1)       // genesis block cumulative difficulty is 1
   471  
   472  		dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY, cumulative_difficulty.Bytes())
   473  
   474  		dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_DIFFICULTY, difficulty_of_current_block.Bytes())
   475  
   476  		// chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_DIFFICULTY, difficulty_of_current_block)
   477  
   478  	} else {
   479  
   480  		difficulty_of_current_block := chain.Get_Difficulty_At_Tips(dbtx, bl.Tips)
   481  		dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_DIFFICULTY, difficulty_of_current_block.Bytes())
   482  
   483  		// NOTE: difficulty must be stored before cumulative difficulty calculation, since it is used while calculating Cdiff
   484  
   485  		base, base_height := chain.find_common_base(dbtx, bl.Tips)
   486  		work_map, cumulative_difficulty := chain.FindTipWorkScore(dbtx, hash, base, base_height)
   487  
   488  		_ = work_map
   489  		/*logger.Infof("workmap base ")
   490  		  for k,v := range work_map{
   491  		   logger.Infof("%s %d",k,v)
   492  		  }*/
   493  
   494  		dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY, cumulative_difficulty.Bytes())
   495  
   496  		// chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY, cumulative_difficulty)
   497  
   498  		/*gbl:=Generate_Genesis_Block()
   499  
   500  		     // TODO BUG BUG BUG  cumulative_difficulty neeeds to calculated against a previous sync point , otherise
   501  		     // we are DOSing  ourselves
   502  		   work_map_gbl, cumulative_difficulty_gbl  := chain.FindTipWorkScore(hash, gbl.GetHash(),0)
   503  
   504  		   if cumulative_difficulty != cumulative_difficulty_gbl {
   505  
   506  		    logger.Warnf("DIFFICULTY mismatch for %s hash   from base %s  %d from genesis %d", base,cumulative_difficulty,cumulative_difficulty_gbl)
   507  
   508  		    logger.Infof("workmap base ")
   509  		    for k,v := range work_map{
   510  		     logger.Infof("%s %d",k,v)
   511  		    }
   512  
   513  		    logger.Infof("workmap genesis base ")
   514  		    for k,v := range work_map_gbl{
   515  		     logger.Infof("%s %d",k,v)
   516  		    }
   517  
   518  		}*/
   519  
   520  	}
   521  
   522  	// the cumulative difficulty  includes  self difficulty
   523  	// total_difficulty = cumulative_difficulty //+ difficulty_of_current_block
   524  
   525  	//chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY, total_difficulty)
   526  	//chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY, hash[:])
   527  
   528  	// cdifficulty_bytes, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY)
   529  
   530  	// logger.Infof("cumulative difficulty of %s is %d", hash, total_difficulty)
   531  
   532  	/*
   533  			// total size of block = size of miner_tx + size of all transactions in block ( excludind miner tx)
   534  
   535  			size_of_block := uint64(0) //len(bl.Miner_tx.Serialize()))
   536  			for i := 0; i < len(bl.Tx_hashes); i++ {
   537  				size_of_tx := chain.Load_TX_Size(bl.Tx_hashes[i])
   538  				size_of_block += size_of_tx
   539  			}
   540  			chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_SIZE, size_of_block)
   541  
   542  			// calculated position of vouts in global indexs
   543  			index_pos := uint64(0)
   544  			if hash != globals.Config.Genesis_Block_Hash {
   545  				// load index pos from last block + add count of vouts from last block
   546  				index_pos = chain.Get_Block_Output_Index(bl.Prev_Hash)
   547  				vout_count_prev_block := chain.Block_Count_Vout(bl.Prev_Hash)
   548  				index_pos += vout_count_prev_block
   549  			}
   550  			chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_OUTPUT_INDEX, index_pos)
   551  			//logger.Debugf("height %d   output index %d",height, index_pos)
   552  
   553  			total_fees := uint64(0)
   554  			for i := 0; i < len(bl.Tx_hashes); i++ {
   555  				tx, _ := chain.Load_TX_FROM_ID(bl.Tx_hashes[i])
   556  				total_fees += tx.RctSignature.Get_TX_Fee()
   557  			}
   558  
   559  			total_reward :=  uint64(0) //bl.Miner_tx.Vout[0].Amount
   560  			base_reward := total_reward - total_fees
   561  			chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_BASEREWARD, base_reward)
   562  
   563  			already_generated_coins := uint64(0)
   564  			if hash != globals.Config.Genesis_Block_Hash { // genesis block has no parent
   565  				already_generated_coins = chain.Load_Already_Generated_Coins_for_BL_ID(bl.Prev_Hash)
   566  			} else {
   567  				base_reward = 1000000000000 // trigger the bug to fix coin calculation, see comments in emission
   568  			}
   569  			already_generated_coins += base_reward
   570  			chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_ALREADY_GENERATED_COINS, already_generated_coins)
   571  
   572  			// also extract and store the miner tx separetly, fr direct querying purpose
   573  		        //TODO miner TX should be created using deterministic random number and saved
   574  			//chain.Store_TX(&bl.Miner_tx, height)
   575  
   576  	*/
   577  	_ = err
   578  }
   579  
   580  var past_cache = lru.New(10240)
   581  var past_cache_lock sync.Mutex
   582  
   583  // all the immediate past of a block
   584  func (chain *Blockchain) Get_Block_Past(dbtx storage.DBTX, hash crypto.Hash) (blocks []crypto.Hash) {
   585  	past_cache_lock.Lock()
   586  	defer past_cache_lock.Unlock()
   587  
   588  	if keysi, ok := past_cache.Get(hash); ok {
   589  		keys := keysi.([]crypto.Hash)
   590  		blocks = make([]crypto.Hash, len(keys))
   591  		for i := range keys {
   592  			copy(blocks[i][:], keys[i][:])
   593  		}
   594  		return
   595  	}
   596  
   597  	var err error
   598  	if dbtx == nil {
   599  		dbtx, err = chain.store.BeginTX(false)
   600  		if err != nil {
   601  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   602  			return
   603  		}
   604  
   605  		defer dbtx.Rollback()
   606  
   607  	}
   608  
   609  	// serve from store
   610  	past_bytes, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_PAST)
   611  	if err != nil {
   612  		return
   613  	}
   614  	blocks = make([]crypto.Hash, len(past_bytes)/32, len(past_bytes)/32)
   615  
   616  	for i := 0; i < len(past_bytes)/32; i++ {
   617  		//logger.Infof("len %d , i %d", len(past_bytes), i)
   618  		copy(blocks[i][:], past_bytes[i*32:(i*32)+32])
   619  	}
   620  
   621  	cache_copy := make([]crypto.Hash, len(blocks), len(blocks))
   622  	for i := range blocks {
   623  		cache_copy[i] = blocks[i]
   624  	}
   625  
   626  	//set in cache
   627  	past_cache.Add(hash, cache_copy)
   628  
   629  	return
   630  }
   631  
   632  // a block withput a future is called tip
   633  func (chain *Blockchain) Get_Block_Future(dbtx storage.DBTX, hash crypto.Hash) (blocks []crypto.Hash) {
   634  
   635  	var err error
   636  	if dbtx == nil {
   637  		dbtx, err = chain.store.BeginTX(false)
   638  		if err != nil {
   639  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   640  			return
   641  		}
   642  
   643  		defer dbtx.Rollback()
   644  
   645  	}
   646  
   647  	// deserialize future
   648  	future_bytes, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_FUTURE)
   649  	if err != nil {
   650  		return
   651  	}
   652  	blocks = make([]crypto.Hash, len(future_bytes)/32, len(future_bytes)/32)
   653  
   654  	for i := 0; i < len(future_bytes)/32; i++ {
   655  		copy(blocks[i][:], future_bytes[i*32:(i*32)+32])
   656  	}
   657  
   658  	return
   659  }
   660  
   661  func (chain *Blockchain) Load_TX_FROM_ID(dbtx storage.DBTX, hash [32]byte) (*transaction.Transaction, error) {
   662  	var tx transaction.Transaction
   663  
   664  	var err error
   665  	if dbtx == nil {
   666  		dbtx, err = chain.store.BeginTX(false)
   667  		if err != nil {
   668  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   669  			return nil, err
   670  		}
   671  
   672  		defer dbtx.Rollback()
   673  
   674  	}
   675  
   676  	tx_data, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_BLOB)
   677  
   678  	if err != nil {
   679  		return nil, err
   680  	}
   681  
   682  	// we should deserialize the block here
   683  	err = tx.DeserializeHeader(tx_data)
   684  
   685  	if err != nil {
   686  		logger.Printf("fError deserialiing tx, block id %s len(data) %d data %x", hash[:], len(tx_data), tx_data)
   687  		return nil, err
   688  	}
   689  	return &tx, nil
   690  
   691  }
   692  
   693  func (chain *Blockchain) Load_BL_FROM_ID(dbtx storage.DBTX, hash [32]byte) (*block.Block, error) {
   694  	var bl block.Block
   695  	var err error
   696  	if dbtx == nil {
   697  		dbtx, err = chain.store.BeginTX(false)
   698  		if err != nil {
   699  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   700  			return nil, err
   701  		}
   702  
   703  		defer dbtx.Rollback()
   704  
   705  	}
   706  
   707  	block_data, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_BLOB)
   708  
   709  	if err != nil {
   710  		return nil, err
   711  	}
   712  
   713  	if len(block_data) == 0 {
   714  		return nil, fmt.Errorf("Block not found in DB")
   715  	}
   716  
   717  	// we should deserialize the block here
   718  	err = bl.Deserialize(block_data)
   719  
   720  	if err != nil {
   721  		logger.Warnf("fError deserialiing block, block id %s len(data) %d data %x", hash[:], len(block_data), block_data)
   722  		return nil, err
   723  	}
   724  	return &bl, nil
   725  }
   726  
   727  // this will give you a block id at a specific height
   728  /*
   729  func (chain *Blockchain) Load_BL_ID_at_Height(Height int64) (hash crypto.Hash, err error) {
   730  	object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_HEIGHT, PLANET_HEIGHT, itob(uint64(Height)))
   731  
   732  	if err != nil {
   733  		return hash, err
   734  	}
   735  
   736  	if len(object_data) == 0 {
   737  		return hash, fmt.Errorf("No Block at such Height %d", Height)
   738  	}
   739  
   740  	if len(object_data) != 32 {
   741  		panic("Database corruption, invalid block hash ")
   742  	}
   743  	copy(hash[:], object_data[:32])
   744  	return hash, nil
   745  
   746  }*/
   747  
   748  /*
   749  // this will give you a block id at a specific height
   750  func (chain *Blockchain) Store_BL_ID_at_Height(Height uint64, hash crypto.Hash) {
   751  	// store height to block id mapping
   752  	chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_HEIGHT, PLANET_HEIGHT, itob(Height), hash[:])
   753  
   754  }
   755  */
   756  
   757  func (chain *Blockchain) Load_Height_for_BL_ID(dbtx storage.DBTX, hash crypto.Hash) (Height int64) {
   758  
   759  	var err error
   760  	if dbtx == nil {
   761  		dbtx, err = chain.store.BeginTX(false)
   762  		if err != nil {
   763  			logger.Warnf("Could NOT open readonly TX, err %s", err)
   764  			return -1
   765  		}
   766  
   767  		defer dbtx.Rollback()
   768  
   769  	}
   770  
   771  	if hash == ZERO_HASH { // handle special case for  genesis
   772  		return 0
   773  	}
   774  
   775  	object_data, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_HEIGHT)
   776  
   777  	if err != nil {
   778  		logger.Warnf("Error while querying height for block %s", hash)
   779  		return
   780  	}
   781  
   782  	if len(object_data) == 0 {
   783  		//return hash, fmt.Errorf("No Height for block %x", hash[:])
   784  		return
   785  	}
   786  
   787  	if len(object_data) != 8 {
   788  		panic("Database corruption, invalid block hash ")
   789  	}
   790  
   791  	Height = int64(binary.BigEndian.Uint64(object_data))
   792  
   793  	return int64(Height)
   794  
   795  }
   796  
   797  func (chain *Blockchain) Load_Block_Timestamp(dbtx storage.DBTX, hash crypto.Hash) int64 {
   798  
   799  	var err error
   800  	if dbtx == nil {
   801  		dbtx, err = chain.store.BeginTX(false)
   802  		if err != nil {
   803  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   804  			return -1
   805  		}
   806  
   807  		defer dbtx.Rollback()
   808  
   809  	}
   810  
   811  	timestamp, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_TIMESTAMP)
   812  	if err != nil {
   813  		logger.Warnf("Error while querying timestamp for block %s", hash)
   814  		logger.Panicf("Error while querying timestamp for block %s", hash)
   815  
   816  	}
   817  
   818  	return int64(timestamp)
   819  }
   820  
   821  func (chain *Blockchain) Load_Block_Cumulative_Difficulty(dbtx storage.DBTX, hash crypto.Hash) *big.Int {
   822  
   823  	var err error
   824  	if dbtx == nil {
   825  		dbtx, err = chain.store.BeginTX(false)
   826  		if err != nil {
   827  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   828  			return new(big.Int).SetInt64(0)
   829  		}
   830  
   831  		defer dbtx.Rollback()
   832  
   833  	}
   834  
   835  	cdifficulty_bytes, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY)
   836  
   837  	//cdifficulty, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY)
   838  
   839  	if err != nil {
   840  		logger.Warnf("Error while querying cumulative difficulty for block %s", hash)
   841  		logger.Panicf("Error while querying cumulative difficulty for block %s", hash)
   842  
   843  	}
   844  
   845  	return new(big.Int).SetBytes(cdifficulty_bytes)
   846  }
   847  
   848  func (chain *Blockchain) Load_Block_Difficulty(dbtx storage.DBTX, hash crypto.Hash) *big.Int {
   849  
   850  	var err error
   851  	if dbtx == nil {
   852  		dbtx, err = chain.store.BeginTX(false)
   853  		if err != nil {
   854  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   855  			return new(big.Int).SetInt64(0)
   856  		}
   857  
   858  		defer dbtx.Rollback()
   859  
   860  	}
   861  
   862  	//difficulty, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_DIFFICULTY)
   863  	difficulty_bytes, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_DIFFICULTY)
   864  
   865  	if err != nil {
   866  		logger.Warnf("Error while querying difficulty for block %s", hash)
   867  		logger.Panicf("Error while querying difficulty for block %s", hash)
   868  
   869  	}
   870  
   871  	//return difficulty
   872  	return new(big.Int).SetBytes(difficulty_bytes)
   873  }
   874  
   875  func (chain *Blockchain) Load_Block_Base_Reward(dbtx storage.DBTX, hash crypto.Hash) uint64 {
   876  
   877  	var err error
   878  	if dbtx == nil {
   879  		dbtx, err = chain.store.BeginTX(false)
   880  		if err != nil {
   881  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   882  			return 0
   883  		}
   884  
   885  		defer dbtx.Rollback()
   886  
   887  	}
   888  
   889  	block_reward, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_BASEREWARD)
   890  	if err != nil {
   891  		logger.Warnf("Error while querying base_reward for block %s", hash)
   892  	}
   893  
   894  	return block_reward
   895  }
   896  
   897  // inluding reward + fees
   898  func (chain *Blockchain) Load_Block_Total_Reward(dbtx storage.DBTX, hash crypto.Hash) uint64 {
   899  
   900  	var err error
   901  	if dbtx == nil {
   902  		dbtx, err = chain.store.BeginTX(false)
   903  		if err != nil {
   904  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   905  			return 0
   906  		}
   907  
   908  		defer dbtx.Rollback()
   909  
   910  	}
   911  
   912  	block_reward, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_MINERTX_REWARD)
   913  	if err != nil {
   914  		logger.Warnf("Error while querying base_reward for block %s", hash)
   915  	}
   916  
   917  	return block_reward
   918  }
   919  
   920  func (chain *Blockchain) Load_Already_Generated_Coins_for_Topo_Index(dbtx storage.DBTX, index int64) uint64 {
   921  
   922  	if index < 0 { // fix up pre-genesis
   923  		return 0
   924  	}
   925  
   926  	var err error
   927  	if dbtx == nil {
   928  		dbtx, err = chain.store.BeginTX(false)
   929  		if err != nil {
   930  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   931  			return 0
   932  		}
   933  
   934  		defer dbtx.Rollback()
   935  
   936  	}
   937  
   938  	// first find the block at the topo index
   939  
   940  	hash, err := chain.Load_Block_Topological_order_at_index(dbtx, index)
   941  	if err != nil {
   942  		return 0
   943  	}
   944  
   945  	already_generated_coins, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_ALREADY_GENERATED_COINS)
   946  	if err != nil {
   947  		logger.Warnf("Error while querying alreadt generated coins for block %s", hash)
   948  
   949  	}
   950  
   951  	return already_generated_coins
   952  }
   953  
   954  func (chain *Blockchain) Load_Block_Size(dbtx storage.DBTX, hash crypto.Hash) uint64 {
   955  	var err error
   956  	if dbtx == nil {
   957  		dbtx, err = chain.store.BeginTX(false)
   958  		if err != nil {
   959  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
   960  			return 0
   961  		}
   962  
   963  		defer dbtx.Rollback()
   964  
   965  	}
   966  
   967  	size, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_SIZE)
   968  	if err != nil {
   969  		logger.Warnf("Error while querying size for block %s", hash)
   970  	}
   971  
   972  	return size
   973  }
   974  
   975  /*
   976  func (chain *Blockchain) Load_Block_Parent_ID(hash crypto.Hash) crypto.Hash {
   977  	var parent_id crypto.Hash
   978  	object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_PARENT)
   979  
   980  	if err != nil || len(object_data) != 32 {
   981  		logger.Warnf("Error while querying parent id for block %s", hash)
   982  	}
   983  	copy(parent_id[:], object_data)
   984  
   985  	return parent_id
   986  }
   987  */
   988  
   989  // store current top id
   990  /*
   991  func (chain *Blockchain) Store_TOP_ID(hash crypto.Hash) {
   992  	chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, TOP_ID, TOP_ID, TOP_ID, hash[:])
   993  }
   994  
   995  // crash if something is not correct
   996  func (chain *Blockchain) Load_TOP_ID() (hash crypto.Hash) {
   997  	object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, TOP_ID, TOP_ID, TOP_ID)
   998  
   999  	if err != nil {
  1000  		panic("Backend failure")
  1001  	}
  1002  
  1003  	if len(object_data) == 0 {
  1004  		panic(fmt.Errorf("most probably Database corruption, No TOP_ID stored "))
  1005  	}
  1006  
  1007  	if len(object_data) != 32 {
  1008  		panic("Database corruption, invalid block hash ")
  1009  	}
  1010  	copy(hash[:], object_data[:32])
  1011  	return hash
  1012  }
  1013  
  1014  */
  1015  
  1016  // store current  highest topo id
  1017  func (chain *Blockchain) Store_TOPO_HEIGHT(dbtx storage.DBTX, height int64) {
  1018  	if dbtx == nil {
  1019  		panic("Could NOT change TOP height to chain. Error opening writable TX, err ")
  1020  	}
  1021  	dbtx.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_KEYVALUE, TOPO_HEIGHT, TOPO_HEIGHT, uint64(height))
  1022  }
  1023  
  1024  // faster bootstrap
  1025  func (chain *Blockchain) Load_TOPO_HEIGHT(dbtx storage.DBTX) (height int64) {
  1026  	var err error
  1027  	if dbtx == nil {
  1028  		dbtx, err = chain.store.BeginTX(false)
  1029  		if err != nil {
  1030  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
  1031  			return
  1032  		}
  1033  
  1034  		defer dbtx.Rollback()
  1035  
  1036  	}
  1037  
  1038  	heightx, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_KEYVALUE, TOPO_HEIGHT, TOPO_HEIGHT)
  1039  	if err != nil {
  1040  		// TODO  this panic must be enabled to catch some bugs
  1041  		logger.Warnf("Cannot load  TOPO height for chain err %s", err)
  1042  		return 0
  1043  	}
  1044  	return int64(heightx)
  1045  }
  1046  
  1047  // store current top id  // store top height known
  1048  func (chain *Blockchain) Store_TOP_HEIGHT(dbtx storage.DBTX, height int64) {
  1049  
  1050  	if dbtx == nil {
  1051  		panic("Could NOT change TOP height to chain. Error opening writable TX, ")
  1052  
  1053  	}
  1054  
  1055  	dbtx.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_KEYVALUE, TOP_HEIGHT, TOP_HEIGHT, uint64(height))
  1056  }
  1057  
  1058  // faster bootstrap
  1059  func (chain *Blockchain) Load_TOP_HEIGHT(dbtx storage.DBTX) (height int64) {
  1060  
  1061  	var err error
  1062  	if dbtx == nil {
  1063  		dbtx, err = chain.store.BeginTX(false)
  1064  		if err != nil {
  1065  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
  1066  			return
  1067  		}
  1068  
  1069  		defer dbtx.Rollback()
  1070  
  1071  	}
  1072  
  1073  	heightx, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_KEYVALUE, TOP_HEIGHT, TOP_HEIGHT)
  1074  	if err != nil {
  1075  		// TODO  this panic must be enabled to catch some bugs
  1076  		logger.Warnf("Cannot load  TOP height for chain err %s", err)
  1077  		return 0
  1078  	}
  1079  	return int64(heightx)
  1080  }
  1081  
  1082  // itob returns an 8-byte big endian representation of v.
  1083  func itob(v uint64) []byte {
  1084  	b := make([]byte, 8)
  1085  	binary.BigEndian.PutUint64(b, uint64(v))
  1086  	return b
  1087  }
  1088  
  1089  // get the position from where indexing must start for this block
  1090  // indexing mean vout based index
  1091  // cryptonote works by giving each vout a unique index number
  1092  func (chain *Blockchain) Get_Block_Output_Index(dbtx storage.DBTX, block_id crypto.Hash) (int64, int64) {
  1093  
  1094  	var err error
  1095  	if dbtx == nil {
  1096  		dbtx, err = chain.store.BeginTX(false)
  1097  		if err != nil {
  1098  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
  1099  			return 0, 0
  1100  		}
  1101  
  1102  		defer dbtx.Rollback()
  1103  
  1104  	}
  1105  
  1106  	// first gets the  topo index of this block
  1107  
  1108  	index, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, block_id[:], PLANET_OUTPUT_INDEX)
  1109  	if err != nil {
  1110  		// TODO  this panic must be enabled to catch some bugs
  1111  		logger.Warnf("Cannot load output index for %s err %s", block_id, err)
  1112  		return 0, 0
  1113  	}
  1114  
  1115  	index_end, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, block_id[:], PLANET_OUTPUT_INDEX_END)
  1116  	if err != nil {
  1117  		// TODO  this panic must be enabled to catch some bugs
  1118  		logger.Warnf("Cannot load output index for %s err %s", block_id, err)
  1119  		return int64(index), 0
  1120  	}
  1121  
  1122  	return int64(index), int64(index_end)
  1123  }
  1124  
  1125  func (chain *Blockchain) Get_Blocks_At_Height(dbtx storage.DBTX, height int64) (blocks []crypto.Hash) {
  1126  
  1127  	var err error
  1128  	if dbtx == nil {
  1129  		dbtx, err = chain.store.BeginTX(false)
  1130  		if err != nil {
  1131  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
  1132  			return
  1133  		}
  1134  
  1135  		defer dbtx.Rollback()
  1136  
  1137  	}
  1138  
  1139  	// deserialize height
  1140  	height_bytes, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_HEIGHT, PLANET_HEIGHT, itob(uint64(height)))
  1141  	if err != nil {
  1142  		return
  1143  	}
  1144  	blocks = make([]crypto.Hash, len(height_bytes)/32, len(height_bytes)/32)
  1145  
  1146  	for i := 0; i < len(height_bytes)/32; i++ {
  1147  		copy(blocks[i][:], height_bytes[i*32:(i*32)+32])
  1148  	}
  1149  
  1150  	return
  1151  }
  1152  
  1153  // this will mark a block, tx combination as valid/invalid
  1154  func (chain *Blockchain) mark_TX(dbtx storage.DBTX, blid crypto.Hash, txhash crypto.Hash, valid bool) {
  1155  	if dbtx == nil {
  1156  		panic("dbtx cannot be nil")
  1157  	}
  1158  	store_value := byte(0)
  1159  	if valid {
  1160  		store_value = byte(1)
  1161  	}
  1162  	dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION_VALIDITY, GALAXY_TRANSACTION_VALIDITY, append(blid[:], txhash[:]...), []byte{store_value})
  1163  
  1164  }
  1165  
  1166  // this will return the tx combination as valid/invalid
  1167  func (chain *Blockchain) IS_TX_Valid(dbtx storage.DBTX, blid crypto.Hash, txhash crypto.Hash) bool {
  1168  	var err error
  1169  	if dbtx == nil {
  1170  		dbtx, err = chain.store.BeginTX(false)
  1171  		if err != nil {
  1172  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
  1173  			return false
  1174  		}
  1175  
  1176  		defer dbtx.Rollback()
  1177  
  1178  	}
  1179  
  1180  	object_data, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION_VALIDITY, GALAXY_TRANSACTION_VALIDITY, append(blid[:], txhash[:]...))
  1181  
  1182  	if err != nil {
  1183  		return false
  1184  	}
  1185  
  1186  	if len(object_data) == 0 {
  1187  		return false
  1188  	}
  1189  
  1190  	if len(object_data) != 1 {
  1191  		panic(fmt.Errorf("probably Database corruption, Wrong data stored in tx validity, expected size 1, actual size %d", len(object_data)))
  1192  	}
  1193  
  1194  	if object_data[0] == 1 {
  1195  		return true
  1196  	}
  1197  
  1198  	// anything other than value 1 is considered wrong tx
  1199  
  1200  	return false
  1201  }
  1202  
  1203  // store key image to its own galaxy
  1204  // a keyimage stored with value 1  == it has been consumed
  1205  // a keyimage stored with value 0  == it has not been consumed
  1206  // a key image not found in store == it has NOT been consumed
  1207  // TODO this function should NOT be exported
  1208  func (chain *Blockchain) Store_KeyImage(dbtx storage.DBTX, hash crypto.Hash, height int64) {
  1209  	if dbtx == nil {
  1210  		panic("dbtx cannot be nil")
  1211  	}
  1212  	store_value := itob(uint64(height))
  1213  
  1214  	dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_KEYIMAGE, GALAXY_KEYIMAGE, hash[:], store_value)
  1215  }
  1216  
  1217  // read a key image, whether it's stored with value 1
  1218  // a keyimage stored with value 1  == it has been consumed
  1219  // a keyimage stored with value 0  == it has not been consumed
  1220  // a key image not found in store == it has NOT been consumed
  1221  func (chain *Blockchain) Read_KeyImage_Status(dbtx storage.DBTX, hash crypto.Hash) (int64, bool) {
  1222  
  1223  	var err error
  1224  	if dbtx == nil {
  1225  		dbtx, err = chain.store.BeginTX(false)
  1226  		if err != nil {
  1227  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
  1228  			return -1, false
  1229  		}
  1230  
  1231  		defer dbtx.Rollback()
  1232  
  1233  	}
  1234  
  1235  	marker, err := dbtx.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_KEYIMAGE, GALAXY_KEYIMAGE, hash[:])
  1236  	if err != nil {
  1237  		return -1, false
  1238  	}
  1239  
  1240  	height_consumed := int64(marker)
  1241  
  1242  	if height_consumed < 0 {
  1243  		return -1, false
  1244  	} else {
  1245  		return height_consumed, true
  1246  	}
  1247  
  1248  }
  1249  
  1250  func (chain *Blockchain) store_TX_in_Block(dbtx storage.DBTX, blid, txid crypto.Hash) {
  1251  
  1252  	if dbtx == nil {
  1253  		panic("Could NOT add block to chain. Error opening writable TX,")
  1254  	}
  1255  
  1256  	existing_blocks := chain.Load_TX_blocks(dbtx, txid)
  1257  
  1258  	tx_map := map[crypto.Hash]bool{}
  1259  
  1260  	tx_map[blid] = true
  1261  	for i := range existing_blocks {
  1262  		tx_map[existing_blocks[i]] = true
  1263  	}
  1264  
  1265  	store_value := make([]byte, 0, len(tx_map)*32)
  1266  	for k, _ := range tx_map {
  1267  		store_value = append(store_value, k[:]...)
  1268  	}
  1269  
  1270  	dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, txid[:], PLANET_TX_MINED, store_value)
  1271  
  1272  }
  1273  
  1274  func (chain *Blockchain) Load_TX_blocks(dbtx storage.DBTX, txid crypto.Hash) (blocks []crypto.Hash) {
  1275  
  1276  	var err error
  1277  	if dbtx == nil {
  1278  		dbtx, err = chain.store.BeginTX(false)
  1279  		if err != nil {
  1280  			logger.Warnf("Could NOT add block to chain. Error opening readable TX, err %s", err)
  1281  			return
  1282  		}
  1283  
  1284  		defer dbtx.Rollback()
  1285  
  1286  	}
  1287  
  1288  	object_data, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, txid[:], PLANET_TX_MINED)
  1289  
  1290  	if err != nil {
  1291  		return
  1292  	}
  1293  
  1294  	if len(object_data)%32 != 0 {
  1295  		panic(fmt.Errorf("probably Database corruption, no blocks found for tx %s  actual size %d", txid, len(object_data)))
  1296  	}
  1297  
  1298  	if len(object_data) >= 32 {
  1299  		blocks = make([]crypto.Hash, len(object_data)/32, len(object_data)/32)
  1300  		for i := 0; i < len(object_data)/32; i++ {
  1301  			copy(blocks[i][:], object_data[i*32:i*32+32])
  1302  		}
  1303  	}
  1304  	return blocks
  1305  
  1306  }
  1307  
  1308  // store settle status within the block
  1309  // a blockid with stored with value 1  == it has been settled
  1310  // a blockid stored with value 0  == it has not been settled
  1311  // a blockid not found in store == it has NOT been settled
  1312  func (chain *Blockchain) store_TIPS(dbtx storage.DBTX, tips []crypto.Hash) {
  1313  
  1314  	if dbtx == nil {
  1315  		panic("Could NOT add block to chain. Error opening writable TX,")
  1316  	}
  1317  
  1318  	store_value := make([]byte, 0, len(tips)*32)
  1319  	for i := range tips {
  1320  		store_value = append(store_value, tips[i][:]...)
  1321  	}
  1322  	dbtx.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_KEYVALUE, TIPS, TIPS, store_value)
  1323  }
  1324  
  1325  // this is exported for rpc server
  1326  func (chain *Blockchain) Load_TIPS_ATOMIC(dbtx storage.DBTX) (tips []crypto.Hash) {
  1327       return chain.load_TIPS(dbtx)
  1328  }
  1329  func (chain *Blockchain) load_TIPS(dbtx storage.DBTX) (tips []crypto.Hash) {
  1330  
  1331  	var err error
  1332  	if dbtx == nil {
  1333  		dbtx, err = chain.store.BeginTX(false)
  1334  		if err != nil {
  1335  			logger.Warnf("Could NOT add block to chain. Error opening writable TX, err %s", err)
  1336  			return
  1337  		}
  1338  
  1339  		defer dbtx.Rollback()
  1340  
  1341  	}
  1342  
  1343  	object_data, err := dbtx.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_KEYVALUE, TIPS, TIPS)
  1344  
  1345  	if err != nil {
  1346  		return
  1347  	}
  1348  
  1349  	if len(object_data) == 0 || len(object_data)%32 != 0 {
  1350  		panic(fmt.Errorf("probably Database corruption, No tips founds or invalid tips, tips  actual size %d", len(object_data)))
  1351  	}
  1352  
  1353  	tips = make([]crypto.Hash, len(object_data)/32, len(object_data)/32)
  1354  	for i := 0; i < len(object_data)/32; i++ {
  1355  		copy(tips[i][:], object_data[i*32:i*32+32])
  1356  	}
  1357  	return tips
  1358  }
  1359  
  1360  /*
  1361  // store settle status within the block
  1362  // a blockid with stored with value 1  == it has been settled
  1363  // a blockid stored with value 0  == it has not been settled
  1364  // a blockid not found in store == it has NOT been settled
  1365  func (chain *Blockchain) store_Block_Settled(hash crypto.Hash, settled bool) {
  1366  	store_value := byte(0)
  1367  	if settled {
  1368  		store_value = byte(1)
  1369  	}
  1370  	chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_SETTLE_STATUS, []byte{store_value})
  1371  }
  1372  
  1373  // query whether the block is  settled
  1374  // a blockid with stored with value 1  == it has been settled
  1375  // a blockid stored with value 0  == it has not been settled
  1376  // a blockid not found in store == it has NOT been settled
  1377  func (chain *Blockchain) IsBlockSettled(hash crypto.Hash) bool {
  1378  	object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_SETTLE_STATUS)
  1379  
  1380  	if err != nil {
  1381  		return false
  1382  	}
  1383  
  1384  	if len(object_data) == 0 {
  1385  		return false
  1386  	}
  1387  
  1388  	if len(object_data) != 1 {
  1389  		panic(fmt.Errorf("probably Database corruption, Wrong data stored in settle status, expected size 1, actual size %d", len(object_data)))
  1390  	}
  1391  
  1392  	if object_data[0] == 1 {
  1393  		return true
  1394  	}
  1395  
  1396  
  1397  	// anything other than value 1 is considered  not settled
  1398  
  1399  	return false
  1400  }
  1401  */