kaspad/testing/integration/selected_parent_chain_test.go
stasatdaglabs 21a459c0f4
Implement virtual selected parent chain RPC methods (#1249)
* [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.
2020-12-21 14:43:32 +02:00

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)
}
}