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 */