mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-07 14:46:44 +00:00
Test validateAndInsertPruningPoint (#1420)
* Add TestValidateAndInsertPruningPoint * Check fake UTXO set and validate that the pruning point changed
This commit is contained in:
parent
0769705b37
commit
799eb7515c
@ -0,0 +1,219 @@
|
|||||||
|
package blockprocessor_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxoserialization"
|
||||||
|
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValidateAndInsertPruningPoint(t *testing.T) {
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||||
|
// This is done to reduce the pruning depth to 6 blocks
|
||||||
|
finalityDepth := 3
|
||||||
|
params.FinalityDuration = time.Duration(finalityDepth) * params.TargetTimePerBlock
|
||||||
|
params.K = 0
|
||||||
|
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
|
||||||
|
tcSyncer, teardownSyncer, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncer")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up tcSyncer: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardownSyncer(false)
|
||||||
|
|
||||||
|
tcSyncee, teardownSyncee, err := factory.NewTestConsensus(params, false, "TestValidateAndInsertPruningPointSyncee")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up tcSyncee: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardownSyncee(false)
|
||||||
|
|
||||||
|
addBlock := func(parentHashes []*externalapi.DomainHash) *externalapi.DomainHash {
|
||||||
|
block, _, err := tcSyncer.BuildBlockWithParents(parentHashes, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildBlockWithParents: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tcSyncer.ValidateAndInsertBlock(block)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tcSyncee.ValidateAndInsertBlock(&externalapi.DomainBlock{
|
||||||
|
Header: block.Header,
|
||||||
|
Transactions: nil,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return consensushashing.BlockHash(block)
|
||||||
|
}
|
||||||
|
|
||||||
|
tipHash := params.GenesisHash
|
||||||
|
for i := 0; i < finalityDepth-2; i++ {
|
||||||
|
tipHash = addBlock([]*externalapi.DomainHash{tipHash})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add block in the anticone of the pruning point to test such situation
|
||||||
|
pruningPointAnticoneBlock := addBlock([]*externalapi.DomainHash{tipHash})
|
||||||
|
tipHash = addBlock([]*externalapi.DomainHash{tipHash})
|
||||||
|
nextPruningPoint := addBlock([]*externalapi.DomainHash{tipHash})
|
||||||
|
|
||||||
|
tipHash = addBlock([]*externalapi.DomainHash{pruningPointAnticoneBlock, nextPruningPoint})
|
||||||
|
|
||||||
|
// Add blocks until the pruning point changes
|
||||||
|
for {
|
||||||
|
tipHash = addBlock([]*externalapi.DomainHash{tipHash})
|
||||||
|
|
||||||
|
pruningPoint, err := tcSyncer.PruningPoint()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("PruningPoint: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pruningPoint.Equal(params.GenesisHash) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pruningPoint, err := tcSyncer.PruningPoint()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("PruningPoint: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pruningPoint.Equal(nextPruningPoint) {
|
||||||
|
t.Fatalf("Unexpected pruning point %s", pruningPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
pruningPointUTXOSet, err := tcSyncer.GetPruningPointUTXOSet(pruningPoint)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetPruningPointUTXOSet: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tip, err := tcSyncer.GetBlock(tipHash)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetBlock: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that ValidateAndInsertPruningPoint fails for invalid pruning point
|
||||||
|
err = tcSyncee.ValidateAndInsertPruningPoint(tip, pruningPointUTXOSet)
|
||||||
|
if !errors.Is(err, ruleerrors.ErrUnexpectedPruningPoint) {
|
||||||
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pruningPointBlock, err := tcSyncer.GetBlock(pruningPoint)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetBlock: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
invalidPruningPointBlock := pruningPointBlock.Clone()
|
||||||
|
invalidPruningPointBlock.Transactions[0].Version += 1
|
||||||
|
|
||||||
|
// Check that ValidateAndInsertPruningPoint fails for invalid block
|
||||||
|
err = tcSyncee.ValidateAndInsertPruningPoint(invalidPruningPointBlock, pruningPointUTXOSet)
|
||||||
|
if !errors.Is(err, ruleerrors.ErrBadMerkleRoot) {
|
||||||
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedFakeUTXOSet, err := makeSerializedFakeUTXOSet()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("makeSerializedFakeUTXOSet: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that ValidateAndInsertPruningPoint fails if the UTXO commitment doesn't fit the provided UTXO set.
|
||||||
|
err = tcSyncee.ValidateAndInsertPruningPoint(pruningPointBlock, serializedFakeUTXOSet)
|
||||||
|
if !errors.Is(err, ruleerrors.ErrBadPruningPointUTXOSet) {
|
||||||
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that ValidateAndInsertPruningPoint works given the right arguments.
|
||||||
|
err = tcSyncee.ValidateAndInsertPruningPoint(pruningPointBlock, pruningPointUTXOSet)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ValidateAndInsertPruningPoint: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
virtualSelectedParent, err := tcSyncer.GetVirtualSelectedParent()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetVirtualSelectedParent: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
missingBlockBodyHashes, err := tcSyncee.GetMissingBlockBodyHashes(virtualSelectedParent)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetMissingBlockBodyHashes: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, missingHash := range missingBlockBodyHashes {
|
||||||
|
block, err := tcSyncer.GetBlock(missingHash)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetBlock: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = tcSyncee.ValidateAndInsertBlock(block)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synceeTips, err := tcSyncee.Tips()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Tips: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
syncerTips, err := tcSyncer.Tips()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Tips: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !externalapi.HashesEqual(synceeTips, syncerTips) {
|
||||||
|
t.Fatalf("Syncee's tips are %s while syncer's are %s", synceeTips, syncerTips)
|
||||||
|
}
|
||||||
|
|
||||||
|
synceePruningPoint, err := tcSyncee.PruningPoint()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("PruningPoint: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !synceePruningPoint.Equal(pruningPoint) {
|
||||||
|
t.Fatalf("The syncee pruning point has not changed as exepcted")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type fakeUTXOSetIterator struct {
|
||||||
|
nextCalled bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeUTXOSetIterator) Next() bool {
|
||||||
|
if f.nextCalled {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
f.nextCalled = true
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeUTXOSetIterator) Get() (outpoint *externalapi.DomainOutpoint, utxoEntry externalapi.UTXOEntry, err error) {
|
||||||
|
return &externalapi.DomainOutpoint{
|
||||||
|
TransactionID: *externalapi.NewDomainTransactionIDFromByteArray(&[externalapi.DomainHashSize]byte{0x01}),
|
||||||
|
Index: 0,
|
||||||
|
}, utxo.NewUTXOEntry(1000, &externalapi.ScriptPublicKey{
|
||||||
|
Script: []byte{1, 2, 3},
|
||||||
|
Version: 0,
|
||||||
|
}, false, 2000), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSerializedFakeUTXOSet() ([]byte, error) {
|
||||||
|
serializedUtxo, err := utxoserialization.ReadOnlyUTXOSetToProtoUTXOSet(&fakeUTXOSetIterator{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return proto.Marshal(serializedUtxo)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user