mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00

* [NOD-1579] Rename AcceptedTxIDs to AcceptedTransactionIDs. * [NOD-1579] Add InsertBlockResult to ValidateAndInsertBlock results. * [NOD-1593] Rename InsertBlockResult to BlockInsertionResult. * [NOD-1593] Add SelectedParentChainChanges to AddBlockToVirtual's result. * [NOD-1593] Implement findSelectedParentChainChanges. * [NOD-1593] Implement TestFindSelectedParentChainChanges. * [NOD-1593] Fix a string. * [NOD-1593] Finish implementing TestFindSelectedParentChainChanges. * [NOD-1593] Fix merge errors. * [NOD-1597] Begin implementing UTXOIndex. * [NOD-1597] Connect UTXOIndex to RPC. * [NOD-1597] Connect Consensus to UTXOIndex. * [NOD-1597] Add AcceptanceData to BlockInfo. * [NOD-1597] Implement UTXOIndex.Update(). * [NOD-1597] Implement add(), remove(), and discard() in utxoIndexStore. * [NOD-1597] Add error cases to add() and remove(). * [NOD-1597] Add special cases to add() and remove(). * [NOD-1597] Implement commit. * [NOD-1597] Add a mutex around UTXOIndex.Update(). * [NOD-1597] Return changes to the UTXO from Update(). * [NOD-1597] Add NotifyUTXOsChangedRequestMessage and related structs. * [NOD-1597] Implement HandleNotifyUTXOsChanged. * [NOD-1597] Begin implementing TestUTXOIndex. * [NOD-1597] Implement RegisterForUTXOsChangedNotifications. * [NOD-1597] Fix bad transaction.ID usage. * [NOD-1597] Implement convertUTXOChangesToUTXOsChangedNotification. * [NOD-1597] Make UTXOsChangedNotificationMessage.Removed UTXOsByAddressesEntry instead of just RPCOutpoint so that the client can discern which address was the UTXO removed for. * [NOD-1597] Collect outpoints in TestUTXOIndex. * [NOD-1597] Rename RPC stuff. * [NOD-1597] Add messages for GetUTXOsByAddresses. * [NOD-1597] Implement HandleGetUTXOsByAddresses. * [NOD-1597] Implement GetUTXOsByAddresses. * [NOD-1597] Implement UTXOs(). * [NOD-1597] Implement getUTXOOutpointEntryPairs(). * [NOD-1597] Expand TestUTXOIndex. * [NOD-1597] Convert SubmitTransaction to use RPCTransaction instead of MsgTx. * [NOD-1597] Finish implementing TestUTXOIndex. * [NOD-1597] Add messages for GetVirtualSelectedParentBlueScore. * [NOD-1597] Implement HandleGetVirtualSelectedParentBlueScore and GetVirtualSelectedParentBlueScore. * [NOD-1597] Implement TestVirtualSelectedParentBlueScore. * [NOD-1597] Implement NotifyVirtualSelectedParentBlueScoreChanged. * [NOD-1597] Expand TestVirtualSelectedParentBlueScore. * [NOD-1597] Implement notifyVirtualSelectedParentBlueScoreChanged. * [NOD-1597] Make go lint happy. * [NOD-1593] Fix merge errors. * [NOD-1593] Rename findSelectedParentChainChanges to calculateSelectedParentChainChanges. * [NOD-1593] Expand TestCalculateSelectedParentChainChanges. * [NOD-1597] Add logs to utxoindex.go. * [NOD-1597] Add logs to utxoindex/store.go. * [NOD-1597] Add logs to RPCManager.NotifyXXX functions. * Implement notifySelectedParentChainChanged. * Implement TestSelectedParentChain. * Rename NotifyChainChanged to NotifyVirtualSelectedParentChainChanged. * Rename GetChainFromBlock to GetVirtualSelectedParentChainFromBlock. * Remove AcceptanceIndex from the config. * Implement HandleGetVirtualSelectedParentChainFromBlock. * Expand TestVirtualSelectedParentChain. * Fix merge errors. * Add a comment. * Move a comment.
131 lines
5.4 KiB
Go
131 lines
5.4 KiB
Go
package integration
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"github.com/kaspanet/kaspad/app/appmessage"
|
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
|
"testing"
|
|
)
|
|
|
|
func TestVirtualSelectedParentChain(t *testing.T) {
|
|
// Setup a couple of kaspad instances
|
|
kaspad1, kaspad2, _, teardown := standardSetup(t)
|
|
defer teardown()
|
|
|
|
// Register to virtual selected parent chain changes
|
|
onVirtualSelectedParentChainChangedChan := make(chan *appmessage.VirtualSelectedParentChainChangedNotificationMessage)
|
|
err := kaspad1.rpcClient.RegisterForVirtualSelectedParentChainChangedNotifications(
|
|
func(notification *appmessage.VirtualSelectedParentChainChangedNotificationMessage) {
|
|
onVirtualSelectedParentChainChangedChan <- notification
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to register for virtual selected parent chain change notifications: %s", err)
|
|
}
|
|
|
|
// In kaspad1, mine a chain over the genesis and make sure
|
|
// each chain changed notifications contains only one entry
|
|
// in `added` and nothing in `removed`
|
|
chain1TipHash := consensushashing.BlockHash(kaspad1.config.NetParams().GenesisBlock)
|
|
chain1TipHashHex := hex.EncodeToString(chain1TipHash[:])
|
|
const blockAmountToMine = 10
|
|
for i := 0; i < blockAmountToMine; i++ {
|
|
minedBlock := mineNextBlock(t, kaspad1)
|
|
notification := <-onVirtualSelectedParentChainChangedChan
|
|
if len(notification.RemovedChainBlockHashes) > 0 {
|
|
t.Fatalf("RemovedChainBlockHashes is unexpectedly not empty")
|
|
}
|
|
if len(notification.AddedChainBlocks) != 1 {
|
|
t.Fatalf("Unexpected length of AddedChainBlocks. Want: %d, got: %d",
|
|
1, len(notification.AddedChainBlocks))
|
|
}
|
|
|
|
minedBlockHash := consensushashing.BlockHash(minedBlock)
|
|
minedBlockHashHex := hex.EncodeToString(minedBlockHash[:])
|
|
if minedBlockHashHex != notification.AddedChainBlocks[0].Hash {
|
|
t.Fatalf("Unexpected block hash in AddedChainBlocks. Want: %s, got: %s",
|
|
minedBlockHashHex, notification.AddedChainBlocks[0].Hash)
|
|
}
|
|
chain1TipHashHex = minedBlockHashHex
|
|
}
|
|
|
|
// In kaspad2, mine a different chain of `blockAmountToMine`
|
|
// blocks over the genesis
|
|
for i := 0; i < blockAmountToMine; i++ {
|
|
mineNextBlock(t, kaspad2)
|
|
}
|
|
|
|
// Connect the two kaspads
|
|
connect(t, kaspad1, kaspad2)
|
|
|
|
// In kaspad2, mine another block. This should trigger sync
|
|
// between the two nodes
|
|
chain2Tip := mineNextBlock(t, kaspad2)
|
|
chain2TipHash := consensushashing.BlockHash(chain2Tip)
|
|
chain2TipHashHex := hex.EncodeToString(chain2TipHash[:])
|
|
|
|
// For the first `blockAmountToMine - 1` blocks we don't expect
|
|
// the chain to change at all
|
|
for i := 0; i < blockAmountToMine-1; i++ {
|
|
notification := <-onVirtualSelectedParentChainChangedChan
|
|
if len(notification.RemovedChainBlockHashes) > 0 {
|
|
t.Fatalf("RemovedChainBlockHashes is unexpectedly not empty")
|
|
}
|
|
if len(notification.AddedChainBlocks) > 0 {
|
|
t.Fatalf("AddedChainBlocks is unexpectedly not empty")
|
|
}
|
|
}
|
|
|
|
// Either the next block could cause a reorg or the one
|
|
// after it
|
|
potentialReorgNotification1 := <-onVirtualSelectedParentChainChangedChan
|
|
potentialReorgNotification2 := <-onVirtualSelectedParentChainChangedChan
|
|
var reorgNotification *appmessage.VirtualSelectedParentChainChangedNotificationMessage
|
|
var nonReorgNotification *appmessage.VirtualSelectedParentChainChangedNotificationMessage
|
|
if len(potentialReorgNotification1.RemovedChainBlockHashes) > 0 {
|
|
reorgNotification = potentialReorgNotification1
|
|
nonReorgNotification = potentialReorgNotification2
|
|
} else {
|
|
reorgNotification = potentialReorgNotification2
|
|
nonReorgNotification = potentialReorgNotification1
|
|
}
|
|
|
|
// Make sure that the non-reorg notification has nothing
|
|
// in `removed`
|
|
if len(nonReorgNotification.RemovedChainBlockHashes) > 0 {
|
|
t.Fatalf("nonReorgNotification.RemovedChainBlockHashes is unexpectedly not empty")
|
|
}
|
|
|
|
// Make sure that the reorg notification contains exactly
|
|
// `blockAmountToMine` blocks in its `removed`
|
|
if len(reorgNotification.RemovedChainBlockHashes) != blockAmountToMine {
|
|
t.Fatalf("Unexpected length of reorgNotification.RemovedChainBlockHashes. Want: %d, got: %d",
|
|
blockAmountToMine, len(reorgNotification.RemovedChainBlockHashes))
|
|
}
|
|
|
|
// Get the virtual selected parent chain from the tip of
|
|
// the first chain
|
|
virtualSelectedParentChainFromChain1Tip, err := kaspad1.rpcClient.GetVirtualSelectedParentChainFromBlock(chain1TipHashHex)
|
|
if err != nil {
|
|
t.Fatalf("GetVirtualSelectedParentChainFromBlock failed: %s", err)
|
|
}
|
|
|
|
// Make sure that `blockAmountToMine` blocks were removed
|
|
// and `blockAmountToMine + 1` blocks were added
|
|
if len(virtualSelectedParentChainFromChain1Tip.RemovedChainBlockHashes) != blockAmountToMine {
|
|
t.Fatalf("Unexpected length of virtualSelectedParentChainFromChain1Tip.RemovedChainBlockHashes. Want: %d, got: %d",
|
|
blockAmountToMine, len(virtualSelectedParentChainFromChain1Tip.RemovedChainBlockHashes))
|
|
}
|
|
if len(virtualSelectedParentChainFromChain1Tip.AddedChainBlocks) != blockAmountToMine+1 {
|
|
t.Fatalf("Unexpected length of virtualSelectedParentChainFromChain1Tip.AddedChainBlocks. Want: %d, got: %d",
|
|
blockAmountToMine+1, len(virtualSelectedParentChainFromChain1Tip.AddedChainBlocks))
|
|
}
|
|
|
|
// Make sure that the last block in `added` is the tip
|
|
// of chain2
|
|
lastAddedChainBlock := virtualSelectedParentChainFromChain1Tip.AddedChainBlocks[len(virtualSelectedParentChainFromChain1Tip.AddedChainBlocks)-1]
|
|
if lastAddedChainBlock.Hash != chain2TipHashHex {
|
|
t.Fatalf("Unexpected last added chain block. Want: %s, got: %s",
|
|
chain2TipHashHex, lastAddedChainBlock.Hash)
|
|
}
|
|
}
|