github.com/deso-protocol/core@v1.2.9/lib/block_view_bitcoin_test.go (about) 1 package lib 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "fmt" 7 "github.com/btcsuite/btcd/btcec" 8 "github.com/btcsuite/btcd/wire" 9 merkletree "github.com/deso-protocol/go-merkle-tree" 10 "github.com/dgraph-io/badger/v3" 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 "io/ioutil" 14 "math/big" 15 "os" 16 "strconv" 17 "strings" 18 "testing" 19 ) 20 21 const ( 22 BitcoinTestnetMnemonic = "clump donkey smoke" 23 BitcoinTestnetDerivationPath = "m/44'/1'/0'/" 24 25 BitcoinTestnetBurnAddress = "ms9ybkD3E685i54ZqW8osN7qg3KnQXZabH" 26 BitcoinTestnetBurnPub = "02bcb72f2dcc0a21aaa31ba792c8bf4a13e3393d7d1b3073afbac613a06dd1d99f" 27 BitcoinTestnetBurnPriv = "cUFfryF4sMvdPzcXMXRVFfK4D5wZzsbZDEqGfBdb7o2MJfE9aoiN" 28 29 BitcoinTestnetAddress1 = "mqsT6WSy5D1xa2GGxsVm1dPGrk7shccwk3" 30 BitcoinTestnetPub1 = "02bce3413e2c2eb510208fefd883861f4d65ac494070a76a837196ea663c00f23c" 31 BitcoinTestnetPriv1 = "cQ6NjLY85qGNpEr8rsHZRs4USVpYVLUzYiqufVTpw2gvQ3Hrcfdf" 32 33 BitcoinTestnetAddress2 = "mzcT3DXVuEZho8FZS6428Tk8gbyDTeBRyF" 34 BitcoinTestnetPub2 = "0368bb82e27246e4fc386eb641fee1ae7bc0b0e0684753a58c64370eab9573ce80" 35 BitcoinTestnetPriv2 = "cR2cSmj3pZ51JGjVzmvHiJwAY1m7tb9x8FCesdSkqzBUHayzifM8" 36 37 BitcoinTestnetAddress3 = "myewf7QQJbXhzdx8QUZuxbtqUuD71Dhwy2" 38 BitcoinTestnetPub3 = "03da23d9ac943570a2ecf543733c3f39b8037144397b3bd2306e881539170e47d6" 39 BitcoinTestnetPriv3 = "cU5PpBsfZbiHfFaCoBVDnCo8wYEUjkr4NxbhnRcSd5qPvG5ofKvN" 40 41 TestDataDir = "../test_data" 42 ) 43 44 func GetTestParamsCopy( 45 startHeader *wire.BlockHeader, startHeight uint32, 46 paramss *DeSoParams, minBurnBlocks uint32, 47 ) *DeSoParams { 48 // Set the BitcoinExchange-related params to canned values. 49 paramsCopy := *paramss 50 headerHash := (BlockHash)(startHeader.BlockHash()) 51 paramsCopy.BitcoinStartBlockNode = NewBlockNode( 52 nil, /*ParentNode*/ 53 &headerHash, /*Hash*/ 54 startHeight, 55 _difficultyBitsToHash(startHeader.Bits), 56 // CumWork: We set the work of the start node such that, when added to all of the 57 // blocks that follow it, it hurdles the min chain work. 58 big.NewInt(0), 59 // We are bastardizing the DeSo header to store Bitcoin information here. 60 &MsgDeSoHeader{ 61 TstampSecs: uint64(startHeader.Timestamp.Unix()), 62 Height: 0, 63 }, 64 StatusBitcoinHeaderValidated, 65 ) 66 67 return ¶msCopy 68 } 69 70 func _dumpAndLoadMempool(mempool *DeSoMempool) { 71 mempoolDir := os.TempDir() 72 mempool.mempoolDir = mempoolDir 73 mempool.DumpTxnsToDB() 74 newMempool := NewDeSoMempool( 75 mempool.bc, 0, /* rateLimitFeeRateNanosPerKB */ 76 0 /* minFeeRateNanosPerKB */, "", true, 77 mempool.dataDir, mempoolDir) 78 mempool.mempoolDir = "" 79 mempool.resetPool(newMempool) 80 } 81 82 func _readBitcoinExchangeTestData(t *testing.T) ( 83 _blocks []*wire.MsgBlock, _headers []*wire.BlockHeader, _headerHeights []uint32) { 84 85 require := require.New(t) 86 87 blocks := []*wire.MsgBlock{} 88 { 89 data, err := ioutil.ReadFile(TestDataDir + "/bitcoin_testnet_blocks_containing_burn.txt") 90 require.NoError(err) 91 92 lines := strings.Split(string(data), "\n") 93 lines = lines[:len(lines)-1] 94 95 for _, ll := range lines { 96 cols := strings.Split(ll, ",") 97 blockHash := mustDecodeHexBlockHash(cols[0]) 98 block := &wire.MsgBlock{} 99 blockBytes, err := hex.DecodeString(cols[1]) 100 require.NoError(err) 101 102 err = block.Deserialize(bytes.NewBuffer(blockBytes)) 103 require.NoError(err) 104 105 parsedBlockHash := (BlockHash)(block.BlockHash()) 106 require.Equal(*blockHash, parsedBlockHash) 107 108 blocks = append(blocks, block) 109 } 110 } 111 112 headers := []*wire.BlockHeader{} 113 headerHeights := []uint32{} 114 { 115 data, err := ioutil.ReadFile(TestDataDir + "/bitcoin_testnet_headers_for_burn.txt") 116 require.NoError(err) 117 118 lines := strings.Split(string(data), "\n") 119 lines = lines[:len(lines)-1] 120 121 for _, ll := range lines { 122 cols := strings.Split(ll, ",") 123 124 // Parse the block height 125 blockHeight, err := strconv.Atoi(cols[0]) 126 require.NoError(err) 127 128 // Parse the header hash 129 headerHashBytes, err := hex.DecodeString(cols[1]) 130 require.NoError(err) 131 headerHash := BlockHash{} 132 copy(headerHash[:], headerHashBytes[:]) 133 134 // Parse the header 135 headerBytes, err := hex.DecodeString(cols[2]) 136 require.NoError(err) 137 header := &wire.BlockHeader{} 138 header.Deserialize(bytes.NewBuffer(headerBytes)) 139 140 // Verify that the header hash matches the hash of the header. 141 require.Equal(headerHash, (BlockHash)(header.BlockHash())) 142 143 headers = append(headers, header) 144 headerHeights = append(headerHeights, uint32(blockHeight)) 145 } 146 } 147 return blocks, headers, headerHeights 148 } 149 150 func _privStringToKeys(t *testing.T, privString string) (*btcec.PrivateKey, *btcec.PublicKey) { 151 require := require.New(t) 152 result, _, err := Base58CheckDecodePrefix(privString, 1) 153 require.NoError(err) 154 result = result[:len(result)-1] 155 return btcec.PrivKeyFromBytes(btcec.S256(), result) 156 } 157 158 func _updateUSDCentsPerBitcoinExchangeRate(t *testing.T, chain *Blockchain, db *badger.DB, 159 params *DeSoParams, feeRateNanosPerKB uint64, updaterPkBase58Check string, 160 updaterPrivBase58Check string, usdCentsPerBitcoin uint64) ( 161 _utxoOps []*UtxoOperation, _txn *MsgDeSoTxn, _height uint32, _err error) { 162 163 assert := assert.New(t) 164 require := require.New(t) 165 _ = assert 166 _ = require 167 168 updaterPkBytes, _, err := Base58CheckDecode(updaterPkBase58Check) 169 require.NoError(err) 170 171 txn, totalInputMake, changeAmountMake, feesMake, err := chain.CreateUpdateBitcoinUSDExchangeRateTxn( 172 updaterPkBytes, 173 usdCentsPerBitcoin, 174 feeRateNanosPerKB, 175 nil, 176 []*DeSoOutput{}) 177 if err != nil { 178 return nil, nil, 0, err 179 } 180 181 require.Equal(totalInputMake, changeAmountMake+feesMake) 182 183 // Sign the transaction now that its inputs are set up. 184 _signTxn(t, txn, updaterPrivBase58Check) 185 186 utxoView, err := NewUtxoView(db, params, nil) 187 require.NoError(err) 188 189 txHash := txn.Hash() 190 // Always use height+1 for validation since it's assumed the transaction will 191 // get mined into the next block. 192 blockHeight := chain.blockTip().Height + 1 193 utxoOps, totalInput, totalOutput, fees, err := 194 utxoView.ConnectTransaction(txn, txHash, getTxnSize(*txn), blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 195 // ConnectTransaction should treat the amount locked as contributing to the 196 // output. 197 if err != nil { 198 return nil, nil, 0, err 199 } 200 require.Equal(totalInput, totalOutput+fees) 201 require.Equal(totalInput, totalInputMake) 202 203 // We should have one SPEND UtxoOperation for each input, one ADD operation 204 // for each output, and one OperationTypePrivateMessage operation at the end. 205 require.Equal(len(txn.TxInputs)+len(txn.TxOutputs)+1, len(utxoOps)) 206 for ii := 0; ii < len(txn.TxInputs); ii++ { 207 require.Equal(OperationTypeSpendUtxo, utxoOps[ii].Type) 208 } 209 require.Equal( 210 OperationTypeUpdateBitcoinUSDExchangeRate, utxoOps[len(utxoOps)-1].Type) 211 212 return utxoOps, txn, blockHeight, nil 213 } 214 215 func TestBitcoinExchange(t *testing.T) { 216 assert := assert.New(t) 217 require := require.New(t) 218 _ = assert 219 _ = require 220 221 // Don't refresh the universal view for this test, since it causes a race condition 222 // to trigger. 223 // TODO: Lower this value to .1 and fix this race condition. 224 ReadOnlyUtxoViewRegenerationIntervalSeconds = 100 225 226 oldInitialUSDCentsPerBitcoinExchangeRate := InitialUSDCentsPerBitcoinExchangeRate 227 InitialUSDCentsPerBitcoinExchangeRate = uint64(1350000) 228 defer func() { 229 InitialUSDCentsPerBitcoinExchangeRate = oldInitialUSDCentsPerBitcoinExchangeRate 230 }() 231 232 paramsTmp := DeSoTestnetParams 233 paramsTmp.DeSoNanosPurchasedAtGenesis = 0 234 chain, params, db := NewLowDifficultyBlockchainWithParams(¶msTmp) 235 mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/) 236 237 // Read in the test Bitcoin blocks and headers. 238 bitcoinBlocks, bitcoinHeaders, bitcoinHeaderHeights := _readBitcoinExchangeTestData(t) 239 240 // Extract BitcoinExchange transactions from the test Bitcoin blocks. 241 bitcoinExchangeTxns := []*MsgDeSoTxn{} 242 for _, block := range bitcoinBlocks { 243 currentBurnTxns, err := 244 ExtractBitcoinExchangeTransactionsFromBitcoinBlock( 245 block, BitcoinTestnetBurnAddress, params) 246 require.NoError(err) 247 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentBurnTxns...) 248 } 249 250 // Verify that Bitcoin burn transactions are properly extracted from Bitcoin blocks 251 // and the their burn amounts are computed correctly. 252 require.Equal(9, len(bitcoinExchangeTxns)) 253 expectedBitcoinBurnAmounts := []int64{ 254 10000, 255 12500, 256 41000, 257 20000, 258 15000, 259 50000, 260 15000, 261 20482, 262 2490, 263 } 264 rateUpdateIndex := 4 265 expectedDeSoNanosMinted := []int64{ 266 2700510570, 267 3375631103, 268 11072014581, 269 5400951887, 270 // We double the exchange rate at this point. Include a zero 271 // here to account for this. 272 0, 273 8103578296, 274 27011598923, 275 8103381058, 276 11064823217, 277 1345146534, 278 } 279 blockIndexesForTransactions := []int{1, 1, 1, 1, 1, 1, 1, 3, 3} 280 for ii, bitcoinExchangeTxn := range bitcoinExchangeTxns { 281 txnMeta := bitcoinExchangeTxn.TxnMeta.(*BitcoinExchangeMetadata) 282 burnTxn := txnMeta.BitcoinTransaction 283 burnOutput, err := _computeBitcoinBurnOutput( 284 burnTxn, BitcoinTestnetBurnAddress, params.BitcoinBtcdParams) 285 require.NoError(err) 286 assert.Equalf(expectedBitcoinBurnAmounts[ii], burnOutput, 287 "Bitcoin burn amount for burn txn %d doesn't line up with "+ 288 "what is expected", ii) 289 290 // Sanity-check that the Bitcoin block hashes line up. 291 blockIndex := blockIndexesForTransactions[ii] 292 blockForTxn := bitcoinBlocks[blockIndex] 293 { 294 hash1 := (BlockHash)(blockForTxn.BlockHash()) 295 hash2 := *txnMeta.BitcoinBlockHash 296 require.Equalf( 297 hash1, hash2, 298 "Bitcoin block hash for txn does not line up with block hash: %v %v %d", &hash1, &hash2, ii) 299 } 300 301 // Sanity-check that the Merkle root lines up with what's in the block. 302 { 303 hash1 := (BlockHash)(blockForTxn.Header.MerkleRoot) 304 hash2 := *txnMeta.BitcoinMerkleRoot 305 require.Equalf( 306 hash1, hash2, 307 "Bitcoin merkle root for txn does not line up with block hash: %v %v %d", &hash1, &hash2, ii) 308 } 309 310 // Verify that the merkle proof checks out. 311 { 312 txHash := ((BlockHash)(txnMeta.BitcoinTransaction.TxHash())) 313 merkleProofIsValid := merkletree.VerifyProof( 314 txHash[:], txnMeta.BitcoinMerkleProof, txnMeta.BitcoinMerkleRoot[:]) 315 require.Truef( 316 merkleProofIsValid, "Problem verifying merkle proof for burn txn %d", ii) 317 } 318 319 // Verify that using the wrong Merkle root doesn't work. 320 { 321 badBlock := bitcoinBlocks[blockIndex-1] 322 badMerkleRoot := badBlock.Header.MerkleRoot[:] 323 txHash := ((BlockHash)(txnMeta.BitcoinTransaction.TxHash())) 324 merkleProofIsValid := merkletree.VerifyProof( 325 txHash[:], txnMeta.BitcoinMerkleProof, badMerkleRoot) 326 require.Falsef( 327 merkleProofIsValid, "Bad Merkle root was actually verified for burn txn %d", ii) 328 } 329 330 // Verify that serializing and deserializing work for this transaction. 331 bb, err := bitcoinExchangeTxn.ToBytes(false /*preSignature*/) 332 require.NoError(err) 333 parsedBitcoinExchangeTxn := &MsgDeSoTxn{} 334 parsedBitcoinExchangeTxn.FromBytes(bb) 335 require.Equal(bitcoinExchangeTxn, parsedBitcoinExchangeTxn) 336 } 337 338 // Find the header in our header list corresponding to the first test block, 339 // which contains the first Bitcoin 340 firstBitcoinBurnBlock := bitcoinBlocks[1] 341 firstBitcoinBurnBlockHash := firstBitcoinBurnBlock.BlockHash() 342 headerIndexOfFirstBurn := -1 343 for headerIndex := range bitcoinHeaders { 344 if firstBitcoinBurnBlockHash == bitcoinHeaders[headerIndex].BlockHash() { 345 headerIndexOfFirstBurn = headerIndex 346 break 347 } 348 } 349 require.Greater(headerIndexOfFirstBurn, 0) 350 351 minBurnBlocks := uint32(2) 352 startHeaderIndex := 0 353 paramsCopy := GetTestParamsCopy( 354 bitcoinHeaders[startHeaderIndex], bitcoinHeaderHeights[startHeaderIndex], 355 params, minBurnBlocks, 356 ) 357 paramsCopy.BitcoinBurnAddress = BitcoinTestnetBurnAddress 358 chain.params = paramsCopy 359 // Reset the pool to give the mempool access to the new BitcoinManager object. 360 mempool.resetPool(NewDeSoMempool(chain, 0, /* rateLimitFeeRateNanosPerKB */ 361 0, /* minFeeRateNanosPerKB */ 362 "" /*blockCypherAPIKey*/, false, 363 "" /*dataDir*/, "")) 364 365 // Validating the first Bitcoin burn transaction via a UtxoView should 366 // fail because the block corresponding to it is not yet in the BitcoinManager. 367 burnTxn1 := bitcoinExchangeTxns[0] 368 burnTxn2 := bitcoinExchangeTxns[1] 369 370 // Applying the full transaction with its merkle proof should work. 371 { 372 mempoolTxs, err := mempool.processTransaction( 373 burnTxn1, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0 /*peerID*/, true /*verifySignatures*/) 374 require.NoError(err) 375 require.Equal(1, len(mempoolTxs)) 376 require.Equal(1, len(mempool.poolMap)) 377 mempoolTxRet := mempool.poolMap[*mempoolTxs[0].Hash] 378 require.Equal( 379 mempoolTxRet.Tx.TxnMeta.(*BitcoinExchangeMetadata), 380 burnTxn1.TxnMeta.(*BitcoinExchangeMetadata)) 381 } 382 383 // According to the mempool, the balance of the user whose public key created 384 // the Bitcoin burn transaction should now have some DeSo. 385 pkBytes1, _ := hex.DecodeString(BitcoinTestnetPub1) 386 pkBytes2, _ := hex.DecodeString(BitcoinTestnetPub2) 387 pkBytes3, _ := hex.DecodeString(BitcoinTestnetPub3) 388 { 389 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 390 require.NoError(err) 391 392 require.Equal(1, len(utxoEntries)) 393 assert.Equal(int64(2697810060), int64(utxoEntries[0].AmountNanos)) 394 } 395 396 // The mempool should be able to process a burn transaction directly. 397 { 398 mempoolTxsAdded, err := mempool.processTransaction( 399 burnTxn2, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 400 true /*verifySignatures*/) 401 require.NoError(err) 402 require.Equal(1, len(mempoolTxsAdded)) 403 require.Equal(2, len(mempool.poolMap)) 404 mempoolTxRet := mempool.poolMap[*mempoolTxsAdded[0].Hash] 405 require.Equal( 406 mempoolTxRet.Tx.TxnMeta.(*BitcoinExchangeMetadata), 407 burnTxn2.TxnMeta.(*BitcoinExchangeMetadata)) 408 } 409 410 // According to the mempool, the balances should have updated. 411 { 412 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 413 require.NoError(err) 414 415 require.Equal(1, len(utxoEntries)) 416 assert.Equal(int64(3372255472), int64(utxoEntries[0].AmountNanos)) 417 } 418 419 // If the mempool is not consulted, the balances should be zero. 420 { 421 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 422 require.NoError(err) 423 require.Equal(0, len(utxoEntries)) 424 } 425 426 // The UtxoView should accept all of the burn transactions now that their blocks 427 // have enough work built on them. 428 429 // Set the founder public key to something else for the remainder of the test. 430 // Give this public key a bit of money to play with. 431 //oldFounderRewardPubKey := FounderRewardPubKeyBase58Check 432 //FounderRewardPubKeyBase58Check = moneyPkString 433 //defer func() { 434 //FounderRewardPubKeyBase58Check = oldFounderRewardPubKey 435 //}() 436 437 // Make the moneyPkString the paramUpdater so they can update the exchange rate. 438 params.ParamUpdaterPublicKeys = make(map[PkMapKey]bool) 439 params.ParamUpdaterPublicKeys[MakePkMapKey(MustBase58CheckDecode(moneyPkString))] = true 440 paramsCopy.ParamUpdaterPublicKeys = params.ParamUpdaterPublicKeys 441 442 // Applying all the txns to the UtxoView should work. Include a rate update 443 // in the middle. 444 utxoOpsList := [][]*UtxoOperation{} 445 { 446 utxoView, err := NewUtxoView(db, paramsCopy, nil) 447 require.NoError(err) 448 449 // Add a placeholder where the rate update is going to be 450 fff := append([]*MsgDeSoTxn{}, bitcoinExchangeTxns[:rateUpdateIndex]...) 451 fff = append(fff, nil) 452 fff = append(fff, bitcoinExchangeTxns[rateUpdateIndex:]...) 453 bitcoinExchangeTxns = fff 454 455 for ii := range bitcoinExchangeTxns { 456 fmt.Println("Processing BitcoinExchange: ", ii) 457 458 // When we hit the rate update, populate the placeholder. 459 if ii == rateUpdateIndex { 460 newUSDCentsPerBitcoin := uint64(27000 * 100) 461 _, rateUpdateTxn, _, err := _updateUSDCentsPerBitcoinExchangeRate( 462 t, chain, db, params, 100, /*feeRateNanosPerKB*/ 463 moneyPkString, 464 moneyPrivString, 465 newUSDCentsPerBitcoin) 466 require.NoError(err) 467 468 bitcoinExchangeTxns[ii] = rateUpdateTxn 469 burnTxn := bitcoinExchangeTxns[ii] 470 burnTxnSize := getTxnSize(*burnTxn) 471 blockHeight := chain.blockTip().Height + 1 472 utxoOps, totalInput, totalOutput, fees, err := 473 utxoView.ConnectTransaction( 474 burnTxn, burnTxn.Hash(), burnTxnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 475 _, _, _ = totalInput, totalOutput, fees 476 require.NoError(err) 477 utxoOpsList = append(utxoOpsList, utxoOps) 478 continue 479 } 480 481 burnTxn := bitcoinExchangeTxns[ii] 482 burnTxnSize := getTxnSize(*burnTxn) 483 blockHeight := chain.blockTip().Height + 1 484 utxoOps, totalInput, totalOutput, fees, err := 485 utxoView.ConnectTransaction( 486 burnTxn, burnTxn.Hash(), burnTxnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 487 require.NoError(err) 488 489 require.Equal(2, len(utxoOps)) 490 //fmt.Println(int64(totalInput), ",") 491 assert.Equal(expectedDeSoNanosMinted[ii], int64(totalInput)) 492 assert.Equal(expectedDeSoNanosMinted[ii]*int64(paramsCopy.BitcoinExchangeFeeBasisPoints)/10000, int64(fees)) 493 assert.Equal(int64(fees), int64(totalInput-totalOutput)) 494 495 _, _, _ = ii, totalOutput, fees 496 utxoOpsList = append(utxoOpsList, utxoOps) 497 } 498 499 // Flushing the UtxoView should work. 500 require.NoError(utxoView.FlushToDb()) 501 } 502 503 // The balances according to the db after the flush should be correct. 504 { 505 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 506 require.NoError(err) 507 require.Equal(5, len(utxoEntries)) 508 totalBalance := uint64(0) 509 for _, utxoEntry := range utxoEntries { 510 totalBalance += utxoEntry.AmountNanos 511 } 512 // Note the 10bp fee. 513 assert.Equal(int64(47475508103), int64(totalBalance)) 514 } 515 { 516 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 517 require.NoError(err) 518 require.Equal(1, len(utxoEntries)) 519 // Note the 10bp fee. 520 assert.Equal(int64(8095277677), int64(utxoEntries[0].AmountNanos)) 521 } 522 { 523 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 524 require.NoError(err) 525 require.Equal(3, len(utxoEntries)) 526 totalBalance := uint64(0) 527 for _, utxoEntry := range utxoEntries { 528 totalBalance += utxoEntry.AmountNanos 529 } 530 // Note the 10bp fee. 531 assert.Equal(int64(22528672757), int64(totalBalance)) 532 } 533 534 // Spending from the outputs created by a burn should work. 535 desoPub1 := Base58CheckEncode(pkBytes1, false /*isPrivate*/, paramsCopy) 536 priv1, _ := _privStringToKeys(t, BitcoinTestnetPriv1) 537 desoPriv1 := Base58CheckEncode(priv1.Serialize(), true /*isPrivate*/, paramsCopy) 538 desoPub2 := Base58CheckEncode(pkBytes2, false /*isPrivate*/, paramsCopy) 539 priv2, _ := _privStringToKeys(t, BitcoinTestnetPriv2) 540 desoPriv2 := Base58CheckEncode(priv2.Serialize(), true /*isPrivate*/, paramsCopy) 541 desoPub3 := Base58CheckEncode(pkBytes3, false /*isPrivate*/, paramsCopy) 542 priv3, _ := _privStringToKeys(t, BitcoinTestnetPriv3) 543 desoPriv3 := Base58CheckEncode(priv3.Serialize(), true /*isPrivate*/, paramsCopy) 544 { 545 currentOps, currentTxn, _ := _doBasicTransferWithViewFlush( 546 t, chain, db, params, desoPub1, desoPub2, 547 desoPriv1, 100000*100000 /*amount to send*/, 11 /*feerate*/) 548 549 utxoOpsList = append(utxoOpsList, currentOps) 550 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentTxn) 551 } 552 { 553 currentOps, currentTxn, _ := _doBasicTransferWithViewFlush( 554 t, chain, db, params, desoPub3, desoPub1, 555 desoPriv3, 60000*100000 /*amount to send*/, 11 /*feerate*/) 556 557 utxoOpsList = append(utxoOpsList, currentOps) 558 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentTxn) 559 } 560 { 561 currentOps, currentTxn, _ := _doBasicTransferWithViewFlush( 562 t, chain, db, params, desoPub2, desoPub1, 563 desoPriv2, 60000*100000 /*amount to send*/, 11 /*feerate*/) 564 565 utxoOpsList = append(utxoOpsList, currentOps) 566 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentTxn) 567 } 568 569 // The balances according to the db after the spends above should be correct. 570 { 571 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 572 require.NoError(err) 573 totalBalance := uint64(0) 574 for _, utxoEntry := range utxoEntries { 575 totalBalance += utxoEntry.AmountNanos 576 } 577 assert.Equal(int64(49455017177), int64(totalBalance)) 578 } 579 { 580 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 581 require.NoError(err) 582 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 583 } 584 { 585 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 586 require.NoError(err) 587 totalBalance := uint64(0) 588 for _, utxoEntry := range utxoEntries { 589 totalBalance += utxoEntry.AmountNanos 590 } 591 assert.Equal(int64(16517205024), int64(totalBalance)) 592 } 593 594 { 595 // Rolling back all the transactions should work. 596 utxoView, err := NewUtxoView(db, paramsCopy, nil) 597 require.NoError(err) 598 for ii := range bitcoinExchangeTxns { 599 index := len(bitcoinExchangeTxns) - 1 - ii 600 burnTxn := bitcoinExchangeTxns[index] 601 blockHeight := chain.blockTip().Height + 1 602 err := utxoView.DisconnectTransaction(burnTxn, burnTxn.Hash(), utxoOpsList[index], blockHeight) 603 require.NoErrorf(err, "Transaction index: %v", index) 604 } 605 606 // Flushing the UtxoView back to the db after rolling back the 607 require.NoError(utxoView.FlushToDb()) 608 } 609 610 // The balances according to the db after rolling back and flushing everything 611 // should be zero. 612 { 613 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 614 require.NoError(err) 615 require.Equal(0, len(utxoEntries)) 616 } 617 { 618 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 619 require.NoError(err) 620 require.Equal(0, len(utxoEntries)) 621 } 622 { 623 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 624 require.NoError(err) 625 require.Equal(0, len(utxoEntries)) 626 } 627 628 // Re-applying all the transactions to the view and rolling back without 629 // flushing should be fine. 630 utxoOpsList = [][]*UtxoOperation{} 631 { 632 utxoView, err := NewUtxoView(db, paramsCopy, nil) 633 require.NoError(err) 634 for ii, burnTxn := range bitcoinExchangeTxns { 635 blockHeight := chain.blockTip().Height + 1 636 burnTxnSize := getTxnSize(*burnTxn) 637 utxoOps, totalInput, totalOutput, fees, err := 638 utxoView.ConnectTransaction(burnTxn, burnTxn.Hash(), burnTxnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 639 require.NoError(err) 640 641 if ii < len(expectedBitcoinBurnAmounts) { 642 if ii != rateUpdateIndex { 643 require.Equal(2, len(utxoOps)) 644 assert.Equal(int64(totalInput), expectedDeSoNanosMinted[ii]) 645 assert.Equal(int64(fees), expectedDeSoNanosMinted[ii]*int64(paramsCopy.BitcoinExchangeFeeBasisPoints)/10000) 646 assert.Equal(int64(fees), int64(totalInput-totalOutput)) 647 } 648 } 649 650 utxoOpsList = append(utxoOpsList, utxoOps) 651 } 652 653 for ii := range bitcoinExchangeTxns { 654 index := len(bitcoinExchangeTxns) - 1 - ii 655 burnTxn := bitcoinExchangeTxns[index] 656 blockHeight := chain.blockTip().Height + 1 657 err := utxoView.DisconnectTransaction(burnTxn, burnTxn.Hash(), utxoOpsList[index], blockHeight) 658 require.NoError(err) 659 } 660 661 // Flushing the view after applying and rolling back should work. 662 require.NoError(utxoView.FlushToDb()) 663 } 664 665 // The balances according to the db after applying and unapplying all the 666 // transactions to a view with a flush at the end should be zero. 667 { 668 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 669 require.NoError(err) 670 require.Equal(0, len(utxoEntries)) 671 } 672 { 673 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 674 require.NoError(err) 675 require.Equal(0, len(utxoEntries)) 676 } 677 { 678 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 679 require.NoError(err) 680 require.Equal(0, len(utxoEntries)) 681 } 682 683 // Running all the transactions through the mempool should work and result 684 // in all of them being added. 685 { 686 for _, burnTxn := range bitcoinExchangeTxns { 687 // We have to remove the transactions first. 688 mempool.inefficientRemoveTransaction(burnTxn) 689 } 690 for ii, burnTxn := range bitcoinExchangeTxns { 691 require.Equal(ii, len(mempool.poolMap)) 692 mempoolTxsAdded, err := mempool.processTransaction( 693 burnTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 694 true /*verifySignatures*/) 695 require.NoErrorf(err, "on index: %v", ii) 696 require.Equal(1, len(mempoolTxsAdded)) 697 } 698 } 699 700 // Test that the mempool can be backed up properly by dumping them and then 701 // reloading them. 702 _dumpAndLoadMempool(mempool) 703 704 // The balances according to the mempool after applying all the transactions 705 // should be correct. 706 { 707 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 708 require.NoError(err) 709 totalBalance := uint64(0) 710 for _, utxoEntry := range utxoEntries { 711 totalBalance += utxoEntry.AmountNanos 712 } 713 assert.Equal(int64(49455017177), int64(totalBalance)) 714 } 715 { 716 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 717 require.NoError(err) 718 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 719 } 720 { 721 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 722 require.NoError(err) 723 totalBalance := uint64(0) 724 for _, utxoEntry := range utxoEntries { 725 totalBalance += utxoEntry.AmountNanos 726 } 727 assert.Equal(int64(16517205024), int64(totalBalance)) 728 } 729 730 // Remove all the transactions from the mempool. 731 for _, burnTxn := range bitcoinExchangeTxns { 732 mempool.inefficientRemoveTransaction(burnTxn) 733 } 734 735 // Check that removals hit the database properly by calling a dump and 736 // then reloading the db state into the view. 737 _dumpAndLoadMempool(mempool) 738 739 // The balances should be zero after removing transactions from the mempool. 740 { 741 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 742 require.NoError(err) 743 require.Equal(0, len(utxoEntries)) 744 } 745 { 746 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 747 require.NoError(err) 748 require.Equal(0, len(utxoEntries)) 749 } 750 { 751 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 752 require.NoError(err) 753 require.Equal(0, len(utxoEntries)) 754 } 755 756 // Re-add all of the transactions to the mempool so we can mine them into a block. 757 { 758 for _, burnTxn := range bitcoinExchangeTxns { 759 mempoolTxsAdded, err := mempool.processTransaction( 760 burnTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 761 true /*verifySignatures*/) 762 require.NoError(err) 763 require.Equal(1, len(mempoolTxsAdded)) 764 //require.Equal(0, len(mempool.immatureBitcoinTxns)) 765 } 766 } 767 768 // Check the db one more time after adding back all the txns. 769 _dumpAndLoadMempool(mempool) 770 771 // Mine a block with all the mempool transactions. 772 miner.params = paramsCopy 773 miner.BlockProducer.params = paramsCopy 774 // 775 // All the txns should be in the mempool already but only some of them have enough 776 // burn work to satisfy the miner. Note we need to mine two blocks since the first 777 // one just makes the DeSo chain time-current. 778 finalBlock1, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 779 require.NoError(err) 780 _ = finalBlock1 781 // Check the mempool dumps and loads from the db properly each time 782 _dumpAndLoadMempool(mempool) 783 784 finalBlock2, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 785 require.NoError(err) 786 _dumpAndLoadMempool(mempool) 787 788 finalBlock3, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 789 require.NoError(err) 790 _dumpAndLoadMempool(mempool) 791 792 finalBlock4, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 793 require.NoError(err) 794 _dumpAndLoadMempool(mempool) 795 796 // Add one for the block reward. 797 assert.Equal(len(finalBlock1.Txns), 1) 798 // The first block should only have some of the Bitcoin txns since 799 // the MinerBitcoinBurnWorkBlocks is higher than the regular burn work. 800 assert.Equal(len(finalBlock2.Txns), 14) 801 assert.Equal(len(finalBlock3.Txns), 1) 802 require.Equal(len(finalBlock4.Txns), 1) 803 804 // The balances after mining the block should line up. 805 { 806 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 807 require.NoError(err) 808 totalBalance := uint64(0) 809 for _, utxoEntry := range utxoEntries { 810 totalBalance += utxoEntry.AmountNanos 811 } 812 assert.Equal(int64(49455017177), int64(totalBalance)) 813 } 814 { 815 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 816 require.NoError(err) 817 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 818 } 819 { 820 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 821 require.NoError(err) 822 totalBalance := uint64(0) 823 for _, utxoEntry := range utxoEntries { 824 totalBalance += utxoEntry.AmountNanos 825 } 826 assert.Equal(int64(16517205024), int64(totalBalance)) 827 } 828 829 // Roll back the blocks and make sure we don't hit any errors. 830 { 831 utxoView, err := NewUtxoView(db, paramsCopy, nil) 832 require.NoError(err) 833 834 { 835 // Fetch the utxo operations for the block we're detaching. We need these 836 // in order to be able to detach the block. 837 hash, err := finalBlock4.Header.Hash() 838 require.NoError(err) 839 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 840 require.NoError(err) 841 842 // Compute the hashes for all the transactions. 843 txHashes, err := ComputeTransactionHashes(finalBlock4.Txns) 844 require.NoError(err) 845 require.NoError(utxoView.DisconnectBlock(finalBlock4, txHashes, utxoOps)) 846 } 847 { 848 // Fetch the utxo operations for the block we're detaching. We need these 849 // in order to be able to detach the block. 850 hash, err := finalBlock3.Header.Hash() 851 require.NoError(err) 852 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 853 require.NoError(err) 854 855 // Compute the hashes for all the transactions. 856 txHashes, err := ComputeTransactionHashes(finalBlock3.Txns) 857 require.NoError(err) 858 require.NoError(utxoView.DisconnectBlock(finalBlock3, txHashes, utxoOps)) 859 } 860 { 861 // Fetch the utxo operations for the block we're detaching. We need these 862 // in order to be able to detach the block. 863 hash, err := finalBlock2.Header.Hash() 864 require.NoError(err) 865 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 866 require.NoError(err) 867 868 // Compute the hashes for all the transactions. 869 txHashes, err := ComputeTransactionHashes(finalBlock2.Txns) 870 require.NoError(err) 871 require.NoError(utxoView.DisconnectBlock(finalBlock2, txHashes, utxoOps)) 872 } 873 { 874 // Fetch the utxo operations for the block we're detaching. We need these 875 // in order to be able to detach the block. 876 hash, err := finalBlock1.Header.Hash() 877 require.NoError(err) 878 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 879 require.NoError(err) 880 881 // Compute the hashes for all the transactions. 882 txHashes, err := ComputeTransactionHashes(finalBlock1.Txns) 883 require.NoError(err) 884 require.NoError(utxoView.DisconnectBlock(finalBlock1, txHashes, utxoOps)) 885 } 886 887 // Flushing the view after applying and rolling back should work. 888 require.NoError(utxoView.FlushToDb()) 889 } 890 891 // The balances according to the db after applying and unapplying all the 892 // transactions to a view with a flush at the end should be zero. 893 { 894 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 895 require.NoError(err) 896 require.Equal(0, len(utxoEntries)) 897 } 898 { 899 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 900 require.NoError(err) 901 require.Equal(0, len(utxoEntries)) 902 } 903 { 904 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 905 require.NoError(err) 906 require.Equal(0, len(utxoEntries)) 907 } 908 909 _, _, _, _, _, _ = db, mempool, miner, bitcoinBlocks, bitcoinHeaders, bitcoinHeaderHeights 910 } 911 912 func TestBitcoinExchangeGlobalParams(t *testing.T) { 913 assert := assert.New(t) 914 require := require.New(t) 915 _ = assert 916 _ = require 917 918 // Don't refresh the universal view for this test, since it causes a race condition 919 // to trigger. 920 // TODO: Lower this value to .1 and fix this race condition. 921 ReadOnlyUtxoViewRegenerationIntervalSeconds = 100 922 923 oldInitialUSDCentsPerBitcoinExchangeRate := InitialUSDCentsPerBitcoinExchangeRate 924 InitialUSDCentsPerBitcoinExchangeRate = uint64(1350000) 925 defer func() { 926 InitialUSDCentsPerBitcoinExchangeRate = oldInitialUSDCentsPerBitcoinExchangeRate 927 }() 928 929 paramsTmp := DeSoTestnetParams 930 paramsTmp.DeSoNanosPurchasedAtGenesis = 0 931 chain, params, db := NewLowDifficultyBlockchainWithParams(¶msTmp) 932 mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/) 933 934 // Read in the test Bitcoin blocks and headers. 935 bitcoinBlocks, bitcoinHeaders, bitcoinHeaderHeights := _readBitcoinExchangeTestData(t) 936 937 // Extract BitcoinExchange transactions from the test Bitcoin blocks. 938 bitcoinExchangeTxns := []*MsgDeSoTxn{} 939 for _, block := range bitcoinBlocks { 940 currentBurnTxns, err := 941 ExtractBitcoinExchangeTransactionsFromBitcoinBlock( 942 block, BitcoinTestnetBurnAddress, params) 943 require.NoError(err) 944 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentBurnTxns...) 945 } 946 947 // Verify that Bitcoin burn transactions are properly extracted from Bitcoin blocks 948 // and the their burn amounts are computed correctly. 949 require.Equal(9, len(bitcoinExchangeTxns)) 950 expectedBitcoinBurnAmounts := []int64{ 951 10000, 952 12500, 953 41000, 954 20000, 955 15000, 956 50000, 957 15000, 958 20482, 959 2490, 960 } 961 rateUpdateIndex := 4 962 expectedDeSoNanosMinted := []int64{ 963 2700510570, 964 3375631103, 965 11072014581, 966 5400951887, 967 // We double the exchange rate at this point. Include a zero 968 // here to account for this. 969 0, 970 8103578296, 971 27011598923, 972 8103381058, 973 11064823217, 974 1345146534, 975 } 976 blockIndexesForTransactions := []int{1, 1, 1, 1, 1, 1, 1, 3, 3} 977 for ii, bitcoinExchangeTxn := range bitcoinExchangeTxns { 978 txnMeta := bitcoinExchangeTxn.TxnMeta.(*BitcoinExchangeMetadata) 979 burnTxn := txnMeta.BitcoinTransaction 980 burnOutput, err := _computeBitcoinBurnOutput( 981 burnTxn, BitcoinTestnetBurnAddress, params.BitcoinBtcdParams) 982 require.NoError(err) 983 assert.Equalf(expectedBitcoinBurnAmounts[ii], burnOutput, 984 "Bitcoin burn amount for burn txn %d doesn't line up with "+ 985 "what is expected", ii) 986 987 // Sanity-check that the Bitcoin block hashes line up. 988 blockIndex := blockIndexesForTransactions[ii] 989 blockForTxn := bitcoinBlocks[blockIndex] 990 { 991 hash1 := (BlockHash)(blockForTxn.BlockHash()) 992 hash2 := *txnMeta.BitcoinBlockHash 993 require.Equalf( 994 hash1, hash2, 995 "Bitcoin block hash for txn does not line up with block hash: %v %v %d", &hash1, &hash2, ii) 996 } 997 998 // Sanity-check that the Merkle root lines up with what's in the block. 999 { 1000 hash1 := (BlockHash)(blockForTxn.Header.MerkleRoot) 1001 hash2 := *txnMeta.BitcoinMerkleRoot 1002 require.Equalf( 1003 hash1, hash2, 1004 "Bitcoin merkle root for txn does not line up with block hash: %v %v %d", &hash1, &hash2, ii) 1005 } 1006 1007 // Verify that the merkle proof checks out. 1008 { 1009 txHash := ((BlockHash)(txnMeta.BitcoinTransaction.TxHash())) 1010 merkleProofIsValid := merkletree.VerifyProof( 1011 txHash[:], txnMeta.BitcoinMerkleProof, txnMeta.BitcoinMerkleRoot[:]) 1012 require.Truef( 1013 merkleProofIsValid, "Problem verifying merkle proof for burn txn %d", ii) 1014 } 1015 1016 // Verify that using the wrong Merkle root doesn't work. 1017 { 1018 badBlock := bitcoinBlocks[blockIndex-1] 1019 badMerkleRoot := badBlock.Header.MerkleRoot[:] 1020 txHash := ((BlockHash)(txnMeta.BitcoinTransaction.TxHash())) 1021 merkleProofIsValid := merkletree.VerifyProof( 1022 txHash[:], txnMeta.BitcoinMerkleProof, badMerkleRoot) 1023 require.Falsef( 1024 merkleProofIsValid, "Bad Merkle root was actually verified for burn txn %d", ii) 1025 } 1026 1027 // Verify that serializing and deserializing work for this transaction. 1028 bb, err := bitcoinExchangeTxn.ToBytes(false /*preSignature*/) 1029 require.NoError(err) 1030 parsedBitcoinExchangeTxn := &MsgDeSoTxn{} 1031 parsedBitcoinExchangeTxn.FromBytes(bb) 1032 require.Equal(bitcoinExchangeTxn, parsedBitcoinExchangeTxn) 1033 } 1034 1035 // Find the header in our header list corresponding to the first test block, 1036 // which contains the first Bitcoin 1037 firstBitcoinBurnBlock := bitcoinBlocks[1] 1038 firstBitcoinBurnBlockHash := firstBitcoinBurnBlock.BlockHash() 1039 headerIndexOfFirstBurn := -1 1040 for headerIndex := range bitcoinHeaders { 1041 if firstBitcoinBurnBlockHash == bitcoinHeaders[headerIndex].BlockHash() { 1042 headerIndexOfFirstBurn = headerIndex 1043 break 1044 } 1045 } 1046 require.Greater(headerIndexOfFirstBurn, 0) 1047 1048 // Create a Bitcoinmanager that is current whose tip corresponds to the block 1049 // just before the block containing the first Bitcoin burn transaction. 1050 minBurnBlocks := uint32(2) 1051 startHeaderIndex := 0 1052 paramsCopy := GetTestParamsCopy(bitcoinHeaders[startHeaderIndex], 1053 bitcoinHeaderHeights[startHeaderIndex], params, minBurnBlocks) 1054 1055 // Update some of the params to make them reflect what we've hacked into 1056 // the bitcoinManager. 1057 paramsCopy.BitcoinBurnAddress = BitcoinTestnetBurnAddress 1058 chain.params = paramsCopy 1059 // Reset the pool to give the mempool access to the new BitcoinManager object. 1060 mempool.resetPool(NewDeSoMempool(chain, 0, /* rateLimitFeeRateNanosPerKB */ 1061 0, /* minFeeRateNanosPerKB */ 1062 "" /*blockCypherAPIKey*/, false, 1063 "" /*dataDir*/, "")) 1064 1065 //// Validating the first Bitcoin burn transaction via a UtxoView should 1066 //// fail because the block corresponding to it is not yet in the BitcoinManager. 1067 burnTxn1 := bitcoinExchangeTxns[0] 1068 burnTxn1Size := getTxnSize(*burnTxn1) 1069 txHash1 := burnTxn1.Hash() 1070 burnTxn2 := bitcoinExchangeTxns[1] 1071 1072 // The user we just applied this transaction for should have a balance now. 1073 pkBytes1, _ := hex.DecodeString(BitcoinTestnetPub1) 1074 1075 // Applying the full transaction with its merkle proof to the mempool should 1076 // replace the existing "unmined" version that we added previously. 1077 { 1078 mempoolTxs, err := mempool.processTransaction( 1079 burnTxn1, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0 /*peerID*/, true /*verifySignatures*/) 1080 require.NoError(err) 1081 require.Equal(1, len(mempoolTxs)) 1082 require.Equal(1, len(mempool.poolMap)) 1083 mempoolTxRet := mempool.poolMap[*mempoolTxs[0].Hash] 1084 require.Equal( 1085 mempoolTxRet.Tx.TxnMeta.(*BitcoinExchangeMetadata), 1086 burnTxn1.TxnMeta.(*BitcoinExchangeMetadata)) 1087 } 1088 1089 // Applying the full txns a second time should fail. 1090 { 1091 mempoolTxs, err := mempool.processTransaction( 1092 burnTxn1, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0 /*peerID*/, true /*verifySignatures*/) 1093 require.Error(err) 1094 require.Equal(0, len(mempoolTxs)) 1095 require.Equal(1, len(mempool.poolMap)) 1096 mempoolTxRet := mempool.poolMap[*burnTxn1.Hash()] 1097 require.Equal( 1098 mempoolTxRet.Tx.TxnMeta.(*BitcoinExchangeMetadata), 1099 burnTxn1.TxnMeta.(*BitcoinExchangeMetadata)) 1100 } 1101 1102 // According to the mempool, the balance of the user whose public key created 1103 // the Bitcoin burn transaction should now have some DeSo. 1104 pkBytes2, _ := hex.DecodeString(BitcoinTestnetPub2) 1105 pkBytes3, _ := hex.DecodeString(BitcoinTestnetPub3) 1106 { 1107 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 1108 require.NoError(err) 1109 1110 require.Equal(1, len(utxoEntries)) 1111 assert.Equal(int64(2697810060), int64(utxoEntries[0].AmountNanos)) 1112 } 1113 1114 // The mempool should be able to process a burn transaction directly. 1115 { 1116 mempoolTxsAdded, err := mempool.processTransaction( 1117 burnTxn2, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 1118 true /*verifySignatures*/) 1119 require.NoError(err) 1120 require.Equal(1, len(mempoolTxsAdded)) 1121 require.Equal(2, len(mempool.poolMap)) 1122 mempoolTxRet := mempool.poolMap[*mempoolTxsAdded[0].Hash] 1123 require.Equal( 1124 mempoolTxRet.Tx.TxnMeta.(*BitcoinExchangeMetadata), 1125 burnTxn2.TxnMeta.(*BitcoinExchangeMetadata)) 1126 } 1127 1128 // According to the mempool, the balances should have updated. 1129 { 1130 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 1131 require.NoError(err) 1132 1133 require.Equal(1, len(utxoEntries)) 1134 assert.Equal(int64(3372255472), int64(utxoEntries[0].AmountNanos)) 1135 } 1136 1137 // If the mempool is not consulted, the balances should be zero. 1138 { 1139 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 1140 require.NoError(err) 1141 require.Equal(0, len(utxoEntries)) 1142 } 1143 1144 // Verify that adding the transaction to the UtxoView fails because there is 1145 // not enough work on the burn block yet. 1146 { 1147 utxoView, _ := NewUtxoView(db, paramsCopy, nil) 1148 blockHeight := chain.blockTip().Height + 1 1149 utxoView.ConnectTransaction(burnTxn1, txHash1, burnTxn1Size, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 1150 } 1151 1152 { 1153 utxoView, _ := NewUtxoView(db, paramsCopy, nil) 1154 blockHeight := chain.blockTip().Height + 1 1155 utxoView.ConnectTransaction(burnTxn1, txHash1, burnTxn1Size, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 1156 } 1157 1158 // The transaction should pass now 1159 { 1160 utxoView, _ := NewUtxoView(db, paramsCopy, nil) 1161 blockHeight := chain.blockTip().Height + 1 1162 _, _, _, _, err := 1163 utxoView.ConnectTransaction(burnTxn1, txHash1, burnTxn1Size, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 1164 require.NoError(err) 1165 } 1166 1167 // Make the moneyPkString the paramUpdater so they can update the exchange rate. 1168 params.ParamUpdaterPublicKeys = make(map[PkMapKey]bool) 1169 params.ParamUpdaterPublicKeys[MakePkMapKey(MustBase58CheckDecode(moneyPkString))] = true 1170 paramsCopy.ParamUpdaterPublicKeys = params.ParamUpdaterPublicKeys 1171 1172 // Applying all the txns to the UtxoView should work. Include a rate update 1173 // in the middle. 1174 utxoOpsList := [][]*UtxoOperation{} 1175 { 1176 utxoView, err := NewUtxoView(db, paramsCopy, nil) 1177 require.NoError(err) 1178 1179 // Add a placeholder where the rate update is going to be 1180 fff := append([]*MsgDeSoTxn{}, bitcoinExchangeTxns[:rateUpdateIndex]...) 1181 fff = append(fff, nil) 1182 fff = append(fff, bitcoinExchangeTxns[rateUpdateIndex:]...) 1183 bitcoinExchangeTxns = fff 1184 1185 for ii := range bitcoinExchangeTxns { 1186 fmt.Println("Processing BitcoinExchange: ", ii) 1187 1188 // When we hit the rate update, populate the placeholder. 1189 if ii == rateUpdateIndex { 1190 newUSDCentsPerBitcoin := int64(27000 * 100) 1191 _, rateUpdateTxn, _, err := _updateGlobalParamsEntry(t, chain, db, params, 10, 1192 moneyPkString, moneyPrivString, newUSDCentsPerBitcoin, 0, 0, 0, -1, false) 1193 1194 require.NoError(err) 1195 1196 bitcoinExchangeTxns[ii] = rateUpdateTxn 1197 burnTxn := bitcoinExchangeTxns[ii] 1198 burnTxnSize := getTxnSize(*burnTxn) 1199 blockHeight := chain.blockTip().Height + 1 1200 utxoOps, totalInput, totalOutput, fees, err := 1201 utxoView.ConnectTransaction( 1202 burnTxn, burnTxn.Hash(), burnTxnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 1203 _, _, _ = totalInput, totalOutput, fees 1204 require.NoError(err) 1205 utxoOpsList = append(utxoOpsList, utxoOps) 1206 continue 1207 } 1208 1209 burnTxn := bitcoinExchangeTxns[ii] 1210 burnTxnSize := getTxnSize(*burnTxn) 1211 blockHeight := chain.blockTip().Height + 1 1212 utxoOps, totalInput, totalOutput, fees, err := 1213 utxoView.ConnectTransaction( 1214 burnTxn, burnTxn.Hash(), burnTxnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 1215 require.NoError(err) 1216 1217 require.Equal(2, len(utxoOps)) 1218 //fmt.Println(int64(totalInput), ",") 1219 assert.Equal(expectedDeSoNanosMinted[ii], int64(totalInput)) 1220 assert.Equal(expectedDeSoNanosMinted[ii]*int64(paramsCopy.BitcoinExchangeFeeBasisPoints)/10000, int64(fees)) 1221 assert.Equal(int64(fees), int64(totalInput-totalOutput)) 1222 1223 _, _, _ = ii, totalOutput, fees 1224 utxoOpsList = append(utxoOpsList, utxoOps) 1225 } 1226 1227 // Flushing the UtxoView should work. 1228 require.NoError(utxoView.FlushToDb()) 1229 } 1230 1231 // The balances according to the db after the flush should be correct. 1232 { 1233 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 1234 require.NoError(err) 1235 require.Equal(5, len(utxoEntries)) 1236 totalBalance := uint64(0) 1237 for _, utxoEntry := range utxoEntries { 1238 totalBalance += utxoEntry.AmountNanos 1239 } 1240 // Note the 10bp fee. 1241 assert.Equal(int64(47475508103), int64(totalBalance)) 1242 } 1243 { 1244 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 1245 require.NoError(err) 1246 require.Equal(1, len(utxoEntries)) 1247 // Note the 10bp fee. 1248 assert.Equal(int64(8095277677), int64(utxoEntries[0].AmountNanos)) 1249 } 1250 { 1251 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 1252 require.NoError(err) 1253 require.Equal(3, len(utxoEntries)) 1254 totalBalance := uint64(0) 1255 for _, utxoEntry := range utxoEntries { 1256 totalBalance += utxoEntry.AmountNanos 1257 } 1258 // Note the 10bp fee. 1259 assert.Equal(int64(22528672757), int64(totalBalance)) 1260 } 1261 1262 // Spending from the outputs created by a burn should work. 1263 desoPub1 := Base58CheckEncode(pkBytes1, false /*isPrivate*/, paramsCopy) 1264 priv1, _ := _privStringToKeys(t, BitcoinTestnetPriv1) 1265 desoPriv1 := Base58CheckEncode(priv1.Serialize(), true /*isPrivate*/, paramsCopy) 1266 desoPub2 := Base58CheckEncode(pkBytes2, false /*isPrivate*/, paramsCopy) 1267 priv2, _ := _privStringToKeys(t, BitcoinTestnetPriv2) 1268 desoPriv2 := Base58CheckEncode(priv2.Serialize(), true /*isPrivate*/, paramsCopy) 1269 desoPub3 := Base58CheckEncode(pkBytes3, false /*isPrivate*/, paramsCopy) 1270 priv3, _ := _privStringToKeys(t, BitcoinTestnetPriv3) 1271 desoPriv3 := Base58CheckEncode(priv3.Serialize(), true /*isPrivate*/, paramsCopy) 1272 { 1273 currentOps, currentTxn, _ := _doBasicTransferWithViewFlush( 1274 t, chain, db, params, desoPub1, desoPub2, 1275 desoPriv1, 100000*100000 /*amount to send*/, 11 /*feerate*/) 1276 1277 utxoOpsList = append(utxoOpsList, currentOps) 1278 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentTxn) 1279 } 1280 { 1281 currentOps, currentTxn, _ := _doBasicTransferWithViewFlush( 1282 t, chain, db, params, desoPub3, desoPub1, 1283 desoPriv3, 60000*100000 /*amount to send*/, 11 /*feerate*/) 1284 1285 utxoOpsList = append(utxoOpsList, currentOps) 1286 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentTxn) 1287 } 1288 { 1289 currentOps, currentTxn, _ := _doBasicTransferWithViewFlush( 1290 t, chain, db, params, desoPub2, desoPub1, 1291 desoPriv2, 60000*100000 /*amount to send*/, 11 /*feerate*/) 1292 1293 utxoOpsList = append(utxoOpsList, currentOps) 1294 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentTxn) 1295 } 1296 1297 // The balances according to the db after the spends above should be correct. 1298 { 1299 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 1300 require.NoError(err) 1301 totalBalance := uint64(0) 1302 for _, utxoEntry := range utxoEntries { 1303 totalBalance += utxoEntry.AmountNanos 1304 } 1305 assert.Equal(int64(49455017177), int64(totalBalance)) 1306 } 1307 { 1308 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 1309 require.NoError(err) 1310 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 1311 } 1312 { 1313 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 1314 require.NoError(err) 1315 totalBalance := uint64(0) 1316 for _, utxoEntry := range utxoEntries { 1317 totalBalance += utxoEntry.AmountNanos 1318 } 1319 assert.Equal(int64(16517205024), int64(totalBalance)) 1320 } 1321 1322 { 1323 // Rolling back all the transactions should work. 1324 utxoView, err := NewUtxoView(db, paramsCopy, nil) 1325 require.NoError(err) 1326 for ii := range bitcoinExchangeTxns { 1327 index := len(bitcoinExchangeTxns) - 1 - ii 1328 burnTxn := bitcoinExchangeTxns[index] 1329 blockHeight := chain.blockTip().Height + 1 1330 err := utxoView.DisconnectTransaction(burnTxn, burnTxn.Hash(), utxoOpsList[index], blockHeight) 1331 require.NoErrorf(err, "Transaction index: %v", index) 1332 } 1333 1334 // Flushing the UtxoView back to the db after rolling back the 1335 require.NoError(utxoView.FlushToDb()) 1336 } 1337 1338 // The balances according to the db after rolling back and flushing everything 1339 // should be zero. 1340 { 1341 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 1342 require.NoError(err) 1343 require.Equal(0, len(utxoEntries)) 1344 } 1345 { 1346 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 1347 require.NoError(err) 1348 require.Equal(0, len(utxoEntries)) 1349 } 1350 { 1351 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 1352 require.NoError(err) 1353 require.Equal(0, len(utxoEntries)) 1354 } 1355 1356 // Re-applying all the transactions to the view and rolling back without 1357 // flushing should be fine. 1358 utxoOpsList = [][]*UtxoOperation{} 1359 { 1360 utxoView, err := NewUtxoView(db, paramsCopy, nil) 1361 require.NoError(err) 1362 for ii, burnTxn := range bitcoinExchangeTxns { 1363 blockHeight := chain.blockTip().Height + 1 1364 burnTxnSize := getTxnSize(*burnTxn) 1365 utxoOps, totalInput, totalOutput, fees, err := 1366 utxoView.ConnectTransaction(burnTxn, burnTxn.Hash(), burnTxnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 1367 require.NoError(err) 1368 1369 if ii < len(expectedBitcoinBurnAmounts) { 1370 if ii != rateUpdateIndex { 1371 require.Equal(2, len(utxoOps)) 1372 assert.Equal(int64(totalInput), expectedDeSoNanosMinted[ii]) 1373 assert.Equal(int64(fees), expectedDeSoNanosMinted[ii]*int64(paramsCopy.BitcoinExchangeFeeBasisPoints)/10000) 1374 assert.Equal(int64(fees), int64(totalInput-totalOutput)) 1375 } 1376 } 1377 1378 utxoOpsList = append(utxoOpsList, utxoOps) 1379 } 1380 1381 for ii := range bitcoinExchangeTxns { 1382 index := len(bitcoinExchangeTxns) - 1 - ii 1383 burnTxn := bitcoinExchangeTxns[index] 1384 blockHeight := chain.blockTip().Height + 1 1385 err := utxoView.DisconnectTransaction(burnTxn, burnTxn.Hash(), utxoOpsList[index], blockHeight) 1386 require.NoError(err) 1387 } 1388 1389 // Flushing the view after applying and rolling back should work. 1390 require.NoError(utxoView.FlushToDb()) 1391 } 1392 1393 // The balances according to the db after applying and unapplying all the 1394 // transactions to a view with a flush at the end should be zero. 1395 { 1396 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 1397 require.NoError(err) 1398 require.Equal(0, len(utxoEntries)) 1399 } 1400 { 1401 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 1402 require.NoError(err) 1403 require.Equal(0, len(utxoEntries)) 1404 } 1405 { 1406 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 1407 require.NoError(err) 1408 require.Equal(0, len(utxoEntries)) 1409 } 1410 1411 // Running all the transactions through the mempool should work and result 1412 // in all of them being added. 1413 { 1414 for _, burnTxn := range bitcoinExchangeTxns { 1415 // We have to remove the transactions first. 1416 mempool.inefficientRemoveTransaction(burnTxn) 1417 } 1418 for ii, burnTxn := range bitcoinExchangeTxns { 1419 require.Equal(ii, len(mempool.poolMap)) 1420 mempoolTxsAdded, err := mempool.processTransaction( 1421 burnTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 1422 true /*verifySignatures*/) 1423 require.NoErrorf(err, "on index: %v", ii) 1424 require.Equal(1, len(mempoolTxsAdded)) 1425 } 1426 } 1427 1428 // Test that the mempool can be backed up properly by dumping them and then 1429 // reloading them. 1430 _dumpAndLoadMempool(mempool) 1431 1432 // The balances according to the mempool after applying all the transactions 1433 // should be correct. 1434 { 1435 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 1436 require.NoError(err) 1437 totalBalance := uint64(0) 1438 for _, utxoEntry := range utxoEntries { 1439 totalBalance += utxoEntry.AmountNanos 1440 } 1441 assert.Equal(int64(49455017177), int64(totalBalance)) 1442 } 1443 { 1444 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 1445 require.NoError(err) 1446 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 1447 } 1448 { 1449 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 1450 require.NoError(err) 1451 totalBalance := uint64(0) 1452 for _, utxoEntry := range utxoEntries { 1453 totalBalance += utxoEntry.AmountNanos 1454 } 1455 assert.Equal(int64(16517205024), int64(totalBalance)) 1456 } 1457 1458 // Remove all the transactions from the mempool. 1459 for _, burnTxn := range bitcoinExchangeTxns { 1460 mempool.inefficientRemoveTransaction(burnTxn) 1461 } 1462 1463 // Check that removals hit the database properly by calling a dump and 1464 // then reloading the db state into the view. 1465 _dumpAndLoadMempool(mempool) 1466 1467 // The balances should be zero after removing transactions from the mempool. 1468 { 1469 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 1470 require.NoError(err) 1471 require.Equal(0, len(utxoEntries)) 1472 } 1473 { 1474 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 1475 require.NoError(err) 1476 require.Equal(0, len(utxoEntries)) 1477 } 1478 { 1479 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 1480 require.NoError(err) 1481 require.Equal(0, len(utxoEntries)) 1482 } 1483 1484 // Re-add all of the transactions to the mempool so we can mine them into a block. 1485 { 1486 for _, burnTxn := range bitcoinExchangeTxns { 1487 mempoolTxsAdded, err := mempool.processTransaction( 1488 burnTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 1489 true /*verifySignatures*/) 1490 require.NoError(err) 1491 require.Equal(1, len(mempoolTxsAdded)) 1492 //require.Equal(0, len(mempool.immatureBitcoinTxns)) 1493 } 1494 } 1495 1496 // Check the db one more time after adding back all the txns. 1497 _dumpAndLoadMempool(mempool) 1498 1499 miner.params = paramsCopy 1500 miner.BlockProducer.params = paramsCopy 1501 1502 // All the txns should be in the mempool already but only some of them have enough 1503 // burn work to satisfy the miner. Note we need to mine two blocks since the first 1504 // one just makes the DeSo chain time-current. 1505 finalBlock1, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 1506 require.NoError(err) 1507 _ = finalBlock1 1508 // Check the mempool dumps and loads from the db properly each time 1509 _dumpAndLoadMempool(mempool) 1510 1511 finalBlock2, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 1512 require.NoError(err) 1513 _dumpAndLoadMempool(mempool) 1514 1515 finalBlock3, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 1516 require.NoError(err) 1517 _dumpAndLoadMempool(mempool) 1518 1519 finalBlock4, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 1520 require.NoError(err) 1521 _dumpAndLoadMempool(mempool) 1522 1523 // Add one for the block reward. 1524 assert.Equal(len(finalBlock1.Txns), 1) 1525 // The first block should only have some of the Bitcoin txns since 1526 // the MinerBitcoinBurnWorkBlocks is higher than the regular burn work. 1527 assert.Equal(len(finalBlock2.Txns), 14) 1528 assert.Equal(len(finalBlock3.Txns), 1) 1529 require.Equal(len(finalBlock4.Txns), 1) 1530 1531 // The balances after mining the block should line up. 1532 { 1533 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 1534 require.NoError(err) 1535 totalBalance := uint64(0) 1536 for _, utxoEntry := range utxoEntries { 1537 totalBalance += utxoEntry.AmountNanos 1538 } 1539 assert.Equal(int64(49455017177), int64(totalBalance)) 1540 } 1541 { 1542 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 1543 require.NoError(err) 1544 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 1545 } 1546 { 1547 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 1548 require.NoError(err) 1549 totalBalance := uint64(0) 1550 for _, utxoEntry := range utxoEntries { 1551 totalBalance += utxoEntry.AmountNanos 1552 } 1553 assert.Equal(int64(16517205024), int64(totalBalance)) 1554 } 1555 1556 // Roll back the blocks and make sure we don't hit any errors. 1557 { 1558 utxoView, err := NewUtxoView(db, paramsCopy, nil) 1559 require.NoError(err) 1560 1561 { 1562 // Fetch the utxo operations for the block we're detaching. We need these 1563 // in order to be able to detach the block. 1564 hash, err := finalBlock4.Header.Hash() 1565 require.NoError(err) 1566 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 1567 require.NoError(err) 1568 1569 // Compute the hashes for all the transactions. 1570 txHashes, err := ComputeTransactionHashes(finalBlock4.Txns) 1571 require.NoError(err) 1572 require.NoError(utxoView.DisconnectBlock(finalBlock4, txHashes, utxoOps)) 1573 } 1574 { 1575 // Fetch the utxo operations for the block we're detaching. We need these 1576 // in order to be able to detach the block. 1577 hash, err := finalBlock3.Header.Hash() 1578 require.NoError(err) 1579 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 1580 require.NoError(err) 1581 1582 // Compute the hashes for all the transactions. 1583 txHashes, err := ComputeTransactionHashes(finalBlock3.Txns) 1584 require.NoError(err) 1585 require.NoError(utxoView.DisconnectBlock(finalBlock3, txHashes, utxoOps)) 1586 } 1587 { 1588 // Fetch the utxo operations for the block we're detaching. We need these 1589 // in order to be able to detach the block. 1590 hash, err := finalBlock2.Header.Hash() 1591 require.NoError(err) 1592 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 1593 require.NoError(err) 1594 1595 // Compute the hashes for all the transactions. 1596 txHashes, err := ComputeTransactionHashes(finalBlock2.Txns) 1597 require.NoError(err) 1598 require.NoError(utxoView.DisconnectBlock(finalBlock2, txHashes, utxoOps)) 1599 } 1600 { 1601 // Fetch the utxo operations for the block we're detaching. We need these 1602 // in order to be able to detach the block. 1603 hash, err := finalBlock1.Header.Hash() 1604 require.NoError(err) 1605 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 1606 require.NoError(err) 1607 1608 // Compute the hashes for all the transactions. 1609 txHashes, err := ComputeTransactionHashes(finalBlock1.Txns) 1610 require.NoError(err) 1611 require.NoError(utxoView.DisconnectBlock(finalBlock1, txHashes, utxoOps)) 1612 } 1613 1614 // Flushing the view after applying and rolling back should work. 1615 require.NoError(utxoView.FlushToDb()) 1616 } 1617 1618 // The balances according to the db after applying and unapplying all the 1619 // transactions to a view with a flush at the end should be zero. 1620 { 1621 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 1622 require.NoError(err) 1623 require.Equal(0, len(utxoEntries)) 1624 } 1625 { 1626 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 1627 require.NoError(err) 1628 require.Equal(0, len(utxoEntries)) 1629 } 1630 { 1631 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 1632 require.NoError(err) 1633 require.Equal(0, len(utxoEntries)) 1634 } 1635 1636 _, _, _, _, _, _ = db, mempool, miner, bitcoinBlocks, bitcoinHeaders, bitcoinHeaderHeights 1637 } 1638 1639 func TestSpendOffOfUnminedTxnsBitcoinExchange(t *testing.T) { 1640 assert := assert.New(t) 1641 require := require.New(t) 1642 _ = assert 1643 _ = require 1644 1645 oldInitialUSDCentsPerBitcoinExchangeRate := InitialUSDCentsPerBitcoinExchangeRate 1646 InitialUSDCentsPerBitcoinExchangeRate = 1350000 1647 defer func() { 1648 InitialUSDCentsPerBitcoinExchangeRate = oldInitialUSDCentsPerBitcoinExchangeRate 1649 }() 1650 1651 paramsTmp := DeSoTestnetParams 1652 paramsTmp.DeSoNanosPurchasedAtGenesis = 0 1653 chain, params, db := NewLowDifficultyBlockchainWithParams(¶msTmp) 1654 mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/) 1655 1656 // Read in the test Bitcoin blocks and headers. 1657 bitcoinBlocks, bitcoinHeaders, bitcoinHeaderHeights := _readBitcoinExchangeTestData(t) 1658 1659 // Extract BitcoinExchange transactions from the test Bitcoin blocks. 1660 bitcoinExchangeTxns := []*MsgDeSoTxn{} 1661 for _, block := range bitcoinBlocks { 1662 currentBurnTxns, err := 1663 ExtractBitcoinExchangeTransactionsFromBitcoinBlock( 1664 block, BitcoinTestnetBurnAddress, params) 1665 require.NoError(err) 1666 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentBurnTxns...) 1667 } 1668 1669 // Verify that Bitcoin burn transactions are properly extracted from Bitcoin blocks 1670 // and the their burn amounts are computed correctly. 1671 require.Equal(9, len(bitcoinExchangeTxns)) 1672 expectedBitcoinBurnAmounts := []int64{ 1673 10000, 1674 12500, 1675 41000, 1676 20000, 1677 15000, 1678 50000, 1679 15000, 1680 20482, 1681 2490, 1682 } 1683 rateUpdateIndex := 4 1684 // We don't need these for this test because checking the final balances 1685 // is sufficient. 1686 //expectedDeSoNanosMinted := []int64{ 1687 //2700510570, 1688 //3375631103, 1689 //11072014581, 1690 //5400951887, 1691 //// We double the exchange rate at this point. Include a zero 1692 //// here to account for this. 1693 //0, 1694 //8103578296, 1695 //27011598923, 1696 //8103381058, 1697 //11064823217, 1698 //1345146534, 1699 //} 1700 blockIndexesForTransactions := []int{1, 1, 1, 1, 1, 1, 1, 3, 3} 1701 for ii, bitcoinExchangeTxn := range bitcoinExchangeTxns { 1702 txnMeta := bitcoinExchangeTxn.TxnMeta.(*BitcoinExchangeMetadata) 1703 burnTxn := txnMeta.BitcoinTransaction 1704 burnOutput, err := _computeBitcoinBurnOutput( 1705 burnTxn, BitcoinTestnetBurnAddress, params.BitcoinBtcdParams) 1706 require.NoError(err) 1707 assert.Equalf(expectedBitcoinBurnAmounts[ii], burnOutput, 1708 "Bitcoin burn amount for burn txn %d doesn't line up with "+ 1709 "what is expected", ii) 1710 1711 // Sanity-check that the Bitcoin block hashes line up. 1712 blockIndex := blockIndexesForTransactions[ii] 1713 blockForTxn := bitcoinBlocks[blockIndex] 1714 { 1715 hash1 := (BlockHash)(blockForTxn.BlockHash()) 1716 hash2 := *txnMeta.BitcoinBlockHash 1717 require.Equalf( 1718 hash1, hash2, 1719 "Bitcoin block hash for txn does not line up with block hash: %v %v %d", &hash1, &hash2, ii) 1720 } 1721 1722 // Sanity-check that the Merkle root lines up with what's in the block. 1723 { 1724 hash1 := (BlockHash)(blockForTxn.Header.MerkleRoot) 1725 hash2 := *txnMeta.BitcoinMerkleRoot 1726 require.Equalf( 1727 hash1, hash2, 1728 "Bitcoin merkle root for txn does not line up with block hash: %v %v %d", &hash1, &hash2, ii) 1729 } 1730 1731 // Verify that the merkle proof checks out. 1732 { 1733 txHash := ((BlockHash)(txnMeta.BitcoinTransaction.TxHash())) 1734 merkleProofIsValid := merkletree.VerifyProof( 1735 txHash[:], txnMeta.BitcoinMerkleProof, txnMeta.BitcoinMerkleRoot[:]) 1736 require.Truef( 1737 merkleProofIsValid, "Problem verifying merkle proof for burn txn %d", ii) 1738 } 1739 1740 // Verify that using the wrong Merkle root doesn't work. 1741 { 1742 badBlock := bitcoinBlocks[blockIndex-1] 1743 badMerkleRoot := badBlock.Header.MerkleRoot[:] 1744 txHash := ((BlockHash)(txnMeta.BitcoinTransaction.TxHash())) 1745 merkleProofIsValid := merkletree.VerifyProof( 1746 txHash[:], txnMeta.BitcoinMerkleProof, badMerkleRoot) 1747 require.Falsef( 1748 merkleProofIsValid, "Bad Merkle root was actually verified for burn txn %d", ii) 1749 } 1750 1751 // Verify that serializing and deserializing work for this transaction. 1752 bb, err := bitcoinExchangeTxn.ToBytes(false /*preSignature*/) 1753 require.NoError(err) 1754 parsedBitcoinExchangeTxn := &MsgDeSoTxn{} 1755 parsedBitcoinExchangeTxn.FromBytes(bb) 1756 require.Equal(bitcoinExchangeTxn, parsedBitcoinExchangeTxn) 1757 } 1758 1759 // Find the header in our header list corresponding to the first test block, 1760 // which contains the first Bitcoin 1761 firstBitcoinBurnBlock := bitcoinBlocks[1] 1762 firstBitcoinBurnBlockHash := firstBitcoinBurnBlock.BlockHash() 1763 headerIndexOfFirstBurn := -1 1764 for headerIndex := range bitcoinHeaders { 1765 if firstBitcoinBurnBlockHash == bitcoinHeaders[headerIndex].BlockHash() { 1766 headerIndexOfFirstBurn = headerIndex 1767 break 1768 } 1769 } 1770 require.Greater(headerIndexOfFirstBurn, 0) 1771 1772 // Create a Bitcoinmanager that is current whose tip corresponds to the block 1773 // just before the block containing the first Bitcoin burn transaction. 1774 minBurnBlocks := uint32(2) 1775 startHeaderIndex := 0 1776 paramsCopy := GetTestParamsCopy( 1777 bitcoinHeaders[startHeaderIndex], bitcoinHeaderHeights[startHeaderIndex], 1778 params, minBurnBlocks, 1779 ) 1780 1781 // Update some of the params to make them reflect what we've hacked into 1782 // the bitcoinManager. 1783 paramsCopy.BitcoinBurnAddress = BitcoinTestnetBurnAddress 1784 chain.params = paramsCopy 1785 // Reset the pool to give the mempool access to the new BitcoinManager object. 1786 mempool.resetPool(NewDeSoMempool(chain, 0, /* rateLimitFeeRateNanosPerKB */ 1787 0, /* minFeeRateNanosPerKB */ 1788 "" /*blockCypherAPIKey*/, false, 1789 "" /*dataDir*/, "")) 1790 1791 // The amount of work on the first burn transaction should be zero. 1792 burnTxn1 := bitcoinExchangeTxns[0] 1793 burnTxn1Size := getTxnSize(*burnTxn1) 1794 burnTxn2 := bitcoinExchangeTxns[1] 1795 txHash1 := burnTxn1.Hash() 1796 1797 // The mempool should accept a BitcoinExchange transaction if its merkle proof 1798 // is empty, since it skips the merkle proof checks in this case. 1799 { 1800 txnCopy := *burnTxn1 1801 txnCopy.TxnMeta = &BitcoinExchangeMetadata{ 1802 BitcoinTransaction: txnCopy.TxnMeta.(*BitcoinExchangeMetadata).BitcoinTransaction, 1803 BitcoinBlockHash: &BlockHash{}, 1804 BitcoinMerkleRoot: &BlockHash{}, 1805 BitcoinMerkleProof: []*merkletree.ProofPart{}, 1806 } 1807 mempoolTxs, err := mempool.processTransaction( 1808 &txnCopy, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0 /*peerID*/, true /*verifySignatures*/) 1809 require.NoError(err) 1810 require.Equal(1, len(mempoolTxs)) 1811 require.Equal(1, len(mempool.poolMap)) 1812 } 1813 1814 // The user we just applied this transaction for should have a balance now. 1815 pkBytes1, _ := hex.DecodeString(BitcoinTestnetPub1) 1816 { 1817 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 1818 require.NoError(err) 1819 1820 require.Equal(1, len(utxoEntries)) 1821 assert.Equal(int64(2697810060), int64(utxoEntries[0].AmountNanos)) 1822 } 1823 1824 // DO NOT process the Bitcoin block containing the first set of burn transactions. 1825 // This is the difference between this test and the previous test. 1826 1827 // According to the mempool, the balance of the user whose public key created 1828 // the Bitcoin burn transaction should now have some DeSo. 1829 pkBytes2, _ := hex.DecodeString(BitcoinTestnetPub2) 1830 pkBytes3, _ := hex.DecodeString(BitcoinTestnetPub3) 1831 1832 // The mempool should be able to process a burn transaction directly. 1833 { 1834 txnCopy := *burnTxn2 1835 txnCopy.TxnMeta = &BitcoinExchangeMetadata{ 1836 BitcoinTransaction: txnCopy.TxnMeta.(*BitcoinExchangeMetadata).BitcoinTransaction, 1837 BitcoinBlockHash: &BlockHash{}, 1838 BitcoinMerkleRoot: &BlockHash{}, 1839 BitcoinMerkleProof: []*merkletree.ProofPart{}, 1840 } 1841 mempoolTxsAdded, err := mempool.processTransaction( 1842 &txnCopy, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 1843 true /*verifySignatures*/) 1844 require.NoError(err) 1845 require.Equal(1, len(mempoolTxsAdded)) 1846 require.Equal(2, len(mempool.poolMap)) 1847 mempoolTxRet := mempool.poolMap[*mempoolTxsAdded[0].Hash] 1848 require.Equal( 1849 mempoolTxRet.Tx.TxnMeta.(*BitcoinExchangeMetadata), 1850 txnCopy.TxnMeta.(*BitcoinExchangeMetadata)) 1851 } 1852 1853 // According to the mempool, the balances should have updated. 1854 { 1855 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 1856 require.NoError(err) 1857 1858 require.Equal(1, len(utxoEntries)) 1859 assert.Equal(int64(3372255472), int64(utxoEntries[0].AmountNanos)) 1860 } 1861 1862 // If the mempool is not consulted, the balances should be zero. 1863 { 1864 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 1865 require.NoError(err) 1866 require.Equal(0, len(utxoEntries)) 1867 } 1868 1869 // Make the moneyPkString the paramUpdater so they can update the exchange rate. 1870 params.ParamUpdaterPublicKeys = make(map[PkMapKey]bool) 1871 params.ParamUpdaterPublicKeys[MakePkMapKey(MustBase58CheckDecode(moneyPkString))] = true 1872 paramsCopy.ParamUpdaterPublicKeys = params.ParamUpdaterPublicKeys 1873 1874 // Running the remaining transactions through the mempool should work and result 1875 // in all of them being added. 1876 { 1877 // Add a placeholder where the rate update is going to be 1878 fff := append([]*MsgDeSoTxn{}, bitcoinExchangeTxns[:rateUpdateIndex]...) 1879 fff = append(fff, nil) 1880 fff = append(fff, bitcoinExchangeTxns[rateUpdateIndex:]...) 1881 bitcoinExchangeTxns = fff 1882 1883 for fakeIndex, burnTxn := range bitcoinExchangeTxns[2:] { 1884 realIndex := fakeIndex + 2 1885 if realIndex == rateUpdateIndex { 1886 newUSDCentsPerBitcoin := int64(27000 * 100) 1887 updaterPkBytes, _, err := Base58CheckDecode(moneyPkString) 1888 require.NoError(err) 1889 rateUpdateTxn, _, _, _, err := chain.CreateUpdateGlobalParamsTxn( 1890 updaterPkBytes, 1891 newUSDCentsPerBitcoin, 1892 0, 1893 0, 1894 -1, 1895 0, 1896 nil, 1897 100, /*feeRateNanosPerKB*/ 1898 nil, 1899 []*DeSoOutput{}) 1900 require.NoError(err) 1901 // Sign the transaction now that its inputs are set up. 1902 _signTxn(t, rateUpdateTxn, moneyPrivString) 1903 1904 bitcoinExchangeTxns[realIndex] = rateUpdateTxn 1905 burnTxn := bitcoinExchangeTxns[realIndex] 1906 1907 require.Equal(realIndex, len(mempool.poolMap)) 1908 mempoolTxsAdded, err := mempool.processTransaction( 1909 burnTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 1910 true /*verifySignatures*/) 1911 require.NoErrorf(err, "on index: %v", realIndex) 1912 require.Equal(1, len(mempoolTxsAdded)) 1913 1914 continue 1915 } 1916 1917 txnCopy := *burnTxn 1918 txnCopy.TxnMeta = &BitcoinExchangeMetadata{ 1919 BitcoinTransaction: txnCopy.TxnMeta.(*BitcoinExchangeMetadata).BitcoinTransaction, 1920 BitcoinBlockHash: &BlockHash{}, 1921 BitcoinMerkleRoot: &BlockHash{}, 1922 BitcoinMerkleProof: []*merkletree.ProofPart{}, 1923 } 1924 require.Equal(realIndex, len(mempool.poolMap)) 1925 mempoolTxsAdded, err := mempool.processTransaction( 1926 &txnCopy, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 1927 true /*verifySignatures*/) 1928 require.NoErrorf(err, "on index: %v", realIndex) 1929 require.Equal(1, len(mempoolTxsAdded)) 1930 } 1931 } 1932 1933 { 1934 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 1935 require.NoError(err) 1936 require.Equal(5, len(utxoEntries)) 1937 totalBalance := uint64(0) 1938 for _, utxoEntry := range utxoEntries { 1939 totalBalance += utxoEntry.AmountNanos 1940 } 1941 // Note the 10bp fee. 1942 assert.Equal(int64(47475508103), int64(totalBalance)) 1943 } 1944 { 1945 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 1946 require.NoError(err) 1947 require.Equal(1, len(utxoEntries)) 1948 // Note the 10bp fee. 1949 assert.Equal(int64(8095277677), int64(utxoEntries[0].AmountNanos)) 1950 } 1951 { 1952 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 1953 require.NoError(err) 1954 require.Equal(3, len(utxoEntries)) 1955 totalBalance := uint64(0) 1956 for _, utxoEntry := range utxoEntries { 1957 totalBalance += utxoEntry.AmountNanos 1958 } 1959 // Note the 10bp fee. 1960 assert.Equal(int64(22528672757), int64(totalBalance)) 1961 } 1962 1963 // Spending from the outputs created by a burn should work. 1964 desoPub1 := Base58CheckEncode(pkBytes1, false /*isPrivate*/, paramsCopy) 1965 priv1, _ := _privStringToKeys(t, BitcoinTestnetPriv1) 1966 desoPriv1 := Base58CheckEncode(priv1.Serialize(), true /*isPrivate*/, paramsCopy) 1967 desoPub2 := Base58CheckEncode(pkBytes2, false /*isPrivate*/, paramsCopy) 1968 priv2, _ := _privStringToKeys(t, BitcoinTestnetPriv2) 1969 desoPriv2 := Base58CheckEncode(priv2.Serialize(), true /*isPrivate*/, paramsCopy) 1970 desoPub3 := Base58CheckEncode(pkBytes3, false /*isPrivate*/, paramsCopy) 1971 priv3, _ := _privStringToKeys(t, BitcoinTestnetPriv3) 1972 desoPriv3 := Base58CheckEncode(priv3.Serialize(), true /*isPrivate*/, paramsCopy) 1973 { 1974 txn := _assembleBasicTransferTxnFullySigned( 1975 t, chain, 100000*100000, 11, desoPub1, desoPub2, 1976 desoPriv1, mempool) 1977 mempoolTxsAdded, err := mempool.processTransaction( 1978 txn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 1979 true /*verifySignatures*/) 1980 require.NoError(err) 1981 require.Equal(1, len(mempoolTxsAdded)) 1982 bitcoinExchangeTxns = append(bitcoinExchangeTxns, txn) 1983 } 1984 { 1985 txn := _assembleBasicTransferTxnFullySigned( 1986 t, chain, 60000*100000, 11, desoPub3, desoPub1, 1987 desoPriv3, mempool) 1988 mempoolTxsAdded, err := mempool.processTransaction( 1989 txn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 1990 true /*verifySignatures*/) 1991 require.NoError(err) 1992 require.Equal(1, len(mempoolTxsAdded)) 1993 bitcoinExchangeTxns = append(bitcoinExchangeTxns, txn) 1994 } 1995 { 1996 txn := _assembleBasicTransferTxnFullySigned( 1997 t, chain, 60000*100000, 11, desoPub2, desoPub1, 1998 desoPriv2, mempool) 1999 mempoolTxsAdded, err := mempool.processTransaction( 2000 txn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 2001 true /*verifySignatures*/) 2002 require.NoError(err) 2003 require.Equal(1, len(mempoolTxsAdded)) 2004 bitcoinExchangeTxns = append(bitcoinExchangeTxns, txn) 2005 } 2006 2007 // The balances according to the db after the spends above should be correct. 2008 { 2009 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 2010 require.NoError(err) 2011 totalBalance := uint64(0) 2012 for _, utxoEntry := range utxoEntries { 2013 totalBalance += utxoEntry.AmountNanos 2014 } 2015 assert.Equal(int64(49455017177), int64(totalBalance)) 2016 } 2017 { 2018 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 2019 require.NoError(err) 2020 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 2021 } 2022 { 2023 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 2024 require.NoError(err) 2025 totalBalance := uint64(0) 2026 for _, utxoEntry := range utxoEntries { 2027 totalBalance += utxoEntry.AmountNanos 2028 } 2029 assert.Equal(int64(16517205024), int64(totalBalance)) 2030 } 2031 prevMempoolSize := len(mempool.poolMap) 2032 2033 // The transaction should pass now 2034 { 2035 utxoView, _ := NewUtxoView(db, paramsCopy, nil) 2036 blockHeight := chain.blockTip().Height + 1 2037 2038 _, _, _, _, err := 2039 utxoView.ConnectTransaction(burnTxn1, txHash1, burnTxn1Size, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 2040 require.NoError(err) 2041 } 2042 2043 miner.params = paramsCopy 2044 miner.BlockProducer.params = paramsCopy 2045 2046 // At this point, the mempool should contain *mined* BitcoinExchange 2047 // transactions with fully proper merkle proofs. 2048 2049 // Now mining the blocks should get us the balances that the mempool 2050 // reported previously. 2051 finalBlock1, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 2052 require.NoError(err) 2053 _ = finalBlock1 2054 finalBlock2, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 2055 require.NoError(err) 2056 finalBlock3, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 2057 require.NoError(err) 2058 finalBlock4, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 2059 require.NoError(err) 2060 2061 // The first block should contain the txns because we mined a 2062 // block to get the chain current previously. 2063 require.Equal(len(finalBlock1.Txns), 1) 2064 require.Equal(len(finalBlock2.Txns), 14) 2065 require.Equal(len(finalBlock3.Txns), 1) 2066 require.Equal(len(finalBlock4.Txns), 1) 2067 2068 // The transactions should all have been processed into blocks and 2069 // removed from the mempool. 2070 require.Equal(0, len(mempool.poolMap)) 2071 // The balances should be what they were even if you query the mempool 2072 // because the txns have now moved into the db. 2073 { 2074 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 2075 require.NoError(err) 2076 totalBalance := uint64(0) 2077 for _, utxoEntry := range utxoEntries { 2078 totalBalance += utxoEntry.AmountNanos 2079 } 2080 assert.Equal(int64(49455017177), int64(totalBalance)) 2081 } 2082 { 2083 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 2084 require.NoError(err) 2085 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 2086 } 2087 { 2088 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 2089 require.NoError(err) 2090 totalBalance := uint64(0) 2091 for _, utxoEntry := range utxoEntries { 2092 totalBalance += utxoEntry.AmountNanos 2093 } 2094 assert.Equal(int64(16517205024), int64(totalBalance)) 2095 } 2096 2097 // The balances after mining the block should line up. 2098 { 2099 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 2100 require.NoError(err) 2101 totalBalance := uint64(0) 2102 for _, utxoEntry := range utxoEntries { 2103 totalBalance += utxoEntry.AmountNanos 2104 } 2105 assert.Equal(int64(49455017177), int64(totalBalance)) 2106 } 2107 { 2108 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 2109 require.NoError(err) 2110 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 2111 } 2112 { 2113 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 2114 require.NoError(err) 2115 totalBalance := uint64(0) 2116 for _, utxoEntry := range utxoEntries { 2117 totalBalance += utxoEntry.AmountNanos 2118 } 2119 assert.Equal(int64(16517205024), int64(totalBalance)) 2120 } 2121 2122 // Roll back the blocks and make sure we don't hit any errors. Call 2123 // the mempool's disconnect function to make sure we get the txns 2124 // back during a reorg. 2125 { 2126 utxoView, err := NewUtxoView(db, paramsCopy, nil) 2127 require.NoError(err) 2128 2129 { 2130 // Fetch the utxo operations for the block we're detaching. We need these 2131 // in order to be able to detach the block. 2132 hash, err := finalBlock4.Header.Hash() 2133 require.NoError(err) 2134 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 2135 require.NoError(err) 2136 2137 // Compute the hashes for all the transactions. 2138 txHashes, err := ComputeTransactionHashes(finalBlock4.Txns) 2139 require.NoError(err) 2140 require.NoError(utxoView.DisconnectBlock(finalBlock4, txHashes, utxoOps)) 2141 } 2142 { 2143 // Fetch the utxo operations for the block we're detaching. We need these 2144 // in order to be able to detach the block. 2145 hash, err := finalBlock3.Header.Hash() 2146 require.NoError(err) 2147 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 2148 require.NoError(err) 2149 2150 // Compute the hashes for all the transactions. 2151 txHashes, err := ComputeTransactionHashes(finalBlock3.Txns) 2152 require.NoError(err) 2153 require.NoError(utxoView.DisconnectBlock(finalBlock3, txHashes, utxoOps)) 2154 } 2155 { 2156 // Fetch the utxo operations for the block we're detaching. We need these 2157 // in order to be able to detach the block. 2158 hash, err := finalBlock2.Header.Hash() 2159 require.NoError(err) 2160 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 2161 require.NoError(err) 2162 2163 // Compute the hashes for all the transactions. 2164 txHashes, err := ComputeTransactionHashes(finalBlock2.Txns) 2165 require.NoError(err) 2166 require.NoError(utxoView.DisconnectBlock(finalBlock2, txHashes, utxoOps)) 2167 } 2168 { 2169 // Fetch the utxo operations for the block we're detaching. We need these 2170 // in order to be able to detach the block. 2171 hash, err := finalBlock1.Header.Hash() 2172 require.NoError(err) 2173 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 2174 require.NoError(err) 2175 2176 // Compute the hashes for all the transactions. 2177 txHashes, err := ComputeTransactionHashes(finalBlock1.Txns) 2178 require.NoError(err) 2179 require.NoError(utxoView.DisconnectBlock(finalBlock1, txHashes, utxoOps)) 2180 } 2181 2182 // Flushing the view after applying and rolling back should work. 2183 require.NoError(utxoView.FlushToDb()) 2184 2185 mempool.UpdateAfterDisconnectBlock(finalBlock4) 2186 mempool.UpdateAfterDisconnectBlock(finalBlock3) 2187 mempool.UpdateAfterDisconnectBlock(finalBlock2) 2188 mempool.UpdateAfterDisconnectBlock(finalBlock1) 2189 } 2190 2191 // The balances according to the db without querying the mempool should 2192 // be zero again. 2193 { 2194 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 2195 require.NoError(err) 2196 require.Equal(0, len(utxoEntries)) 2197 } 2198 { 2199 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 2200 require.NoError(err) 2201 require.Equal(0, len(utxoEntries)) 2202 } 2203 { 2204 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 2205 require.NoError(err) 2206 require.Equal(0, len(utxoEntries)) 2207 } 2208 2209 // The mempool should have all of its txns back and the balances should be what 2210 // they were before we did a block reorg. 2211 require.Equal(prevMempoolSize, len(mempool.poolMap)) 2212 { 2213 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 2214 require.NoError(err) 2215 totalBalance := uint64(0) 2216 for _, utxoEntry := range utxoEntries { 2217 totalBalance += utxoEntry.AmountNanos 2218 } 2219 assert.Equal(int64(49455017177), int64(totalBalance)) 2220 } 2221 { 2222 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 2223 require.NoError(err) 2224 assert.Equal(int64(2087182397), int64(utxoEntries[0].AmountNanos)) 2225 } 2226 { 2227 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 2228 require.NoError(err) 2229 totalBalance := uint64(0) 2230 for _, utxoEntry := range utxoEntries { 2231 totalBalance += utxoEntry.AmountNanos 2232 } 2233 assert.Equal(int64(16517205024), int64(totalBalance)) 2234 } 2235 2236 _, _, _, _, _, _ = db, mempool, miner, bitcoinBlocks, bitcoinHeaders, bitcoinHeaderHeights 2237 } 2238 2239 func TestBitcoinExchangeWithAmountNanosNonZeroAtGenesis(t *testing.T) { 2240 assert := assert.New(t) 2241 require := require.New(t) 2242 _ = assert 2243 _ = require 2244 2245 // Don't refresh the universal view for this test, since it causes a race condition 2246 // to trigger. 2247 // TODO: Lower this value to .1 and fix this race condition. 2248 ReadOnlyUtxoViewRegenerationIntervalSeconds = 100 2249 2250 oldInitialUSDCentsPerBitcoinExchangeRate := InitialUSDCentsPerBitcoinExchangeRate 2251 InitialUSDCentsPerBitcoinExchangeRate = 1350000 2252 defer func() { 2253 InitialUSDCentsPerBitcoinExchangeRate = oldInitialUSDCentsPerBitcoinExchangeRate 2254 }() 2255 2256 paramsTmp := DeSoTestnetParams 2257 paramsTmp.DeSoNanosPurchasedAtGenesis = 500000123456789 2258 chain, params, db := NewLowDifficultyBlockchainWithParams(¶msTmp) 2259 mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/) 2260 2261 // Read in the test Bitcoin blocks and headers. 2262 bitcoinBlocks, bitcoinHeaders, bitcoinHeaderHeights := _readBitcoinExchangeTestData(t) 2263 2264 // Extract BitcoinExchange transactions from the test Bitcoin blocks. 2265 bitcoinExchangeTxns := []*MsgDeSoTxn{} 2266 for _, block := range bitcoinBlocks { 2267 currentBurnTxns, err := 2268 ExtractBitcoinExchangeTransactionsFromBitcoinBlock( 2269 block, BitcoinTestnetBurnAddress, params) 2270 require.NoError(err) 2271 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentBurnTxns...) 2272 } 2273 2274 // Verify that Bitcoin burn transactions are properly extracted from Bitcoin blocks 2275 // and the their burn amounts are computed correctly. 2276 require.Equal(9, len(bitcoinExchangeTxns)) 2277 expectedBitcoinBurnAmounts := []int64{ 2278 10000, 2279 12500, 2280 41000, 2281 20000, 2282 15000, 2283 50000, 2284 15000, 2285 20482, 2286 2490, 2287 } 2288 rateUpdateIndex := 4 2289 expectedDeSoNanosMinted := []int64{ 2290 1909549696, 2291 2386933566, 2292 7829114379, 2293 3819064767, 2294 // We double the exchange rate at this point. Include a zero 2295 // here to account for this. 2296 0, 2297 5730125620, 2298 19100254365, 2299 5730026999, 2300 7824124112, 2301 951177121, 2302 } 2303 blockIndexesForTransactions := []int{1, 1, 1, 1, 1, 1, 1, 3, 3} 2304 for ii, bitcoinExchangeTxn := range bitcoinExchangeTxns { 2305 txnMeta := bitcoinExchangeTxn.TxnMeta.(*BitcoinExchangeMetadata) 2306 burnTxn := txnMeta.BitcoinTransaction 2307 burnOutput, err := _computeBitcoinBurnOutput( 2308 burnTxn, BitcoinTestnetBurnAddress, params.BitcoinBtcdParams) 2309 require.NoError(err) 2310 assert.Equalf(expectedBitcoinBurnAmounts[ii], burnOutput, 2311 "Bitcoin burn amount for burn txn %d doesn't line up with "+ 2312 "what is expected", ii) 2313 2314 // Sanity-check that the Bitcoin block hashes line up. 2315 blockIndex := blockIndexesForTransactions[ii] 2316 blockForTxn := bitcoinBlocks[blockIndex] 2317 { 2318 hash1 := (BlockHash)(blockForTxn.BlockHash()) 2319 hash2 := *txnMeta.BitcoinBlockHash 2320 require.Equalf( 2321 hash1, hash2, 2322 "Bitcoin block hash for txn does not line up with block hash: %v %v %d", &hash1, &hash2, ii) 2323 } 2324 2325 // Sanity-check that the Merkle root lines up with what's in the block. 2326 { 2327 hash1 := (BlockHash)(blockForTxn.Header.MerkleRoot) 2328 hash2 := *txnMeta.BitcoinMerkleRoot 2329 require.Equalf( 2330 hash1, hash2, 2331 "Bitcoin merkle root for txn does not line up with block hash: %v %v %d", &hash1, &hash2, ii) 2332 } 2333 2334 // Verify that the merkle proof checks out. 2335 { 2336 txHash := ((BlockHash)(txnMeta.BitcoinTransaction.TxHash())) 2337 merkleProofIsValid := merkletree.VerifyProof( 2338 txHash[:], txnMeta.BitcoinMerkleProof, txnMeta.BitcoinMerkleRoot[:]) 2339 require.Truef( 2340 merkleProofIsValid, "Problem verifying merkle proof for burn txn %d", ii) 2341 } 2342 2343 // Verify that using the wrong Merkle root doesn't work. 2344 { 2345 badBlock := bitcoinBlocks[blockIndex-1] 2346 badMerkleRoot := badBlock.Header.MerkleRoot[:] 2347 txHash := ((BlockHash)(txnMeta.BitcoinTransaction.TxHash())) 2348 merkleProofIsValid := merkletree.VerifyProof( 2349 txHash[:], txnMeta.BitcoinMerkleProof, badMerkleRoot) 2350 require.Falsef( 2351 merkleProofIsValid, "Bad Merkle root was actually verified for burn txn %d", ii) 2352 } 2353 2354 // Verify that serializing and deserializing work for this transaction. 2355 bb, err := bitcoinExchangeTxn.ToBytes(false /*preSignature*/) 2356 require.NoError(err) 2357 parsedBitcoinExchangeTxn := &MsgDeSoTxn{} 2358 parsedBitcoinExchangeTxn.FromBytes(bb) 2359 require.Equal(bitcoinExchangeTxn, parsedBitcoinExchangeTxn) 2360 } 2361 2362 // Find the header in our header list corresponding to the first test block, 2363 // which contains the first Bitcoin 2364 firstBitcoinBurnBlock := bitcoinBlocks[1] 2365 firstBitcoinBurnBlockHash := firstBitcoinBurnBlock.BlockHash() 2366 headerIndexOfFirstBurn := -1 2367 for headerIndex := range bitcoinHeaders { 2368 if firstBitcoinBurnBlockHash == bitcoinHeaders[headerIndex].BlockHash() { 2369 headerIndexOfFirstBurn = headerIndex 2370 break 2371 } 2372 } 2373 require.Greater(headerIndexOfFirstBurn, 0) 2374 2375 // Create a Bitcoinmanager that is current whose tip corresponds to the block 2376 // just before the block containing the first Bitcoin burn transaction. 2377 minBurnBlocks := uint32(2) 2378 startHeaderIndex := 0 2379 paramsCopy := GetTestParamsCopy( 2380 bitcoinHeaders[startHeaderIndex], bitcoinHeaderHeights[startHeaderIndex], 2381 params, minBurnBlocks, 2382 ) 2383 2384 // Update some of the params to make them reflect what we've hacked into 2385 // the bitcoinManager. 2386 paramsCopy.BitcoinBurnAddress = BitcoinTestnetBurnAddress 2387 chain.params = paramsCopy 2388 // Reset the pool to give the mempool access to the new BitcoinManager object. 2389 mempool.resetPool(NewDeSoMempool(chain, 0, /* rateLimitFeeRateNanosPerKB */ 2390 0, /* minFeeRateNanosPerKB */ 2391 "" /*blockCypherAPIKey*/, false, 2392 "" /*dataDir*/, "")) 2393 2394 // The amount of work on the first burn transaction should be zero. 2395 burnTxn1 := bitcoinExchangeTxns[0] 2396 burnTxn2 := bitcoinExchangeTxns[1] 2397 2398 // Applying the full transaction with its merkle proof to the mempool should work 2399 { 2400 mempoolTxs, err := mempool.processTransaction( 2401 burnTxn1, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0 /*peerID*/, true /*verifySignatures*/) 2402 require.NoError(err) 2403 require.Equal(1, len(mempoolTxs)) 2404 require.Equal(1, len(mempool.poolMap)) 2405 mempoolTxRet := mempool.poolMap[*mempoolTxs[0].Hash] 2406 require.Equal( 2407 mempoolTxRet.Tx.TxnMeta.(*BitcoinExchangeMetadata), 2408 burnTxn1.TxnMeta.(*BitcoinExchangeMetadata)) 2409 } 2410 2411 // According to the mempool, the balance of the user whose public key created 2412 // the Bitcoin burn transaction should now have some DeSo. 2413 pkBytes1, _ := hex.DecodeString(BitcoinTestnetPub1) 2414 pkBytes2, _ := hex.DecodeString(BitcoinTestnetPub2) 2415 pkBytes3, _ := hex.DecodeString(BitcoinTestnetPub3) 2416 { 2417 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 2418 require.NoError(err) 2419 2420 require.Equal(1, len(utxoEntries)) 2421 assert.Equal(int64(1907640147), int64(utxoEntries[0].AmountNanos)) 2422 } 2423 2424 // The mempool should be able to process a burn transaction directly. 2425 { 2426 mempoolTxsAdded, err := mempool.processTransaction( 2427 burnTxn2, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 2428 true /*verifySignatures*/) 2429 require.NoError(err) 2430 require.Equal(1, len(mempoolTxsAdded)) 2431 require.Equal(2, len(mempool.poolMap)) 2432 mempoolTxRet := mempool.poolMap[*mempoolTxsAdded[0].Hash] 2433 require.Equal( 2434 mempoolTxRet.Tx.TxnMeta.(*BitcoinExchangeMetadata), 2435 burnTxn2.TxnMeta.(*BitcoinExchangeMetadata)) 2436 } 2437 2438 // According to the mempool, the balances should have updated. 2439 { 2440 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 2441 require.NoError(err) 2442 2443 require.Equal(1, len(utxoEntries)) 2444 assert.Equal(int64(2384546633), int64(utxoEntries[0].AmountNanos)) 2445 } 2446 2447 // If the mempool is not consulted, the balances should be zero. 2448 { 2449 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 2450 require.NoError(err) 2451 require.Equal(0, len(utxoEntries)) 2452 } 2453 2454 // Make the moneyPkString the paramUpdater so they can update the exchange rate. 2455 params.ParamUpdaterPublicKeys = make(map[PkMapKey]bool) 2456 params.ParamUpdaterPublicKeys[MakePkMapKey(MustBase58CheckDecode(moneyPkString))] = true 2457 paramsCopy.ParamUpdaterPublicKeys = params.ParamUpdaterPublicKeys 2458 2459 // Applying all the txns to the UtxoView should work. Include a rate update 2460 // in the middle. 2461 utxoOpsList := [][]*UtxoOperation{} 2462 { 2463 utxoView, err := NewUtxoView(db, paramsCopy, nil) 2464 require.NoError(err) 2465 2466 // Add a placeholder where the rate update is going to be 2467 fff := append([]*MsgDeSoTxn{}, bitcoinExchangeTxns[:rateUpdateIndex]...) 2468 fff = append(fff, nil) 2469 fff = append(fff, bitcoinExchangeTxns[rateUpdateIndex:]...) 2470 bitcoinExchangeTxns = fff 2471 2472 for ii := range bitcoinExchangeTxns { 2473 // When we hit the rate update, populate the placeholder. 2474 if ii == rateUpdateIndex { 2475 newUSDCentsPerBitcoin := uint64(27000 * 100) 2476 _, rateUpdateTxn, _, err := _updateUSDCentsPerBitcoinExchangeRate( 2477 t, chain, db, params, 100, /*feeRateNanosPerKB*/ 2478 moneyPkString, 2479 moneyPrivString, 2480 newUSDCentsPerBitcoin) 2481 require.NoError(err) 2482 2483 bitcoinExchangeTxns[ii] = rateUpdateTxn 2484 burnTxn := bitcoinExchangeTxns[ii] 2485 burnTxnSize := getTxnSize(*burnTxn) 2486 blockHeight := chain.blockTip().Height + 1 2487 utxoOps, totalInput, totalOutput, fees, err := 2488 utxoView.ConnectTransaction( 2489 burnTxn, burnTxn.Hash(), burnTxnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 2490 _, _, _ = totalInput, totalOutput, fees 2491 require.NoError(err) 2492 utxoOpsList = append(utxoOpsList, utxoOps) 2493 continue 2494 } 2495 2496 burnTxn := bitcoinExchangeTxns[ii] 2497 burnTxnSize := getTxnSize(*burnTxn) 2498 blockHeight := chain.blockTip().Height + 1 2499 utxoOps, totalInput, totalOutput, fees, err := 2500 utxoView.ConnectTransaction( 2501 burnTxn, burnTxn.Hash(), burnTxnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 2502 require.NoError(err) 2503 2504 require.Equal(2, len(utxoOps)) 2505 //fmt.Println(int64(totalInput), ",") 2506 assert.Equal(expectedDeSoNanosMinted[ii], int64(totalInput)) 2507 assert.Equal(expectedDeSoNanosMinted[ii]*int64(paramsCopy.BitcoinExchangeFeeBasisPoints)/10000, int64(fees)) 2508 assert.Equal(int64(fees), int64(totalInput-totalOutput)) 2509 2510 _, _, _ = ii, totalOutput, fees 2511 utxoOpsList = append(utxoOpsList, utxoOps) 2512 } 2513 2514 // Flushing the UtxoView should work. 2515 require.NoError(utxoView.FlushToDb()) 2516 } 2517 2518 // The balances according to the db after the flush should be correct. 2519 { 2520 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 2521 require.NoError(err) 2522 require.Equal(5, len(utxoEntries)) 2523 totalBalance := uint64(0) 2524 for _, utxoEntry := range utxoEntries { 2525 totalBalance += utxoEntry.AmountNanos 2526 } 2527 // Note the 10bp fee. 2528 assert.Equal(int64(33570565893), int64(totalBalance)) 2529 } 2530 { 2531 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 2532 require.NoError(err) 2533 require.Equal(1, len(utxoEntries)) 2534 // Note the 10bp fee. 2535 assert.Equal(int64(5724296973), int64(utxoEntries[0].AmountNanos)) 2536 } 2537 { 2538 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 2539 require.NoError(err) 2540 require.Equal(3, len(utxoEntries)) 2541 totalBalance := uint64(0) 2542 for _, utxoEntry := range utxoEntries { 2543 totalBalance += utxoEntry.AmountNanos 2544 } 2545 // Note the 10bp fee. 2546 assert.Equal(int64(15930227393), int64(totalBalance)) 2547 } 2548 2549 // Spending from the outputs created by a burn should work. 2550 desoPub1 := Base58CheckEncode(pkBytes1, false /*isPrivate*/, paramsCopy) 2551 priv1, _ := _privStringToKeys(t, BitcoinTestnetPriv1) 2552 desoPriv1 := Base58CheckEncode(priv1.Serialize(), true /*isPrivate*/, paramsCopy) 2553 desoPub2 := Base58CheckEncode(pkBytes2, false /*isPrivate*/, paramsCopy) 2554 priv2, _ := _privStringToKeys(t, BitcoinTestnetPriv2) 2555 desoPriv2 := Base58CheckEncode(priv2.Serialize(), true /*isPrivate*/, paramsCopy) 2556 desoPub3 := Base58CheckEncode(pkBytes3, false /*isPrivate*/, paramsCopy) 2557 priv3, _ := _privStringToKeys(t, BitcoinTestnetPriv3) 2558 desoPriv3 := Base58CheckEncode(priv3.Serialize(), true /*isPrivate*/, paramsCopy) 2559 { 2560 currentOps, currentTxn, _ := _doBasicTransferWithViewFlush( 2561 t, chain, db, params, desoPub1, desoPub2, 2562 desoPriv1, 100000*100000 /*amount to send*/, 11 /*feerate*/) 2563 2564 utxoOpsList = append(utxoOpsList, currentOps) 2565 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentTxn) 2566 } 2567 { 2568 currentOps, currentTxn, _ := _doBasicTransferWithViewFlush( 2569 t, chain, db, params, desoPub3, desoPub1, 2570 desoPriv3, 60000*100000 /*amount to send*/, 11 /*feerate*/) 2571 2572 utxoOpsList = append(utxoOpsList, currentOps) 2573 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentTxn) 2574 } 2575 { 2576 currentOps, currentTxn, _ := _doBasicTransferWithViewFlush( 2577 t, chain, db, params, desoPub2, desoPub1, 2578 desoPriv2, 60000*100000 /*amount to send*/, 11 /*feerate*/) 2579 2580 utxoOpsList = append(utxoOpsList, currentOps) 2581 bitcoinExchangeTxns = append(bitcoinExchangeTxns, currentTxn) 2582 } 2583 2584 // The balances according to the db after the spends above should be correct. 2585 { 2586 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 2587 require.NoError(err) 2588 totalBalance := uint64(0) 2589 for _, utxoEntry := range utxoEntries { 2590 totalBalance += utxoEntry.AmountNanos 2591 } 2592 assert.Equal(int64(35556076477), int64(totalBalance)) 2593 } 2594 { 2595 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 2596 require.NoError(err) 2597 assert.Equal(int64(9718572674), int64(utxoEntries[0].AmountNanos)) 2598 } 2599 { 2600 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 2601 require.NoError(err) 2602 totalBalance := uint64(0) 2603 for _, utxoEntry := range utxoEntries { 2604 totalBalance += utxoEntry.AmountNanos 2605 } 2606 assert.Equal(int64(9922118448), int64(totalBalance)) 2607 } 2608 2609 { 2610 // Rolling back all the transactions should work. 2611 utxoView, err := NewUtxoView(db, paramsCopy, nil) 2612 require.NoError(err) 2613 for ii := range bitcoinExchangeTxns { 2614 index := len(bitcoinExchangeTxns) - 1 - ii 2615 burnTxn := bitcoinExchangeTxns[index] 2616 blockHeight := chain.blockTip().Height + 1 2617 err := utxoView.DisconnectTransaction(burnTxn, burnTxn.Hash(), utxoOpsList[index], blockHeight) 2618 require.NoErrorf(err, "Transaction index: %v", index) 2619 } 2620 2621 // Flushing the UtxoView back to the db after rolling back the 2622 require.NoError(utxoView.FlushToDb()) 2623 } 2624 2625 // The balances according to the db after rolling back and flushing everything 2626 // should be zero. 2627 { 2628 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 2629 require.NoError(err) 2630 require.Equal(0, len(utxoEntries)) 2631 } 2632 { 2633 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 2634 require.NoError(err) 2635 require.Equal(0, len(utxoEntries)) 2636 } 2637 { 2638 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 2639 require.NoError(err) 2640 require.Equal(0, len(utxoEntries)) 2641 } 2642 2643 // Re-applying all the transactions to the view and rolling back without 2644 // flushing should be fine. 2645 utxoOpsList = [][]*UtxoOperation{} 2646 { 2647 utxoView, err := NewUtxoView(db, paramsCopy, nil) 2648 require.NoError(err) 2649 for ii, burnTxn := range bitcoinExchangeTxns { 2650 blockHeight := chain.blockTip().Height + 1 2651 burnTxnSize := getTxnSize(*burnTxn) 2652 utxoOps, totalInput, totalOutput, fees, err := 2653 utxoView.ConnectTransaction(burnTxn, burnTxn.Hash(), burnTxnSize, blockHeight, true /*verifySignature*/, false /*ignoreUtxos*/) 2654 require.NoError(err) 2655 2656 if ii < len(expectedBitcoinBurnAmounts) { 2657 if ii != rateUpdateIndex { 2658 require.Equal(2, len(utxoOps)) 2659 assert.Equal(int64(totalInput), expectedDeSoNanosMinted[ii]) 2660 assert.Equal(int64(fees), expectedDeSoNanosMinted[ii]*int64(paramsCopy.BitcoinExchangeFeeBasisPoints)/10000) 2661 assert.Equal(int64(fees), int64(totalInput-totalOutput)) 2662 } 2663 } 2664 2665 utxoOpsList = append(utxoOpsList, utxoOps) 2666 } 2667 2668 for ii := range bitcoinExchangeTxns { 2669 index := len(bitcoinExchangeTxns) - 1 - ii 2670 burnTxn := bitcoinExchangeTxns[index] 2671 blockHeight := chain.blockTip().Height + 1 2672 err := utxoView.DisconnectTransaction(burnTxn, burnTxn.Hash(), utxoOpsList[index], blockHeight) 2673 require.NoError(err) 2674 } 2675 2676 // Flushing the view after applying and rolling back should work. 2677 require.NoError(utxoView.FlushToDb()) 2678 } 2679 2680 // The balances according to the db after applying and unapplying all the 2681 // transactions to a view with a flush at the end should be zero. 2682 { 2683 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 2684 require.NoError(err) 2685 require.Equal(0, len(utxoEntries)) 2686 } 2687 { 2688 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 2689 require.NoError(err) 2690 require.Equal(0, len(utxoEntries)) 2691 } 2692 { 2693 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 2694 require.NoError(err) 2695 require.Equal(0, len(utxoEntries)) 2696 } 2697 2698 // Running all the transactions through the mempool should work and result 2699 // in all of them being added. 2700 { 2701 for _, burnTxn := range bitcoinExchangeTxns { 2702 // We have to remove the transactions first. 2703 mempool.inefficientRemoveTransaction(burnTxn) 2704 } 2705 for ii, burnTxn := range bitcoinExchangeTxns { 2706 require.Equal(ii, len(mempool.poolMap)) 2707 mempoolTxsAdded, err := mempool.processTransaction( 2708 burnTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 2709 true /*verifySignatures*/) 2710 require.NoErrorf(err, "on index: %v", ii) 2711 require.Equal(1, len(mempoolTxsAdded)) 2712 } 2713 } 2714 2715 // The balances according to the mempool after applying all the transactions 2716 // should be correct. 2717 { 2718 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 2719 require.NoError(err) 2720 totalBalance := uint64(0) 2721 for _, utxoEntry := range utxoEntries { 2722 totalBalance += utxoEntry.AmountNanos 2723 } 2724 assert.Equal(int64(35556076477), int64(totalBalance)) 2725 } 2726 { 2727 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 2728 require.NoError(err) 2729 assert.Equal(int64(9718572674), int64(utxoEntries[0].AmountNanos)) 2730 } 2731 { 2732 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 2733 require.NoError(err) 2734 totalBalance := uint64(0) 2735 for _, utxoEntry := range utxoEntries { 2736 totalBalance += utxoEntry.AmountNanos 2737 } 2738 assert.Equal(int64(9922118448), int64(totalBalance)) 2739 } 2740 2741 // Remove all the transactions from the mempool. 2742 for _, burnTxn := range bitcoinExchangeTxns { 2743 mempool.inefficientRemoveTransaction(burnTxn) 2744 } 2745 2746 // The balances should be zero after removing transactions from the mempool. 2747 { 2748 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, mempool, nil) 2749 require.NoError(err) 2750 require.Equal(0, len(utxoEntries)) 2751 } 2752 { 2753 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, mempool, nil) 2754 require.NoError(err) 2755 require.Equal(0, len(utxoEntries)) 2756 } 2757 { 2758 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, mempool, nil) 2759 require.NoError(err) 2760 require.Equal(0, len(utxoEntries)) 2761 } 2762 2763 // Re-add all of the transactions to the mempool so we can mine them into a block. 2764 { 2765 for _, burnTxn := range bitcoinExchangeTxns { 2766 mempoolTxsAdded, err := mempool.processTransaction( 2767 burnTxn, true /*allowUnconnectedTxn*/, true /*rateLimit*/, 0, /*peerID*/ 2768 true /*verifySignatures*/) 2769 require.NoError(err) 2770 require.Equal(1, len(mempoolTxsAdded)) 2771 //require.Equal(0, len(mempool.immatureBitcoinTxns)) 2772 } 2773 } 2774 2775 miner.params = paramsCopy 2776 miner.BlockProducer.params = paramsCopy 2777 // All the txns should be in the mempool already so mining a block should put 2778 // all those transactions in it. Note we need to mine two blocks since the first 2779 // one just makes the DeSo chain time-current. 2780 finalBlock1, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 2781 require.NoError(err) 2782 _ = finalBlock1 2783 finalBlock2, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 2784 require.NoError(err) 2785 2786 finalBlock3, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 2787 require.NoError(err) 2788 2789 finalBlock4, err := miner.MineAndProcessSingleBlock(0 /*threadIndex*/, mempool) 2790 require.NoError(err) 2791 2792 // Add one for the block reward. Now we have a meaty block. 2793 assert.Equal(len(finalBlock1.Txns), 1) 2794 assert.Equal(len(finalBlock2.Txns), 14) 2795 assert.Equal(len(finalBlock3.Txns), 1) 2796 require.Equal(len(finalBlock4.Txns), 1) 2797 2798 // The balances after mining the block should line up. 2799 { 2800 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 2801 require.NoError(err) 2802 totalBalance := uint64(0) 2803 for _, utxoEntry := range utxoEntries { 2804 totalBalance += utxoEntry.AmountNanos 2805 } 2806 assert.Equal(int64(35556076477), int64(totalBalance)) 2807 } 2808 { 2809 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 2810 require.NoError(err) 2811 assert.Equal(int64(9718572674), int64(utxoEntries[0].AmountNanos)) 2812 } 2813 { 2814 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 2815 require.NoError(err) 2816 totalBalance := uint64(0) 2817 for _, utxoEntry := range utxoEntries { 2818 totalBalance += utxoEntry.AmountNanos 2819 } 2820 assert.Equal(int64(9922118448), int64(totalBalance)) 2821 } 2822 2823 // Roll back the blocks and make sure we don't hit any errors. 2824 { 2825 utxoView, err := NewUtxoView(db, paramsCopy, nil) 2826 require.NoError(err) 2827 2828 { 2829 // Fetch the utxo operations for the block we're detaching. We need these 2830 // in order to be able to detach the block. 2831 hash, err := finalBlock4.Header.Hash() 2832 require.NoError(err) 2833 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 2834 require.NoError(err) 2835 2836 // Compute the hashes for all the transactions. 2837 txHashes, err := ComputeTransactionHashes(finalBlock4.Txns) 2838 require.NoError(err) 2839 require.NoError(utxoView.DisconnectBlock(finalBlock4, txHashes, utxoOps)) 2840 } 2841 { 2842 // Fetch the utxo operations for the block we're detaching. We need these 2843 // in order to be able to detach the block. 2844 hash, err := finalBlock3.Header.Hash() 2845 require.NoError(err) 2846 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 2847 require.NoError(err) 2848 2849 // Compute the hashes for all the transactions. 2850 txHashes, err := ComputeTransactionHashes(finalBlock3.Txns) 2851 require.NoError(err) 2852 require.NoError(utxoView.DisconnectBlock(finalBlock3, txHashes, utxoOps)) 2853 } 2854 { 2855 // Fetch the utxo operations for the block we're detaching. We need these 2856 // in order to be able to detach the block. 2857 hash, err := finalBlock2.Header.Hash() 2858 require.NoError(err) 2859 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 2860 require.NoError(err) 2861 2862 // Compute the hashes for all the transactions. 2863 txHashes, err := ComputeTransactionHashes(finalBlock2.Txns) 2864 require.NoError(err) 2865 require.NoError(utxoView.DisconnectBlock(finalBlock2, txHashes, utxoOps)) 2866 } 2867 { 2868 // Fetch the utxo operations for the block we're detaching. We need these 2869 // in order to be able to detach the block. 2870 hash, err := finalBlock1.Header.Hash() 2871 require.NoError(err) 2872 utxoOps, err := GetUtxoOperationsForBlock(db, hash) 2873 require.NoError(err) 2874 2875 // Compute the hashes for all the transactions. 2876 txHashes, err := ComputeTransactionHashes(finalBlock1.Txns) 2877 require.NoError(err) 2878 require.NoError(utxoView.DisconnectBlock(finalBlock1, txHashes, utxoOps)) 2879 } 2880 2881 // Flushing the view after applying and rolling back should work. 2882 require.NoError(utxoView.FlushToDb()) 2883 } 2884 2885 // The balances according to the db after applying and unapplying all the 2886 // transactions to a view with a flush at the end should be zero. 2887 { 2888 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes1, nil, nil) 2889 require.NoError(err) 2890 require.Equal(0, len(utxoEntries)) 2891 } 2892 { 2893 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes2, nil, nil) 2894 require.NoError(err) 2895 require.Equal(0, len(utxoEntries)) 2896 } 2897 { 2898 utxoEntries, err := chain.GetSpendableUtxosForPublicKey(pkBytes3, nil, nil) 2899 require.NoError(err) 2900 require.Equal(0, len(utxoEntries)) 2901 } 2902 2903 _, _, _, _, _, _ = db, mempool, miner, bitcoinBlocks, bitcoinHeaders, bitcoinHeaderHeights 2904 } 2905 2906 func TestUpdateExchangeRate(t *testing.T) { 2907 // Set up a blockchain 2908 assert := assert.New(t) 2909 require := require.New(t) 2910 _, _ = assert, require 2911 2912 chain, params, db := NewLowDifficultyBlockchain() 2913 mempool, miner := NewTestMiner(t, chain, params, true /*isSender*/) 2914 _, _ = mempool, miner 2915 2916 // Set the founder equal to the moneyPk 2917 params.ParamUpdaterPublicKeys = make(map[PkMapKey]bool) 2918 params.ParamUpdaterPublicKeys[MakePkMapKey(MustBase58CheckDecode(moneyPkString))] = true 2919 2920 // Send money to m0 from moneyPk 2921 _, _, _ = _doBasicTransferWithViewFlush( 2922 t, chain, db, params, moneyPkString, m0Pub, 2923 moneyPrivString, 6*NanosPerUnit /*amount to send*/, 11 /*feerate*/) 2924 2925 // Should fail when founder key is not equal to moneyPk 2926 { 2927 newUSDCentsPerBitcoin := uint64(27000 * 100) 2928 _, _, _, err := _updateUSDCentsPerBitcoinExchangeRate( 2929 t, chain, db, params, 100, /*feeRateNanosPerKB*/ 2930 m0Pub, 2931 m0Priv, 2932 newUSDCentsPerBitcoin) 2933 require.Error(err) 2934 require.Contains(err.Error(), RuleErrorUserNotAuthorizedToUpdateExchangeRate) 2935 } 2936 2937 // Should pass when founder key is equal to moneyPk 2938 var updateExchangeRateTxn *MsgDeSoTxn 2939 var err error 2940 { 2941 newUSDCentsPerBitcoin := uint64(27000 * 100) 2942 _, updateExchangeRateTxn, _, err = _updateUSDCentsPerBitcoinExchangeRate( 2943 t, chain, db, params, 100, /*feeRateNanosPerKB*/ 2944 moneyPkString, 2945 moneyPrivString, 2946 newUSDCentsPerBitcoin) 2947 require.NoError(err) 2948 2949 utxoView, err := NewUtxoView(db, params, nil) 2950 require.NoError(err) 2951 txnSize := getTxnSize(*updateExchangeRateTxn) 2952 blockHeight := chain.blockTip().Height + 1 2953 utxoOps, totalInput, totalOutput, fees, err := 2954 utxoView.ConnectTransaction(updateExchangeRateTxn, 2955 updateExchangeRateTxn.Hash(), txnSize, blockHeight, true, /*verifySignature*/ 2956 false /*ignoreUtxos*/) 2957 require.NoError(err) 2958 _, _, _, _ = utxoOps, totalInput, totalOutput, fees 2959 require.NoError(utxoView.FlushToDb()) 2960 2961 // Check the balance of the updater after this txn 2962 require.NotEqual(0, _getBalance(t, chain, nil, moneyPkString)) 2963 } 2964 }