github.com/deso-protocol/core@v1.2.9/lib/db_utils_test.go (about) 1 package lib 2 3 import ( 4 "io/ioutil" 5 "log" 6 "math/big" 7 "os" 8 "testing" 9 "time" 10 11 "github.com/btcsuite/btcd/btcec" 12 "github.com/dgraph-io/badger/v3" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 ) 16 17 func _GetTestBlockNode() *BlockNode { 18 bs := BlockNode{} 19 20 // Hash 21 bs.Hash = &BlockHash{ 22 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 23 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 24 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 25 0x30, 0x31, 26 } 27 28 // Height 29 bs.Height = 123456789 30 31 // DifficultyTarget 32 bs.DifficultyTarget = &BlockHash{ 33 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 34 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 35 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 36 0x30, 0x31, 37 } 38 39 // CumWork 40 bs.CumWork = big.NewInt(5) 41 42 // Header (make a copy) 43 bs.Header = NewMessage(MsgTypeHeader).(*MsgDeSoHeader) 44 headerBytes, _ := expectedBlockHeader.ToBytes(false) 45 bs.Header.FromBytes(headerBytes) 46 47 // Status 48 bs.Status = StatusBlockValidated 49 50 return &bs 51 } 52 53 func GetTestBadgerDb() (_db *badger.DB, _dir string) { 54 dir, err := ioutil.TempDir("", "badgerdb") 55 if err != nil { 56 log.Fatal(err) 57 } 58 59 // Open a badgerdb in a temporary directory. 60 opts := badger.DefaultOptions(dir) 61 opts.Dir = dir 62 opts.ValueDir = dir 63 db, err := badger.Open(opts) 64 if err != nil { 65 log.Fatal(err) 66 } 67 68 return db, dir 69 } 70 71 func TestBlockNodeSerialize(t *testing.T) { 72 assert := assert.New(t) 73 require := require.New(t) 74 _ = assert 75 _ = require 76 77 bs := _GetTestBlockNode() 78 79 serialized, err := SerializeBlockNode(bs) 80 require.NoError(err) 81 deserialized, err := DeserializeBlockNode(serialized) 82 require.NoError(err) 83 84 assert.Equal(bs, deserialized) 85 } 86 87 func TestBlockNodePutGet(t *testing.T) { 88 assert := assert.New(t) 89 require := require.New(t) 90 _ = assert 91 _ = require 92 93 // Create a test db and clean up the files at the end. 94 db, dir := GetTestBadgerDb() 95 defer os.RemoveAll(dir) 96 97 // Make a blockchain that looks as follows: 98 // b1 - -> b2 -> b3 99 // \ -> b4 100 // I.e. there's a side chain in there. 101 b1 := _GetTestBlockNode() 102 b1.Height = 0 103 b2 := _GetTestBlockNode() 104 b2.Hash[0] = 0x99 // Make the hash of b2 sort lexographically later than b4 for kicks. 105 b2.Header.PrevBlockHash = b1.Hash 106 b2.Height = 1 107 b3 := _GetTestBlockNode() 108 b3.Hash[0] = 0x03 109 b3.Header.PrevBlockHash = b2.Hash 110 b3.Height = 2 111 b4 := _GetTestBlockNode() 112 b4.Hash[0] = 0x04 113 b4.Header.PrevBlockHash = b1.Hash 114 b4.Height = 1 115 116 err := PutHeightHashToNodeInfo(b1, db, false /*bitcoinNodes*/) 117 require.NoError(err) 118 119 err = PutHeightHashToNodeInfo(b2, db, false /*bitcoinNodes*/) 120 require.NoError(err) 121 122 err = PutHeightHashToNodeInfo(b3, db, false /*bitcoinNodes*/) 123 require.NoError(err) 124 125 err = PutHeightHashToNodeInfo(b4, db, false /*bitcoinNodes*/) 126 require.NoError(err) 127 128 blockIndex, err := GetBlockIndex(db, false /*bitcoinNodes*/) 129 require.NoError(err) 130 131 require.Len(blockIndex, 4) 132 b1Ret, exists := blockIndex[*b1.Hash] 133 require.True(exists, "b1 not found") 134 135 b2Ret, exists := blockIndex[*b2.Hash] 136 require.True(exists, "b2 not found") 137 138 b3Ret, exists := blockIndex[*b3.Hash] 139 require.True(exists, "b3 not found") 140 141 b4Ret, exists := blockIndex[*b4.Hash] 142 require.True(exists, "b4 not found") 143 144 // Make sure the hashes all line up. 145 require.Equal(b1.Hash[:], b1Ret.Hash[:]) 146 require.Equal(b2.Hash[:], b2Ret.Hash[:]) 147 require.Equal(b3.Hash[:], b3Ret.Hash[:]) 148 require.Equal(b4.Hash[:], b4Ret.Hash[:]) 149 150 // Make sure the nodes are connected properly. 151 require.Nil(b1Ret.Parent) 152 require.Equal(b2Ret.Parent, b1Ret) 153 require.Equal(b3Ret.Parent, b2Ret) 154 require.Equal(b4Ret.Parent, b1Ret) 155 156 // Check that getting the best chain works. 157 { 158 bestChain, err := GetBestChain(b3Ret, blockIndex) 159 require.NoError(err) 160 require.Len(bestChain, 3) 161 require.Equal(b1Ret, bestChain[0]) 162 require.Equal(b2Ret, bestChain[1]) 163 require.Equal(b3Ret, bestChain[2]) 164 } 165 } 166 167 func TestInitDbWithGenesisBlock(t *testing.T) { 168 assert := assert.New(t) 169 require := require.New(t) 170 _ = assert 171 _ = require 172 173 // Create a test db and clean up the files at the end. 174 db, dir := GetTestBadgerDb() 175 defer os.RemoveAll(dir) 176 177 err := InitDbWithDeSoGenesisBlock(&DeSoTestnetParams, db, nil) 178 require.NoError(err) 179 180 // Check the block index. 181 blockIndex, err := GetBlockIndex(db, false /*bitcoinNodes*/) 182 require.NoError(err) 183 require.Len(blockIndex, 1) 184 genesisHash := *MustDecodeHexBlockHash(DeSoTestnetParams.GenesisBlockHashHex) 185 genesis, exists := blockIndex[genesisHash] 186 require.True(exists, "genesis block not found in index") 187 require.NotNil(genesis) 188 require.Equal(&genesisHash, genesis.Hash) 189 190 // Check the bestChain. 191 bestChain, err := GetBestChain(genesis, blockIndex) 192 require.NoError(err) 193 require.Len(bestChain, 1) 194 require.Equal(genesis, bestChain[0]) 195 } 196 197 func TestPrivateMessages(t *testing.T) { 198 assert := assert.New(t) 199 require := require.New(t) 200 _ = assert 201 _ = require 202 203 // Create a test db and clean up the files at the end. 204 db, dir := GetTestBadgerDb() 205 defer os.RemoveAll(dir) 206 207 priv1, err := btcec.NewPrivateKey(btcec.S256()) 208 require.NoError(err) 209 pk1 := priv1.PubKey().SerializeCompressed() 210 211 priv2, err := btcec.NewPrivateKey(btcec.S256()) 212 require.NoError(err) 213 pk2 := priv2.PubKey().SerializeCompressed() 214 215 priv3, err := btcec.NewPrivateKey(btcec.S256()) 216 require.NoError(err) 217 pk3 := priv3.PubKey().SerializeCompressed() 218 219 tstamp1 := uint64(1) 220 tstamp2 := uint64(2) 221 tstamp3 := uint64(12345) 222 tstamp4 := uint64(time.Now().UnixNano()) 223 tstamp5 := uint64(time.Now().UnixNano()) 224 225 message1Str := []byte("message1: abcdef") 226 message2Str := []byte("message2: ghi") 227 message3Str := []byte("message3: klmn\123\000\000\000_") 228 message4Str := append([]byte("message4: "), RandomBytes(100)...) 229 message5Str := append([]byte("message5: "), RandomBytes(123)...) 230 231 // pk1 -> pk2: message1Str, tstamp1 232 require.NoError(DbPutMessageEntry( 233 db, &MessageEntry{ 234 SenderPublicKey: pk1, 235 TstampNanos: tstamp1, 236 RecipientPublicKey: pk2, 237 EncryptedText: message1Str, 238 })) 239 // pk2 -> pk1: message2Str, tstamp2 240 require.NoError(DbPutMessageEntry( 241 db, &MessageEntry{ 242 SenderPublicKey: pk2, 243 TstampNanos: tstamp2, 244 RecipientPublicKey: pk1, 245 EncryptedText: message2Str, 246 })) 247 // pk3 -> pk1: message3Str, tstamp3 248 require.NoError(DbPutMessageEntry( 249 db, &MessageEntry{ 250 SenderPublicKey: pk3, 251 TstampNanos: tstamp3, 252 RecipientPublicKey: pk1, 253 EncryptedText: message3Str, 254 })) 255 // pk2 -> pk1: message4Str, tstamp4 256 require.NoError(DbPutMessageEntry( 257 db, &MessageEntry{ 258 SenderPublicKey: pk2, 259 TstampNanos: tstamp4, 260 RecipientPublicKey: pk1, 261 EncryptedText: message4Str, 262 })) 263 // pk1 -> pk3: message5Str, tstamp5 264 require.NoError(DbPutMessageEntry( 265 db, &MessageEntry{ 266 SenderPublicKey: pk1, 267 TstampNanos: tstamp5, 268 RecipientPublicKey: pk3, 269 EncryptedText: message5Str, 270 })) 271 272 // Define all the messages as they appear in the db. 273 message1 := &MessageEntry{ 274 SenderPublicKey: pk1, 275 RecipientPublicKey: pk2, 276 EncryptedText: message1Str, 277 TstampNanos: tstamp1, 278 } 279 message2 := &MessageEntry{ 280 SenderPublicKey: pk2, 281 RecipientPublicKey: pk1, 282 EncryptedText: message2Str, 283 TstampNanos: tstamp2, 284 } 285 message3 := &MessageEntry{ 286 SenderPublicKey: pk3, 287 RecipientPublicKey: pk1, 288 EncryptedText: message3Str, 289 TstampNanos: tstamp3, 290 } 291 message4 := &MessageEntry{ 292 SenderPublicKey: pk2, 293 RecipientPublicKey: pk1, 294 EncryptedText: message4Str, 295 TstampNanos: tstamp4, 296 } 297 message5 := &MessageEntry{ 298 SenderPublicKey: pk1, 299 RecipientPublicKey: pk3, 300 EncryptedText: message5Str, 301 TstampNanos: tstamp5, 302 } 303 304 // Fetch message3 directly using both public keys. 305 { 306 msg := DbGetMessageEntry(db, pk3, tstamp3) 307 require.Equal(message3, msg) 308 } 309 { 310 msg := DbGetMessageEntry(db, pk1, tstamp3) 311 require.Equal(message3, msg) 312 } 313 314 // Fetch all messages for pk1 315 { 316 messages, err := DbGetMessageEntriesForPublicKey(db, pk1) 317 require.NoError(err) 318 319 require.Equal([]*MessageEntry{ 320 message1, 321 message2, 322 message3, 323 message4, 324 message5, 325 }, messages) 326 } 327 328 // Fetch all messages for pk2 329 { 330 messages, err := DbGetMessageEntriesForPublicKey(db, pk2) 331 require.NoError(err) 332 333 require.Equal([]*MessageEntry{ 334 message1, 335 message2, 336 message4, 337 }, messages) 338 } 339 340 // Fetch all messages for pk3 341 { 342 messages, err := DbGetMessageEntriesForPublicKey(db, pk3) 343 require.NoError(err) 344 345 require.Equal([]*MessageEntry{ 346 message3, 347 message5, 348 }, messages) 349 } 350 351 // Delete message3 352 require.NoError(DbDeleteMessageEntryMappings(db, pk1, tstamp3)) 353 354 // Now all the messages returned should exclude message3 355 { 356 messages, err := DbGetMessageEntriesForPublicKey(db, pk1) 357 require.NoError(err) 358 359 require.Equal([]*MessageEntry{ 360 message1, 361 message2, 362 message4, 363 message5, 364 }, messages) 365 } 366 { 367 messages, err := DbGetMessageEntriesForPublicKey(db, pk2) 368 require.NoError(err) 369 370 require.Equal([]*MessageEntry{ 371 message1, 372 message2, 373 message4, 374 }, messages) 375 } 376 { 377 messages, err := DbGetMessageEntriesForPublicKey(db, pk3) 378 require.NoError(err) 379 380 require.Equal([]*MessageEntry{ 381 message5, 382 }, messages) 383 } 384 385 // Delete all remaining messages, sometimes using the recipient rather 386 // than the sender public key 387 require.NoError(DbDeleteMessageEntryMappings(db, pk2, tstamp1)) 388 require.NoError(DbDeleteMessageEntryMappings(db, pk1, tstamp2)) 389 require.NoError(DbDeleteMessageEntryMappings(db, pk2, tstamp4)) 390 require.NoError(DbDeleteMessageEntryMappings(db, pk1, tstamp5)) 391 392 // Now all public keys should have zero messages. 393 { 394 messages, err := DbGetMessageEntriesForPublicKey(db, pk1) 395 require.NoError(err) 396 require.Equal(0, len(messages)) 397 } 398 { 399 messages, err := DbGetMessageEntriesForPublicKey(db, pk2) 400 require.NoError(err) 401 require.Equal(0, len(messages)) 402 } 403 { 404 messages, err := DbGetMessageEntriesForPublicKey(db, pk3) 405 require.NoError(err) 406 require.Equal(0, len(messages)) 407 } 408 } 409 410 func TestFollows(t *testing.T) { 411 assert := assert.New(t) 412 require := require.New(t) 413 _ = assert 414 _ = require 415 416 // Create a test db and clean up the files at the end. 417 db, dir := GetTestBadgerDb() 418 defer os.RemoveAll(dir) 419 420 priv1, err := btcec.NewPrivateKey(btcec.S256()) 421 require.NoError(err) 422 pk1 := priv1.PubKey().SerializeCompressed() 423 424 priv2, err := btcec.NewPrivateKey(btcec.S256()) 425 require.NoError(err) 426 pk2 := priv2.PubKey().SerializeCompressed() 427 428 priv3, err := btcec.NewPrivateKey(btcec.S256()) 429 require.NoError(err) 430 pk3 := priv3.PubKey().SerializeCompressed() 431 432 // Get the PKIDs for all the public keys 433 pkid1 := DBGetPKIDEntryForPublicKey(db, pk1).PKID 434 pkid2 := DBGetPKIDEntryForPublicKey(db, pk2).PKID 435 pkid3 := DBGetPKIDEntryForPublicKey(db, pk3).PKID 436 437 // PK2 follows everyone. Make sure "get" works properly. 438 require.Nil(DbGetFollowerToFollowedMapping(db, pkid2, pkid1)) 439 require.NoError(DbPutFollowMappings(db, pkid2, pkid1)) 440 require.NotNil(DbGetFollowerToFollowedMapping(db, pkid2, pkid1)) 441 require.Nil(DbGetFollowerToFollowedMapping(db, pkid2, pkid3)) 442 require.NoError(DbPutFollowMappings(db, pkid2, pkid3)) 443 require.NotNil(DbGetFollowerToFollowedMapping(db, pkid2, pkid3)) 444 445 // pkid3 only follows pkid1. Make sure "get" works properly. 446 require.Nil(DbGetFollowerToFollowedMapping(db, pkid3, pkid1)) 447 require.NoError(DbPutFollowMappings(db, pkid3, pkid1)) 448 require.NotNil(DbGetFollowerToFollowedMapping(db, pkid3, pkid1)) 449 450 // Check PK1's followers. 451 { 452 pubKeys, err := DbGetPubKeysFollowingYou(db, pk1) 453 require.NoError(err) 454 for i := 0; i < len(pubKeys); i++ { 455 require.Contains([][]byte{pk2, pk3}, pubKeys[i]) 456 } 457 } 458 459 // Check PK1's follows. 460 { 461 pubKeys, err := DbGetPubKeysYouFollow(db, pk1) 462 require.NoError(err) 463 require.Equal(len(pubKeys), 0) 464 } 465 466 // Check PK2's followers. 467 { 468 pubKeys, err := DbGetPubKeysFollowingYou(db, pk2) 469 require.NoError(err) 470 require.Equal(len(pubKeys), 0) 471 } 472 473 // Check PK2's follows. 474 { 475 pubKeys, err := DbGetPubKeysYouFollow(db, pk2) 476 require.NoError(err) 477 for i := 0; i < len(pubKeys); i++ { 478 require.Contains([][]byte{pk1, pk3}, pubKeys[i]) 479 } 480 } 481 482 // Check PK3's followers. 483 { 484 pubKeys, err := DbGetPubKeysFollowingYou(db, pk3) 485 require.NoError(err) 486 for i := 0; i < len(pubKeys); i++ { 487 require.Contains([][]byte{pk2}, pubKeys[i]) 488 } 489 } 490 491 // Check PK3's follows. 492 { 493 pubKeys, err := DbGetPubKeysYouFollow(db, pk3) 494 require.NoError(err) 495 for i := 0; i < len(pubKeys); i++ { 496 require.Contains([][]byte{pk1, pk1}, pubKeys[i]) 497 } 498 } 499 500 // Delete PK2's follows. 501 require.NoError(DbDeleteFollowMappings(db, pkid2, pkid1)) 502 require.NoError(DbDeleteFollowMappings(db, pkid2, pkid3)) 503 504 // Check PK2's follows were actually deleted. 505 { 506 pubKeys, err := DbGetPubKeysYouFollow(db, pk2) 507 require.NoError(err) 508 require.Equal(len(pubKeys), 0) 509 } 510 }