mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-06-09 23:56:42 +00:00
Hard fork - new genesis with the utxo set of the last block (#1856)
* UTXO dump of block 0fca37ca667c2d550a6c4416dad9717e50927128c424fa4edbebc436ab13aeef * Activate HF immediately and change reward to 1000 * Change protocol version and datadir location * Delete comments * Fix zero hash to muhash zero hash in genesis utxo dump check * Don't omit genesis as direct parent * Fix tests * Change subsidy to 500 * Dont assume genesis multiset is empty * Fix BlockReward test * Fix TestValidateAndInsertImportedPruningPoint test * Fix pruning point genesis utxo set * Fix tests related to mainnet utxo set * Dont change the difficulty before you have a full window * Fix TestBlockWindow tests * Remove global utxo set variable, and persist mainnetnet utxo deserialization between runs * Fix last tests * Make peer banning opt-in * small fix for a test * Fix go lint * Fix Ori's review comments * Change DAA score of genesis to checkpoint DAA score and fix all tests * Fix the BlockLevel bits counting * Fix some tests and make them run a little faster * Change datadir name back to kaspa-mainnet and change db path from /data to /datadir * Last changes for the release and change the version to 0.11.5 Co-authored-by: Ori Newman <orinewman1@gmail.com> Co-authored-by: Ori Newman <> Co-authored-by: msutton <mikisiton2@gmail.com>
This commit is contained in:
parent
2a1b38ce7a
commit
dbf18d8052
@ -20,7 +20,10 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/version"
|
"github.com/kaspanet/kaspad/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const leveldbCacheSizeMiB = 256
|
const (
|
||||||
|
leveldbCacheSizeMiB = 256
|
||||||
|
defaultDataDirname = "datadir"
|
||||||
|
)
|
||||||
|
|
||||||
var desiredLimits = &limits.DesiredLimits{
|
var desiredLimits = &limits.DesiredLimits{
|
||||||
FileLimitWant: 2048,
|
FileLimitWant: 2048,
|
||||||
@ -159,7 +162,7 @@ func (app *kaspadApp) main(startedChan chan<- struct{}) error {
|
|||||||
|
|
||||||
// dbPath returns the path to the block database given a database type.
|
// dbPath returns the path to the block database given a database type.
|
||||||
func databasePath(cfg *config.Config) string {
|
func databasePath(cfg *config.Config) string {
|
||||||
return filepath.Join(cfg.AppDir, "data")
|
return filepath.Join(cfg.AppDir, defaultDataDirname)
|
||||||
}
|
}
|
||||||
|
|
||||||
func removeDatabase(cfg *config.Config) error {
|
func removeDatabase(cfg *config.Config) error {
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// ProtocolVersion is the latest protocol version this package supports.
|
// ProtocolVersion is the latest protocol version this package supports.
|
||||||
ProtocolVersion uint32 = 1
|
ProtocolVersion uint32 = 2
|
||||||
|
|
||||||
// DefaultServices describes the default services that are supported by
|
// DefaultServices describes the default services that are supported by
|
||||||
// the server.
|
// the server.
|
||||||
|
@ -102,7 +102,7 @@ func (m *Manager) routerInitializer(router *routerpkg.Router, netConnection *net
|
|||||||
|
|
||||||
func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection, outgoingRoute *routerpkg.Route) {
|
func (m *Manager) handleError(err error, netConnection *netadapter.NetConnection, outgoingRoute *routerpkg.Route) {
|
||||||
if protocolErr := (protocolerrors.ProtocolError{}); errors.As(err, &protocolErr) {
|
if protocolErr := (protocolerrors.ProtocolError{}); errors.As(err, &protocolErr) {
|
||||||
if !m.context.Config().DisableBanning && protocolErr.ShouldBan {
|
if m.context.Config().EnableBanning && protocolErr.ShouldBan {
|
||||||
log.Warnf("Banning %s (reason: %s)", netConnection, protocolErr.Cause)
|
log.Warnf("Banning %s (reason: %s)", netConnection, protocolErr.Cause)
|
||||||
|
|
||||||
err := m.context.ConnectionManager().Ban(netConnection)
|
err := m.context.ConnectionManager().Ban(netConnection)
|
||||||
|
@ -159,7 +159,7 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
|||||||
dagTraversalManager := dagTraversalManagers[0]
|
dagTraversalManager := dagTraversalManagers[0]
|
||||||
|
|
||||||
// Processes
|
// Processes
|
||||||
parentsManager := parentssanager.New(config.GenesisHash, config.HardForkOmitGenesisFromParentsDAAScore)
|
parentsManager := parentssanager.New(config.GenesisHash)
|
||||||
blockParentBuilder := blockparentbuilder.New(
|
blockParentBuilder := blockparentbuilder.New(
|
||||||
dbManager,
|
dbManager,
|
||||||
blockHeaderStore,
|
blockHeaderStore,
|
||||||
@ -168,7 +168,6 @@ func (f *factory) NewConsensus(config *Config, db infrastructuredatabase.Databas
|
|||||||
reachabilityDataStore,
|
reachabilityDataStore,
|
||||||
pruningStore,
|
pruningStore,
|
||||||
|
|
||||||
config.HardForkOmitGenesisFromParentsDAAScore,
|
|
||||||
config.GenesisHash,
|
config.GenesisHash,
|
||||||
)
|
)
|
||||||
pastMedianTimeManager := f.pastMedianTimeConsructor(
|
pastMedianTimeManager := f.pastMedianTimeConsructor(
|
||||||
|
@ -16,8 +16,8 @@ import (
|
|||||||
|
|
||||||
func TestFinality(t *testing.T) {
|
func TestFinality(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
// Set finalityInterval to 50 blocks, so that test runs quickly
|
// Set finalityInterval to 20 blocks, so that test runs quickly
|
||||||
consensusConfig.FinalityDuration = 50 * consensusConfig.TargetTimePerBlock
|
consensusConfig.FinalityDuration = 20 * consensusConfig.TargetTimePerBlock
|
||||||
|
|
||||||
factory := consensus.NewFactory()
|
factory := consensus.NewFactory()
|
||||||
consensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestFinality")
|
consensus, teardown, err := factory.NewTestConsensus(consensusConfig, "TestFinality")
|
||||||
@ -180,7 +180,8 @@ func TestFinality(t *testing.T) {
|
|||||||
func TestBoundedMergeDepth(t *testing.T) {
|
func TestBoundedMergeDepth(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
// Set finalityInterval to 50 blocks, so that test runs quickly
|
// Set finalityInterval to 50 blocks, so that test runs quickly
|
||||||
consensusConfig.FinalityDuration = 50 * consensusConfig.TargetTimePerBlock
|
consensusConfig.K = 5
|
||||||
|
consensusConfig.FinalityDuration = 7 * consensusConfig.TargetTimePerBlock
|
||||||
finalityInterval := int(consensusConfig.FinalityDepth())
|
finalityInterval := int(consensusConfig.FinalityDepth())
|
||||||
|
|
||||||
if int(consensusConfig.K) >= finalityInterval {
|
if int(consensusConfig.K) >= finalityInterval {
|
||||||
|
@ -16,8 +16,7 @@ type blockParentBuilder struct {
|
|||||||
reachabilityDataStore model.ReachabilityDataStore
|
reachabilityDataStore model.ReachabilityDataStore
|
||||||
pruningStore model.PruningStore
|
pruningStore model.PruningStore
|
||||||
|
|
||||||
hardForkOmitGenesisFromParentsDAAScore uint64
|
genesisHash *externalapi.DomainHash
|
||||||
genesisHash *externalapi.DomainHash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new instance of a BlockParentBuilder
|
// New creates a new instance of a BlockParentBuilder
|
||||||
@ -30,7 +29,6 @@ func New(
|
|||||||
reachabilityDataStore model.ReachabilityDataStore,
|
reachabilityDataStore model.ReachabilityDataStore,
|
||||||
pruningStore model.PruningStore,
|
pruningStore model.PruningStore,
|
||||||
|
|
||||||
hardForkOmitGenesisFromParentsDAAScore uint64,
|
|
||||||
genesisHash *externalapi.DomainHash,
|
genesisHash *externalapi.DomainHash,
|
||||||
) model.BlockParentBuilder {
|
) model.BlockParentBuilder {
|
||||||
return &blockParentBuilder{
|
return &blockParentBuilder{
|
||||||
@ -39,10 +37,9 @@ func New(
|
|||||||
dagTopologyManager: dagTopologyManager,
|
dagTopologyManager: dagTopologyManager,
|
||||||
parentsManager: parentsManager,
|
parentsManager: parentsManager,
|
||||||
|
|
||||||
reachabilityDataStore: reachabilityDataStore,
|
reachabilityDataStore: reachabilityDataStore,
|
||||||
pruningStore: pruningStore,
|
pruningStore: pruningStore,
|
||||||
hardForkOmitGenesisFromParentsDAAScore: hardForkOmitGenesisFromParentsDAAScore,
|
genesisHash: genesisHash,
|
||||||
genesisHash: genesisHash,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,8 +214,10 @@ func (bpb *blockParentBuilder) BuildParents(stagingArea *model.StagingArea,
|
|||||||
|
|
||||||
parents := make([]externalapi.BlockLevelParents, 0, len(candidatesByLevelToReferenceBlocksMap))
|
parents := make([]externalapi.BlockLevelParents, 0, len(candidatesByLevelToReferenceBlocksMap))
|
||||||
for blockLevel := 0; blockLevel < len(candidatesByLevelToReferenceBlocksMap); blockLevel++ {
|
for blockLevel := 0; blockLevel < len(candidatesByLevelToReferenceBlocksMap); blockLevel++ {
|
||||||
if _, ok := candidatesByLevelToReferenceBlocksMap[blockLevel][*bpb.genesisHash]; daaScore >= bpb.hardForkOmitGenesisFromParentsDAAScore && ok && len(candidatesByLevelToReferenceBlocksMap[blockLevel]) == 1 {
|
if blockLevel > 0 {
|
||||||
break
|
if _, ok := candidatesByLevelToReferenceBlocksMap[blockLevel][*bpb.genesisHash]; ok && len(candidatesByLevelToReferenceBlocksMap[blockLevel]) == 1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
levelBlocks := make(externalapi.BlockLevelParents, 0, len(candidatesByLevelToReferenceBlocksMap[blockLevel]))
|
levelBlocks := make(externalapi.BlockLevelParents, 0, len(candidatesByLevelToReferenceBlocksMap[blockLevel]))
|
||||||
|
BIN
domain/consensus/processes/blockprocessor/resources/utxos.gz
Normal file
BIN
domain/consensus/processes/blockprocessor/resources/utxos.gz
Normal file
Binary file not shown.
@ -1,12 +1,20 @@
|
|||||||
package blockprocessor
|
package blockprocessor
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"github.com/kaspanet/go-muhash"
|
||||||
|
|
||||||
|
// we need to embed the utxoset of mainnet genesis here
|
||||||
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/multiset"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/util/staging"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/util/difficulty"
|
"github.com/kaspanet/kaspad/util/difficulty"
|
||||||
|
"github.com/kaspanet/kaspad/util/staging"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
@ -16,6 +24,9 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//go:embed resources/utxos.gz
|
||||||
|
var utxoDumpFile []byte
|
||||||
|
|
||||||
func (bp *blockProcessor) setBlockStatusAfterBlockValidation(
|
func (bp *blockProcessor) setBlockStatusAfterBlockValidation(
|
||||||
stagingArea *model.StagingArea, block *externalapi.DomainBlock, isPruningPoint bool) error {
|
stagingArea *model.StagingArea, block *externalapi.DomainBlock, isPruningPoint bool) error {
|
||||||
|
|
||||||
@ -128,6 +139,11 @@ func (bp *blockProcessor) validateAndInsertBlock(stagingArea *model.StagingArea,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = bp.ifGenesisSetUtxoSet(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
var selectedParentChainChanges *externalapi.SelectedChainPath
|
var selectedParentChainChanges *externalapi.SelectedChainPath
|
||||||
var virtualUTXODiff externalapi.UTXODiff
|
var virtualUTXODiff externalapi.UTXODiff
|
||||||
var reversalData *model.UTXODiffReversalData
|
var reversalData *model.UTXODiffReversalData
|
||||||
@ -215,6 +231,93 @@ func (bp *blockProcessor) validateAndInsertBlock(stagingArea *model.StagingArea,
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mainnetGenesisUTXOSet externalapi.UTXODiff
|
||||||
|
var mainnetGenesisMultiSet model.Multiset
|
||||||
|
var mainnetGenesisOnce sync.Once
|
||||||
|
var mainnetGenesisErr error
|
||||||
|
|
||||||
|
func deserializeMainnetUTXOSet() (externalapi.UTXODiff, model.Multiset, error) {
|
||||||
|
mainnetGenesisOnce.Do(func() {
|
||||||
|
toAdd := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry)
|
||||||
|
mainnetGenesisMultiSet = multiset.New()
|
||||||
|
file, err := gzip.NewReader(bytes.NewReader(utxoDumpFile))
|
||||||
|
if err != nil {
|
||||||
|
mainnetGenesisErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
size := make([]byte, 1)
|
||||||
|
_, err = io.ReadFull(file, size)
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
mainnetGenesisErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedUTXO := make([]byte, size[0])
|
||||||
|
_, err = io.ReadFull(file, serializedUTXO)
|
||||||
|
if err != nil {
|
||||||
|
mainnetGenesisErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mainnetGenesisMultiSet.Add(serializedUTXO)
|
||||||
|
|
||||||
|
entry, outpoint, err := utxo.DeserializeUTXO(serializedUTXO)
|
||||||
|
if err != nil {
|
||||||
|
mainnetGenesisErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
toAdd[*outpoint] = entry
|
||||||
|
}
|
||||||
|
mainnetGenesisUTXOSet, mainnetGenesisErr = utxo.NewUTXODiffFromCollections(utxo.NewUTXOCollection(toAdd), utxo.NewUTXOCollection(make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry)))
|
||||||
|
})
|
||||||
|
return mainnetGenesisUTXOSet, mainnetGenesisMultiSet, mainnetGenesisErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bp *blockProcessor) ifGenesisSetUtxoSet(block *externalapi.DomainBlock) error {
|
||||||
|
isGenesis := len(block.Header.DirectParents()) == 0
|
||||||
|
if !isGenesis {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
if !block.Header.UTXOCommitment().Equal(externalapi.NewDomainHashFromByteArray(muhash.EmptyMuHashHash.AsArray())) {
|
||||||
|
log.Infof("Loading checkpoint UTXO set")
|
||||||
|
diff, utxoSetMultiset, err := deserializeMainnetUTXOSet()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Infof("Finished loading checkpoint UTXO set")
|
||||||
|
utxoSetHash := utxoSetMultiset.Hash()
|
||||||
|
if !utxoSetHash.Equal(block.Header.UTXOCommitment()) {
|
||||||
|
return errors.New("Invalid UTXO set dump")
|
||||||
|
}
|
||||||
|
|
||||||
|
area := model.NewStagingArea()
|
||||||
|
bp.consensusStateStore.StageVirtualUTXODiff(area, diff)
|
||||||
|
bp.utxoDiffStore.Stage(area, blockHash, diff, nil)
|
||||||
|
// commit the multiset of genesis
|
||||||
|
bp.multisetStore.Stage(area, blockHash, utxoSetMultiset)
|
||||||
|
err = staging.CommitAllChanges(bp.databaseContext, area)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if it's genesis but has an empty muhash then commit an empty multiset and an empty diff
|
||||||
|
area := model.NewStagingArea()
|
||||||
|
bp.consensusStateStore.StageVirtualUTXODiff(area, utxo.NewUTXODiff())
|
||||||
|
bp.utxoDiffStore.Stage(area, blockHash, utxo.NewUTXODiff(), nil)
|
||||||
|
bp.multisetStore.Stage(area, blockHash, multiset.New())
|
||||||
|
err := staging.CommitAllChanges(bp.databaseContext, area)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool {
|
func isHeaderOnlyBlock(block *externalapi.DomainBlock) bool {
|
||||||
return len(block.Transactions) == 0
|
return len(block.Transactions) == 0
|
||||||
}
|
}
|
||||||
|
@ -140,10 +140,21 @@ func TestValidateAndInsertImportedPruningPoint(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pruningPointUTXOs, err := tcSyncer.GetPruningPointUTXOs(pruningPoint, nil, 1000)
|
var fromOutpoint *externalapi.DomainOutpoint
|
||||||
if err != nil {
|
var pruningPointUTXOs []*externalapi.OutpointAndUTXOEntryPair
|
||||||
t.Fatalf("GetPruningPointUTXOs: %+v", err)
|
const step = 100_000
|
||||||
|
for {
|
||||||
|
outpointAndUTXOEntryPairs, err := tcSyncer.GetPruningPointUTXOs(pruningPoint, fromOutpoint, step)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("GetPruningPointUTXOs: %+v", err)
|
||||||
|
}
|
||||||
|
fromOutpoint = outpointAndUTXOEntryPairs[len(outpointAndUTXOEntryPairs)-1].Outpoint
|
||||||
|
pruningPointUTXOs = append(pruningPointUTXOs, outpointAndUTXOEntryPairs...)
|
||||||
|
if len(outpointAndUTXOEntryPairs) < step {
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = synceeStaging.AppendImportedPruningPointUTXOs(pruningPointUTXOs)
|
err = synceeStaging.AppendImportedPruningPointUTXOs(pruningPointUTXOs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("AppendImportedPruningPointUTXOs: %+v", err)
|
t.Fatalf("AppendImportedPruningPointUTXOs: %+v", err)
|
||||||
@ -507,7 +518,7 @@ func TestGetPruningPointUTXOs(t *testing.T) {
|
|||||||
|
|
||||||
// Get pruning point UTXOs in a loop
|
// Get pruning point UTXOs in a loop
|
||||||
var allOutpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair
|
var allOutpointAndUTXOEntryPairs []*externalapi.OutpointAndUTXOEntryPair
|
||||||
step := 100
|
const step = 100_000
|
||||||
var fromOutpoint *externalapi.DomainOutpoint
|
var fromOutpoint *externalapi.DomainOutpoint
|
||||||
for {
|
for {
|
||||||
outpointAndUTXOEntryPairs, err := testConsensus.GetPruningPointUTXOs(pruningPoint, fromOutpoint, step)
|
outpointAndUTXOEntryPairs, err := testConsensus.GetPruningPointUTXOs(pruningPoint, fromOutpoint, step)
|
||||||
@ -522,11 +533,17 @@ func TestGetPruningPointUTXOs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mainnetUTXOSize = 1232643
|
||||||
|
expected := len(outputs) + 1
|
||||||
|
if consensusConfig.Name == "kaspa-mainnet" {
|
||||||
|
expected += mainnetUTXOSize
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure the length of the UTXOs is exactly spendingTransaction.Outputs + 1 coinbase
|
// Make sure the length of the UTXOs is exactly spendingTransaction.Outputs + 1 coinbase
|
||||||
// output (includingBlock's coinbase)
|
// output (includingBlock's coinbase)
|
||||||
if len(allOutpointAndUTXOEntryPairs) != len(outputs)+1 {
|
if len(allOutpointAndUTXOEntryPairs) != expected {
|
||||||
t.Fatalf("Returned an unexpected amount of UTXOs. "+
|
t.Fatalf("Returned an unexpected amount of UTXOs. "+
|
||||||
"Want: %d, got: %d", len(outputs)+2, len(allOutpointAndUTXOEntryPairs))
|
"Want: %d, got: %d", expected, len(allOutpointAndUTXOEntryPairs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure all spendingTransaction.Outputs are in the returned UTXOs
|
// Make sure all spendingTransaction.Outputs are in the returned UTXOs
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus"
|
"github.com/kaspanet/kaspad/domain/consensus"
|
||||||
@ -21,6 +23,31 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestBlockValidator_ValidateBodyInIsolation(t *testing.T) {
|
||||||
|
tests := []func(t *testing.T, tc testapi.TestConsensus, cfg *consensus.Config){
|
||||||
|
CheckBlockSanity,
|
||||||
|
CheckBlockHashMerkleRoot,
|
||||||
|
BlockMass,
|
||||||
|
CheckBlockDuplicateTransactions,
|
||||||
|
CheckBlockContainsOnlyOneCoinbase,
|
||||||
|
CheckBlockDoubleSpends,
|
||||||
|
CheckFirstBlockTransactionIsCoinbase,
|
||||||
|
}
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
tc, teardown, err := consensus.NewFactory().NewTestConsensus(consensusConfig, "TestChainedTransactions")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up consensus: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardown(false)
|
||||||
|
for _, test := range tests {
|
||||||
|
testName := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name()
|
||||||
|
t.Run(testName, func(t *testing.T) {
|
||||||
|
test(t, tc, consensusConfig)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestChainedTransactions(t *testing.T) {
|
func TestChainedTransactions(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
consensusConfig.BlockCoinbaseMaturity = 0
|
consensusConfig.BlockCoinbaseMaturity = 0
|
||||||
@ -89,47 +116,39 @@ func TestChainedTransactions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestCheckBlockSanity tests the CheckBlockSanity function to ensure it works
|
// CheckBlockSanity tests the CheckBlockSanity function to ensure it works
|
||||||
// as expected.
|
// as expected.
|
||||||
func TestCheckBlockSanity(t *testing.T) {
|
func CheckBlockSanity(t *testing.T, tc testapi.TestConsensus, _ *consensus.Config) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
blockHash := consensushashing.BlockHash(&exampleValidBlock)
|
||||||
factory := consensus.NewFactory()
|
if len(exampleValidBlock.Transactions) < 3 {
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockSanity")
|
t.Fatalf("Too few transactions in block, expect at least 3, got %v", len(exampleValidBlock.Transactions))
|
||||||
if err != nil {
|
}
|
||||||
t.Fatalf("Error setting up consensus: %+v", err)
|
|
||||||
}
|
|
||||||
defer teardown(false)
|
|
||||||
blockHash := consensushashing.BlockHash(&exampleValidBlock)
|
|
||||||
if len(exampleValidBlock.Transactions) < 3 {
|
|
||||||
t.Fatalf("Too few transactions in block, expect at least 3, got %v", len(exampleValidBlock.Transactions))
|
|
||||||
}
|
|
||||||
|
|
||||||
stagingArea := model.NewStagingArea()
|
stagingArea := model.NewStagingArea()
|
||||||
|
|
||||||
tc.BlockStore().Stage(stagingArea, blockHash, &exampleValidBlock)
|
tc.BlockStore().Stage(stagingArea, blockHash, &exampleValidBlock)
|
||||||
|
|
||||||
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
err := tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed validating block in isolation: %v", err)
|
t.Fatalf("Failed validating block in isolation: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with block with wrong transactions sorting order
|
// Test with block with wrong transactions sorting order
|
||||||
blockHash = consensushashing.BlockHash(&blockWithWrongTxOrder)
|
blockHash = consensushashing.BlockHash(&blockWithWrongTxOrder)
|
||||||
tc.BlockStore().Stage(stagingArea, blockHash, &blockWithWrongTxOrder)
|
tc.BlockStore().Stage(stagingArea, blockHash, &blockWithWrongTxOrder)
|
||||||
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
||||||
if !errors.Is(err, ruleerrors.ErrTransactionsNotSorted) {
|
if !errors.Is(err, ruleerrors.ErrTransactionsNotSorted) {
|
||||||
t.Errorf("CheckBlockSanity: Expected ErrTransactionsNotSorted error, instead got %v", err)
|
t.Errorf("CheckBlockSanity: Expected ErrTransactionsNotSorted error, instead got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test a block with invalid parents order
|
// Test a block with invalid parents order
|
||||||
// We no longer require blocks to have ordered parents
|
// We no longer require blocks to have ordered parents
|
||||||
blockHash = consensushashing.BlockHash(&unOrderedParentsBlock)
|
blockHash = consensushashing.BlockHash(&unOrderedParentsBlock)
|
||||||
tc.BlockStore().Stage(stagingArea, blockHash, &unOrderedParentsBlock)
|
tc.BlockStore().Stage(stagingArea, blockHash, &unOrderedParentsBlock)
|
||||||
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("CheckBlockSanity: Expected block to be be body in isolation valid, got error instead: %v", err)
|
t.Errorf("CheckBlockSanity: Expected block to be be body in isolation valid, got error instead: %v", err)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var unOrderedParentsBlock = externalapi.DomainBlock{
|
var unOrderedParentsBlock = externalapi.DomainBlock{
|
||||||
@ -1025,59 +1044,41 @@ var blockWithWrongTxOrder = externalapi.DomainBlock{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckBlockHashMerkleRoot(t *testing.T) {
|
func CheckBlockHashMerkleRoot(t *testing.T, tc testapi.TestConsensus, consensusConfig *consensus.Config) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||||
factory := consensus.NewFactory()
|
if err != nil {
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockHashMerkleRoot")
|
t.Fatalf("BuildBlockWithParents: %+v", err)
|
||||||
if err != nil {
|
}
|
||||||
t.Fatalf("Error setting up tc: %+v", err)
|
blockWithInvalidMerkleRoot := block.Clone()
|
||||||
}
|
blockWithInvalidMerkleRoot.Transactions[0].Version += 1
|
||||||
defer teardown(false)
|
|
||||||
|
|
||||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
_, err = tc.ValidateAndInsertBlock(blockWithInvalidMerkleRoot, true)
|
||||||
if err != nil {
|
if !errors.Is(err, ruleerrors.ErrBadMerkleRoot) {
|
||||||
t.Fatalf("BuildBlockWithParents: %+v", err)
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
}
|
}
|
||||||
blockWithInvalidMerkleRoot := block.Clone()
|
|
||||||
blockWithInvalidMerkleRoot.Transactions[0].Version += 1
|
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(blockWithInvalidMerkleRoot, true)
|
// Check that a block with invalid merkle root is not marked as invalid
|
||||||
if !errors.Is(err, ruleerrors.ErrBadMerkleRoot) {
|
// and can be re-added with the right transactions.
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
_, err = tc.ValidateAndInsertBlock(block, true)
|
||||||
}
|
if err != nil {
|
||||||
|
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
||||||
// Check that a block with invalid merkle root is not marked as invalid
|
}
|
||||||
// and can be re-added with the right transactions.
|
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ValidateAndInsertBlock: %+v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBlockMass(t *testing.T) {
|
func BlockMass(t *testing.T, tc testapi.TestConsensus, consensusConfig *consensus.Config) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
block, _, err := initBlockWithInvalidBlockMass(consensusConfig, tc)
|
||||||
factory := consensus.NewFactory()
|
if err != nil {
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestBlockMass")
|
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
||||||
if err != nil {
|
}
|
||||||
t.Fatalf("Error setting up tc: %+v", err)
|
blockHash := consensushashing.BlockHash(block)
|
||||||
}
|
stagingArea := model.NewStagingArea()
|
||||||
defer teardown(false)
|
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
||||||
|
|
||||||
block, _, err := initBlockWithInvalidBlockMass(consensusConfig, tc)
|
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
||||||
if err != nil {
|
if err == nil || !errors.Is(err, ruleerrors.ErrBlockMassTooHigh) {
|
||||||
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
t.Fatalf("ValidateBodyInIsolationTest: TestBlockMass:"+
|
||||||
}
|
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrBlockMassTooHigh, err)
|
||||||
blockHash := consensushashing.BlockHash(block)
|
}
|
||||||
stagingArea := model.NewStagingArea()
|
|
||||||
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
|
||||||
|
|
||||||
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
|
||||||
if err == nil || !errors.Is(err, ruleerrors.ErrBlockMassTooHigh) {
|
|
||||||
t.Fatalf("ValidateBodyInIsolationTest: TestBlockMass:"+
|
|
||||||
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrBlockMassTooHigh, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBlockWithInvalidBlockMass(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
func initBlockWithInvalidBlockMass(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||||
@ -1113,30 +1114,20 @@ func initBlockWithInvalidBlockMass(consensusConfig *consensus.Config, tc testapi
|
|||||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx})
|
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckBlockDuplicateTransactions(t *testing.T) {
|
func CheckBlockDuplicateTransactions(t *testing.T, tc testapi.TestConsensus, consensusConfig *consensus.Config) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
block, _, err := initBlockWithDuplicateTransaction(consensusConfig, tc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
||||||
|
}
|
||||||
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
stagingArea := model.NewStagingArea()
|
||||||
|
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
||||||
|
|
||||||
factory := consensus.NewFactory()
|
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockDuplicateTransactions")
|
if err == nil || !errors.Is(err, ruleerrors.ErrDuplicateTx) {
|
||||||
if err != nil {
|
t.Fatalf("ValidateBodyInIsolationTest: TestCheckBlockDuplicateTransactions:"+
|
||||||
t.Fatalf("Error setting up tc: %+v", err)
|
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrDuplicateTx, err)
|
||||||
}
|
}
|
||||||
defer teardown(false)
|
|
||||||
|
|
||||||
block, _, err := initBlockWithDuplicateTransaction(consensusConfig, tc)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
|
||||||
}
|
|
||||||
blockHash := consensushashing.BlockHash(block)
|
|
||||||
stagingArea := model.NewStagingArea()
|
|
||||||
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
|
||||||
|
|
||||||
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
|
||||||
if err == nil || !errors.Is(err, ruleerrors.ErrDuplicateTx) {
|
|
||||||
t.Fatalf("ValidateBodyInIsolationTest: TestCheckBlockDuplicateTransactions:"+
|
|
||||||
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrDuplicateTx, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBlockWithDuplicateTransaction(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
func initBlockWithDuplicateTransaction(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||||
@ -1170,30 +1161,20 @@ func initBlockWithDuplicateTransaction(consensusConfig *consensus.Config, tc tes
|
|||||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx, tx})
|
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx, tx})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckBlockContainsOnlyOneCoinbase(t *testing.T) {
|
func CheckBlockContainsOnlyOneCoinbase(t *testing.T, tc testapi.TestConsensus, consensusConfig *consensus.Config) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
block, _, err := initBlockWithMoreThanOneCoinbase(consensusConfig, tc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
||||||
|
}
|
||||||
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
stagingArea := model.NewStagingArea()
|
||||||
|
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
||||||
|
|
||||||
factory := consensus.NewFactory()
|
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockContainsOnlyOneCoinbase")
|
if err == nil || !errors.Is(err, ruleerrors.ErrMultipleCoinbases) {
|
||||||
if err != nil {
|
t.Fatalf("ValidateBodyInIsolationTest: TestCheckBlockContainsOnlyOneCoinbase:"+
|
||||||
t.Fatalf("Error setting up tc: %+v", err)
|
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrMultipleCoinbases, err)
|
||||||
}
|
}
|
||||||
defer teardown(false)
|
|
||||||
|
|
||||||
block, _, err := initBlockWithMoreThanOneCoinbase(consensusConfig, tc)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
|
||||||
}
|
|
||||||
blockHash := consensushashing.BlockHash(block)
|
|
||||||
stagingArea := model.NewStagingArea()
|
|
||||||
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
|
||||||
|
|
||||||
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
|
||||||
if err == nil || !errors.Is(err, ruleerrors.ErrMultipleCoinbases) {
|
|
||||||
t.Fatalf("ValidateBodyInIsolationTest: TestCheckBlockContainsOnlyOneCoinbase:"+
|
|
||||||
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrMultipleCoinbases, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBlockWithMoreThanOneCoinbase(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
func initBlockWithMoreThanOneCoinbase(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||||
@ -1227,30 +1208,20 @@ func initBlockWithMoreThanOneCoinbase(consensusConfig *consensus.Config, tc test
|
|||||||
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx})
|
return tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, &emptyCoinbase, []*externalapi.DomainTransaction{tx})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckBlockDoubleSpends(t *testing.T) {
|
func CheckBlockDoubleSpends(t *testing.T, tc testapi.TestConsensus, consensusConfig *consensus.Config) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
block, _, err := initBlockWithDoubleSpends(consensusConfig, tc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
||||||
|
}
|
||||||
|
blockHash := consensushashing.BlockHash(block)
|
||||||
|
stagingArea := model.NewStagingArea()
|
||||||
|
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
||||||
|
|
||||||
factory := consensus.NewFactory()
|
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockDoubleSpends")
|
if err == nil || !errors.Is(err, ruleerrors.ErrDoubleSpendInSameBlock) {
|
||||||
if err != nil {
|
t.Fatalf("ValidateBodyInIsolationTest: TestCheckBlockDoubleSpends:"+
|
||||||
t.Fatalf("Error setting up tc: %+v", err)
|
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrDoubleSpendInSameBlock, err)
|
||||||
}
|
}
|
||||||
defer teardown(false)
|
|
||||||
|
|
||||||
block, _, err := initBlockWithDoubleSpends(consensusConfig, tc)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Error BuildBlockWithParents : %+v", err)
|
|
||||||
}
|
|
||||||
blockHash := consensushashing.BlockHash(block)
|
|
||||||
stagingArea := model.NewStagingArea()
|
|
||||||
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
|
||||||
|
|
||||||
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
|
||||||
if err == nil || !errors.Is(err, ruleerrors.ErrDoubleSpendInSameBlock) {
|
|
||||||
t.Fatalf("ValidateBodyInIsolationTest: TestCheckBlockDoubleSpends:"+
|
|
||||||
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrDoubleSpendInSameBlock, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBlockWithDoubleSpends(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
func initBlockWithDoubleSpends(consensusConfig *consensus.Config, tc testapi.TestConsensus) (*externalapi.DomainBlock, externalapi.UTXODiff, error) {
|
||||||
@ -1303,27 +1274,18 @@ func initBlockWithDoubleSpends(consensusConfig *consensus.Config, tc testapi.Tes
|
|||||||
&emptyCoinbase, []*externalapi.DomainTransaction{tx, txSameOutpoint})
|
&emptyCoinbase, []*externalapi.DomainTransaction{tx, txSameOutpoint})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckFirstBlockTransactionIsCoinbase(t *testing.T) {
|
func CheckFirstBlockTransactionIsCoinbase(t *testing.T, tc testapi.TestConsensus, consensusConfig *consensus.Config) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
|
||||||
|
|
||||||
factory := consensus.NewFactory()
|
block := initBlockWithFirstTransactionDifferentThanCoinbase(consensusConfig)
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckFirstBlockTransactionIsCoinbase")
|
blockHash := consensushashing.BlockHash(block)
|
||||||
if err != nil {
|
stagingArea := model.NewStagingArea()
|
||||||
t.Fatalf("Error setting up tc: %+v", err)
|
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
||||||
}
|
|
||||||
defer teardown(false)
|
|
||||||
|
|
||||||
block := initBlockWithFirstTransactionDifferentThanCoinbase(consensusConfig)
|
err := tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
||||||
blockHash := consensushashing.BlockHash(block)
|
if err == nil || !errors.Is(err, ruleerrors.ErrFirstTxNotCoinbase) {
|
||||||
stagingArea := model.NewStagingArea()
|
t.Fatalf("ValidateBodyInIsolationTest: TestCheckFirstBlockTransactionIsCoinbase:"+
|
||||||
tc.BlockStore().Stage(stagingArea, blockHash, block)
|
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrFirstTxNotCoinbase, err)
|
||||||
|
}
|
||||||
err = tc.BlockValidator().ValidateBodyInIsolation(stagingArea, blockHash)
|
|
||||||
if err == nil || !errors.Is(err, ruleerrors.ErrFirstTxNotCoinbase) {
|
|
||||||
t.Fatalf("ValidateBodyInIsolationTest: TestCheckFirstBlockTransactionIsCoinbase:"+
|
|
||||||
" Unexpected error: Expected to: %v, but got : %v", ruleerrors.ErrFirstTxNotCoinbase, err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBlockWithFirstTransactionDifferentThanCoinbase(consensusConfig *consensus.Config) *externalapi.DomainBlock {
|
func initBlockWithFirstTransactionDifferentThanCoinbase(consensusConfig *consensus.Config) *externalapi.DomainBlock {
|
||||||
|
@ -67,8 +67,8 @@ func TestValidateMedianTime(t *testing.T) {
|
|||||||
|
|
||||||
blockTime := tip.Header.TimeInMilliseconds()
|
blockTime := tip.Header.TimeInMilliseconds()
|
||||||
|
|
||||||
for i := 0; i < 100; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
blockTime += 1000
|
blockTime += 100
|
||||||
_, tipHash = addBlock(blockTime, []*externalapi.DomainHash{tipHash}, nil)
|
_, tipHash = addBlock(blockTime, []*externalapi.DomainHash{tipHash}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +163,7 @@ func TestCheckParentsIncest(t *testing.T) {
|
|||||||
|
|
||||||
func TestCheckMergeSizeLimit(t *testing.T) {
|
func TestCheckMergeSizeLimit(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
consensusConfig.MergeSetSizeLimit = 2 * uint64(consensusConfig.K)
|
consensusConfig.MergeSetSizeLimit = 5
|
||||||
factory := consensus.NewFactory()
|
factory := consensus.NewFactory()
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckMergeSizeLimit")
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckMergeSizeLimit")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package blockvalidator_test
|
package blockvalidator_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/testapi"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus"
|
"github.com/kaspanet/kaspad/domain/consensus"
|
||||||
@ -13,73 +16,74 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCheckParentsLimit(t *testing.T) {
|
func TestBlockValidator_ValidateHeaderInIsolation(t *testing.T) {
|
||||||
|
tests := []func(t *testing.T, tc testapi.TestConsensus, cfg *consensus.Config){
|
||||||
|
CheckParentsLimit,
|
||||||
|
CheckBlockVersion,
|
||||||
|
CheckBlockTimestampInIsolation,
|
||||||
|
}
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
factory := consensus.NewFactory()
|
tc, teardown, err := consensus.NewFactory().NewTestConsensus(consensusConfig, "TestBlockValidator_ValidateHeaderInIsolation")
|
||||||
|
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckParentsLimit")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error setting up consensus: %+v", err)
|
t.Fatalf("Error setting up consensus: %+v", err)
|
||||||
}
|
}
|
||||||
defer teardown(false)
|
defer teardown(false)
|
||||||
|
for _, test := range tests {
|
||||||
for i := externalapi.KType(0); i < consensusConfig.MaxBlockParents+1; i++ {
|
testName := runtime.FuncForPC(reflect.ValueOf(test).Pointer()).Name()
|
||||||
_, _, err = tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
t.Run(testName, func(t *testing.T) {
|
||||||
if err != nil {
|
test(t, tc, consensusConfig)
|
||||||
t.Fatalf("AddBlock: %+v", err)
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tips, err := tc.Tips()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Tips: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, err = tc.AddBlock(tips, nil, nil)
|
|
||||||
if !errors.Is(err, ruleerrors.ErrTooManyParents) {
|
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckBlockVersion(t *testing.T) {
|
func CheckParentsLimit(t *testing.T, tc testapi.TestConsensus, consensusConfig *consensus.Config) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
for i := externalapi.KType(0); i < consensusConfig.MaxBlockParents+1; i++ {
|
||||||
factory := consensus.NewFactory()
|
_, _, err := tc.AddBlock([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||||
|
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestCheckBlockVersion")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error setting up consensus: %+v", err)
|
t.Fatalf("AddBlock: %+v", err)
|
||||||
}
|
}
|
||||||
defer teardown(false)
|
}
|
||||||
|
|
||||||
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
tips, err := tc.Tips()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("BuildBlockWithParents: %+v", err)
|
t.Fatalf("Tips: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
block.Header = blockheader.NewImmutableBlockHeader(
|
_, _, err = tc.AddBlock(tips, nil, nil)
|
||||||
constants.MaxBlockVersion+1,
|
if !errors.Is(err, ruleerrors.ErrTooManyParents) {
|
||||||
block.Header.Parents(),
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
block.Header.HashMerkleRoot(),
|
}
|
||||||
block.Header.AcceptedIDMerkleRoot(),
|
|
||||||
block.Header.UTXOCommitment(),
|
|
||||||
block.Header.TimeInMilliseconds(),
|
|
||||||
block.Header.Bits(),
|
|
||||||
block.Header.Nonce(),
|
|
||||||
block.Header.DAAScore(),
|
|
||||||
block.Header.BlueScore(),
|
|
||||||
block.Header.BlueWork(),
|
|
||||||
block.Header.PruningPoint(),
|
|
||||||
)
|
|
||||||
|
|
||||||
_, err = tc.ValidateAndInsertBlock(block, true)
|
|
||||||
if !errors.Is(err, ruleerrors.ErrBlockVersionIsUnknown) {
|
|
||||||
t.Fatalf("Unexpected error: %+v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckBlockTimestampInIsolation(t *testing.T) {
|
func CheckBlockVersion(t *testing.T, tc testapi.TestConsensus, consensusConfig *consensus.Config) {
|
||||||
|
block, _, err := tc.BuildBlockWithParents([]*externalapi.DomainHash{consensusConfig.GenesisHash}, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("BuildBlockWithParents: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
block.Header = blockheader.NewImmutableBlockHeader(
|
||||||
|
constants.MaxBlockVersion+1,
|
||||||
|
block.Header.Parents(),
|
||||||
|
block.Header.HashMerkleRoot(),
|
||||||
|
block.Header.AcceptedIDMerkleRoot(),
|
||||||
|
block.Header.UTXOCommitment(),
|
||||||
|
block.Header.TimeInMilliseconds(),
|
||||||
|
block.Header.Bits(),
|
||||||
|
block.Header.Nonce(),
|
||||||
|
block.Header.DAAScore(),
|
||||||
|
block.Header.BlueScore(),
|
||||||
|
block.Header.BlueWork(),
|
||||||
|
block.Header.PruningPoint(),
|
||||||
|
)
|
||||||
|
|
||||||
|
_, err = tc.ValidateAndInsertBlock(block, true)
|
||||||
|
if !errors.Is(err, ruleerrors.ErrBlockVersionIsUnknown) {
|
||||||
|
t.Fatalf("Unexpected error: %+v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckBlockTimestampInIsolation(t *testing.T, tc testapi.TestConsensus, cfg *consensus.Config) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
factory := consensus.NewFactory()
|
factory := consensus.NewFactory()
|
||||||
|
|
||||||
|
@ -49,9 +49,11 @@ func (v *blockValidator) ValidatePruningPointViolationAndProofOfWorkAndDifficult
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = v.checkProofOfWork(header)
|
if !blockHash.Equal(v.genesisHash) {
|
||||||
if err != nil {
|
err = v.checkProofOfWork(header)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = v.validateDifficulty(stagingArea, blockHash, isBlockWithTrustedData)
|
err = v.validateDifficulty(stagingArea, blockHash, isBlockWithTrustedData)
|
||||||
|
@ -101,10 +101,13 @@ func TestPOW(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
random := rand.New(rand.NewSource(0))
|
random := rand.New(rand.NewSource(0))
|
||||||
mining.SolveBlock(validBlock, random)
|
// Difficulty is too high on mainnet to actually mine.
|
||||||
_, err = tc.ValidateAndInsertBlock(validBlock, true)
|
if consensusConfig.Name != "kaspa-mainnet" {
|
||||||
if err != nil {
|
mining.SolveBlock(validBlock, random)
|
||||||
t.Fatal(err)
|
_, err = tc.ValidateAndInsertBlock(validBlock, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -296,7 +299,7 @@ func TestCheckPruningPointViolation(t *testing.T) {
|
|||||||
func TestValidateDifficulty(t *testing.T) {
|
func TestValidateDifficulty(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
factory := consensus.NewFactory()
|
factory := consensus.NewFactory()
|
||||||
mocDifficulty := &mocDifficultyManager{}
|
mocDifficulty := &mocDifficultyManager{genesisDaaScore: consensusConfig.GenesisBlock.Header.DAAScore()}
|
||||||
factory.SetTestDifficultyManager(func(_ model.DBReader, _ model.GHOSTDAGManager, _ model.GHOSTDAGDataStore,
|
factory.SetTestDifficultyManager(func(_ model.DBReader, _ model.GHOSTDAGManager, _ model.GHOSTDAGDataStore,
|
||||||
_ model.BlockHeaderStore, daaBlocksStore model.DAABlocksStore, _ model.DAGTopologyManager,
|
_ model.BlockHeaderStore, daaBlocksStore model.DAABlocksStore, _ model.DAGTopologyManager,
|
||||||
_ model.DAGTraversalManager, _ *big.Int, _ int, _ bool, _ time.Duration,
|
_ model.DAGTraversalManager, _ *big.Int, _ int, _ bool, _ time.Duration,
|
||||||
@ -342,6 +345,7 @@ type mocDifficultyManager struct {
|
|||||||
testDifficulty uint32
|
testDifficulty uint32
|
||||||
testGenesisBits uint32
|
testGenesisBits uint32
|
||||||
daaBlocksStore model.DAABlocksStore
|
daaBlocksStore model.DAABlocksStore
|
||||||
|
genesisDaaScore uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// RequiredDifficulty returns the difficulty required for the test
|
// RequiredDifficulty returns the difficulty required for the test
|
||||||
@ -352,7 +356,7 @@ func (dm *mocDifficultyManager) RequiredDifficulty(*model.StagingArea, *external
|
|||||||
// StageDAADataAndReturnRequiredDifficulty returns the difficulty required for the test
|
// StageDAADataAndReturnRequiredDifficulty returns the difficulty required for the test
|
||||||
func (dm *mocDifficultyManager) StageDAADataAndReturnRequiredDifficulty(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash, isBlockWithTrustedData bool) (uint32, error) {
|
func (dm *mocDifficultyManager) StageDAADataAndReturnRequiredDifficulty(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash, isBlockWithTrustedData bool) (uint32, error) {
|
||||||
// Populate daaBlocksStore with fake values
|
// Populate daaBlocksStore with fake values
|
||||||
dm.daaBlocksStore.StageDAAScore(stagingArea, blockHash, 0)
|
dm.daaBlocksStore.StageDAAScore(stagingArea, blockHash, dm.genesisDaaScore)
|
||||||
dm.daaBlocksStore.StageBlockDAAAddedBlocks(stagingArea, blockHash, nil)
|
dm.daaBlocksStore.StageBlockDAAAddedBlocks(stagingArea, blockHash, nil)
|
||||||
|
|
||||||
return dm.testDifficulty, nil
|
return dm.testDifficulty, nil
|
||||||
|
@ -86,36 +86,5 @@ func TestBlockRewardSwitch(t *testing.T) {
|
|||||||
t.Fatalf("Subsidy has unexpected value. Want: %d, got: %d", consensusConfig.MinSubsidy, subsidy)
|
t.Fatalf("Subsidy has unexpected value. Want: %d, got: %d", consensusConfig.MinSubsidy, subsidy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add another block. We expect it to be another pruning point
|
|
||||||
lastPruningPointHash, _, err := tc.AddBlock([]*externalapi.DomainHash{tipHash}, nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("AddBlock: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that another pruning point had been added
|
|
||||||
pruningPointHeaders, err = tc.PruningPointHeaders()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("PruningPointHeaders: %+v", pruningPointHeaders)
|
|
||||||
}
|
|
||||||
expectedPruningPointHeaderAmount = expectedPruningPointHeaderAmount + 1
|
|
||||||
if uint64(len(pruningPointHeaders)) != expectedPruningPointHeaderAmount {
|
|
||||||
t.Fatalf("Unexpected amount of pruning point headers. "+
|
|
||||||
"Want: %d, got: %d", expectedPruningPointHeaderAmount, len(pruningPointHeaders))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure that the last pruning point has a post-switch subsidy
|
|
||||||
lastPruningPoint, err := tc.GetBlock(lastPruningPointHash)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("GetBlock: %+v", err)
|
|
||||||
}
|
|
||||||
lastPruningPointCoinbase := lastPruningPoint.Transactions[transactionhelper.CoinbaseTransactionIndex]
|
|
||||||
_, _, subsidy, err := tc.CoinbaseManager().ExtractCoinbaseDataBlueScoreAndSubsidy(lastPruningPointCoinbase)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ExtractCoinbaseDataBlueScoreAndSubsidy: %+v", err)
|
|
||||||
}
|
|
||||||
if subsidy != consensusConfig.SubsidyGenesisReward {
|
|
||||||
t.Fatalf("Subsidy has unexpected value. Want: %d, got: %d", consensusConfig.SubsidyGenesisReward, subsidy)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package coinbasemanager
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||||
@ -10,7 +12,6 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
"github.com/kaspanet/kaspad/infrastructure/db/database"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"math/big"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type coinbaseManager struct {
|
type coinbaseManager struct {
|
||||||
@ -190,51 +191,7 @@ func (c *coinbaseManager) CalcBlockSubsidy(stagingArea *model.StagingArea,
|
|||||||
return c.subsidyGenesisReward, nil
|
return c.subsidyGenesisReward, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
isBlockRewardFixed, err := c.isBlockRewardFixed(stagingArea, blockPruningPoint)
|
return c.maxSubsidy, nil
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
if isBlockRewardFixed {
|
|
||||||
return c.subsidyGenesisReward, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
averagePastSubsidy, err := c.calculateAveragePastSubsidy(stagingArea, blockHash)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
mergeSetSubsidySum, err := c.calculateMergeSetSubsidySum(stagingArea, blockHash)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
subsidyRandomVariable, err := c.calculateSubsidyRandomVariable(stagingArea, blockHash)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pastSubsidy := new(big.Rat).Mul(averagePastSubsidy, c.subsidyPastRewardMultiplier)
|
|
||||||
mergeSetSubsidy := new(big.Rat).Mul(mergeSetSubsidySum, c.subsidyMergeSetRewardMultiplier)
|
|
||||||
|
|
||||||
// In order to avoid unsupported negative exponents in powInt64, flip
|
|
||||||
// the numerator and the denominator manually
|
|
||||||
subsidyRandom := new(big.Rat)
|
|
||||||
if subsidyRandomVariable >= 0 {
|
|
||||||
subsidyRandom = subsidyRandom.SetInt64(1 << subsidyRandomVariable)
|
|
||||||
} else {
|
|
||||||
subsidyRandom = subsidyRandom.SetFrac64(1, 1<<(-subsidyRandomVariable))
|
|
||||||
}
|
|
||||||
|
|
||||||
blockSubsidyBigRat := new(big.Rat).Add(mergeSetSubsidy, new(big.Rat).Mul(pastSubsidy, subsidyRandom))
|
|
||||||
blockSubsidyBigInt := new(big.Int).Div(blockSubsidyBigRat.Num(), blockSubsidyBigRat.Denom())
|
|
||||||
blockSubsidyUint64 := blockSubsidyBigInt.Uint64()
|
|
||||||
|
|
||||||
clampedBlockSubsidy := blockSubsidyUint64
|
|
||||||
if clampedBlockSubsidy < c.minSubsidy {
|
|
||||||
clampedBlockSubsidy = c.minSubsidy
|
|
||||||
} else if clampedBlockSubsidy > c.maxSubsidy {
|
|
||||||
clampedBlockSubsidy = c.maxSubsidy
|
|
||||||
}
|
|
||||||
|
|
||||||
return clampedBlockSubsidy, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *coinbaseManager) calculateAveragePastSubsidy(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (*big.Rat, error) {
|
func (c *coinbaseManager) calculateAveragePastSubsidy(stagingArea *model.StagingArea, blockHash *externalapi.DomainHash) (*big.Rat, error) {
|
||||||
|
@ -75,7 +75,7 @@ func TestVirtualDiff(t *testing.T) {
|
|||||||
blockB.Transactions[0].Outputs[0].Value,
|
blockB.Transactions[0].Outputs[0].Value,
|
||||||
blockB.Transactions[0].Outputs[0].ScriptPublicKey,
|
blockB.Transactions[0].Outputs[0].ScriptPublicKey,
|
||||||
true,
|
true,
|
||||||
2, //Expected virtual DAA score
|
consensusConfig.GenesisBlock.Header.DAAScore()+2, //Expected virtual DAA score
|
||||||
)) {
|
)) {
|
||||||
t.Fatalf("Unexpected entry %s", entry)
|
t.Fatalf("Unexpected entry %s", entry)
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@ package consensusstatemanager
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/multiset"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/logger"
|
"github.com/kaspanet/kaspad/infrastructure/logger"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
@ -23,8 +22,16 @@ func (csm *consensusStateManager) CalculatePastUTXOAndAcceptanceData(stagingArea
|
|||||||
|
|
||||||
if blockHash.Equal(csm.genesisHash) {
|
if blockHash.Equal(csm.genesisHash) {
|
||||||
log.Debugf("Block %s is the genesis. By definition, "+
|
log.Debugf("Block %s is the genesis. By definition, "+
|
||||||
"it has an empty UTXO diff, empty acceptance data, and a blank multiset", blockHash)
|
"it has a predefined UTXO diff, empty acceptance data, and a predefined multiset", blockHash)
|
||||||
return utxo.NewUTXODiff(), externalapi.AcceptanceData{}, multiset.New(), nil
|
multiset, err := csm.multisetStore.Get(csm.databaseContext, stagingArea, blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
utxoDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, stagingArea, blockHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
return utxoDiff, externalapi.AcceptanceData{}, multiset, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
blockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, stagingArea, blockHash, false)
|
blockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, stagingArea, blockHash, false)
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/multiset"
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,8 +18,8 @@ func (csm *consensusStateManager) calculateMultiset(stagingArea *model.StagingAr
|
|||||||
|
|
||||||
if blockHash.Equal(csm.genesisHash) {
|
if blockHash.Equal(csm.genesisHash) {
|
||||||
log.Debugf("Selected parent is nil, which could only happen for the genesis. " +
|
log.Debugf("Selected parent is nil, which could only happen for the genesis. " +
|
||||||
"The genesis, by definition, has an empty multiset")
|
"The genesis has a predefined multiset")
|
||||||
return multiset.New(), nil
|
return csm.multisetStore.Get(csm.databaseContext, stagingArea, blockHash)
|
||||||
}
|
}
|
||||||
|
|
||||||
ms, err := csm.multisetStore.Get(csm.databaseContext, stagingArea, blockGHOSTDAGData.SelectedParent())
|
ms, err := csm.multisetStore.Get(csm.databaseContext, stagingArea, blockGHOSTDAGData.SelectedParent())
|
||||||
|
@ -3,8 +3,6 @@ package consensusstatemanager
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/util/staging"
|
"github.com/kaspanet/kaspad/util/staging"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model"
|
"github.com/kaspanet/kaspad/domain/consensus/model"
|
||||||
@ -129,7 +127,11 @@ func (csm *consensusStateManager) selectedParentInfo(
|
|||||||
if lastUnverifiedBlock.Equal(csm.genesisHash) {
|
if lastUnverifiedBlock.Equal(csm.genesisHash) {
|
||||||
log.Debugf("the most recent unverified block is the genesis block, "+
|
log.Debugf("the most recent unverified block is the genesis block, "+
|
||||||
"which by definition has status: %s", externalapi.StatusUTXOValid)
|
"which by definition has status: %s", externalapi.StatusUTXOValid)
|
||||||
return lastUnverifiedBlock, externalapi.StatusUTXOValid, utxo.NewUTXODiff(), nil
|
utxoDiff, err := csm.utxoDiffStore.UTXODiff(csm.databaseContext, stagingArea, lastUnverifiedBlock)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, nil, err
|
||||||
|
}
|
||||||
|
return lastUnverifiedBlock, externalapi.StatusUTXOValid, utxoDiff, nil
|
||||||
}
|
}
|
||||||
lastUnverifiedBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, stagingArea, lastUnverifiedBlock, false)
|
lastUnverifiedBlockGHOSTDAGData, err := csm.ghostdagDataStore.Get(csm.databaseContext, stagingArea, lastUnverifiedBlock, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -285,7 +285,7 @@ func TestTransactionAcceptance(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error getting blockF: %+v", err)
|
t.Fatalf("Error getting blockF: %+v", err)
|
||||||
}
|
}
|
||||||
updatedDAAScoreVirtualBlock := 26
|
updatedDAAScoreVirtualBlock := consensusConfig.GenesisBlock.Header.DAAScore() + 26
|
||||||
//We expect the second transaction in the "blue block" (blueChildOfRedBlock) to be accepted because the merge set is ordered topologically
|
//We expect the second transaction in the "blue block" (blueChildOfRedBlock) to be accepted because the merge set is ordered topologically
|
||||||
//and the red block is ordered topologically before the "blue block" so the input is known in the UTXOSet.
|
//and the red block is ordered topologically before the "blue block" so the input is known in the UTXOSet.
|
||||||
expectedAcceptanceData := externalapi.AcceptanceData{
|
expectedAcceptanceData := externalapi.AcceptanceData{
|
||||||
|
@ -40,12 +40,12 @@ func TestBlockWindow(t *testing.T) {
|
|||||||
{
|
{
|
||||||
parents: []string{"C", "D"},
|
parents: []string{"C", "D"},
|
||||||
id: "E",
|
id: "E",
|
||||||
expectedWindow: []string{"C", "D", "B"},
|
expectedWindow: []string{"D", "C", "B"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"C", "D"},
|
parents: []string{"C", "D"},
|
||||||
id: "F",
|
id: "F",
|
||||||
expectedWindow: []string{"C", "D", "B"},
|
expectedWindow: []string{"D", "C", "B"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"A"},
|
parents: []string{"A"},
|
||||||
@ -60,37 +60,38 @@ func TestBlockWindow(t *testing.T) {
|
|||||||
{
|
{
|
||||||
parents: []string{"H", "F"},
|
parents: []string{"H", "F"},
|
||||||
id: "I",
|
id: "I",
|
||||||
expectedWindow: []string{"F", "H", "C", "D", "B", "G"},
|
expectedWindow: []string{"F", "D", "H", "C", "G", "B"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"I"},
|
parents: []string{"I"},
|
||||||
id: "J",
|
id: "J",
|
||||||
expectedWindow: []string{"I", "F", "H", "C", "D", "B", "G"},
|
expectedWindow: []string{"I", "F", "D", "H", "C", "G", "B"},
|
||||||
},
|
},
|
||||||
|
//
|
||||||
{
|
{
|
||||||
parents: []string{"J"},
|
parents: []string{"J"},
|
||||||
id: "K",
|
id: "K",
|
||||||
expectedWindow: []string{"J", "I", "F", "H", "C", "D", "B", "G"},
|
expectedWindow: []string{"J", "I", "F", "D", "H", "C", "G", "B"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"K"},
|
parents: []string{"K"},
|
||||||
id: "L",
|
id: "L",
|
||||||
expectedWindow: []string{"K", "J", "I", "F", "H", "C", "D", "B", "G"},
|
expectedWindow: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"L"},
|
parents: []string{"L"},
|
||||||
id: "M",
|
id: "M",
|
||||||
expectedWindow: []string{"L", "K", "J", "I", "F", "H", "C", "D", "B", "G"},
|
expectedWindow: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"M"},
|
parents: []string{"M"},
|
||||||
id: "N",
|
id: "N",
|
||||||
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "B"},
|
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"N"},
|
parents: []string{"N"},
|
||||||
id: "O",
|
id: "O",
|
||||||
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"},
|
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dagconfig.TestnetParams.Name: {
|
dagconfig.TestnetParams.Name: {
|
||||||
@ -132,37 +133,37 @@ func TestBlockWindow(t *testing.T) {
|
|||||||
{
|
{
|
||||||
parents: []string{"H", "F"},
|
parents: []string{"H", "F"},
|
||||||
id: "I",
|
id: "I",
|
||||||
expectedWindow: []string{"F", "H", "C", "D", "G", "B"},
|
expectedWindow: []string{"F", "C", "D", "H", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"I"},
|
parents: []string{"I"},
|
||||||
id: "J",
|
id: "J",
|
||||||
expectedWindow: []string{"I", "F", "H", "C", "D", "G", "B"},
|
expectedWindow: []string{"I", "F", "C", "D", "H", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"J"},
|
parents: []string{"J"},
|
||||||
id: "K",
|
id: "K",
|
||||||
expectedWindow: []string{"J", "I", "F", "H", "C", "D", "G", "B"},
|
expectedWindow: []string{"J", "I", "F", "C", "D", "H", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"K"},
|
parents: []string{"K"},
|
||||||
id: "L",
|
id: "L",
|
||||||
expectedWindow: []string{"K", "J", "I", "F", "H", "C", "D", "G", "B"},
|
expectedWindow: []string{"K", "J", "I", "F", "C", "D", "H", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"L"},
|
parents: []string{"L"},
|
||||||
id: "M",
|
id: "M",
|
||||||
expectedWindow: []string{"L", "K", "J", "I", "F", "H", "C", "D", "G", "B"},
|
expectedWindow: []string{"L", "K", "J", "I", "F", "C", "D", "H", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"M"},
|
parents: []string{"M"},
|
||||||
id: "N",
|
id: "N",
|
||||||
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "H", "C", "D", "G"},
|
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "C", "D", "H", "B"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"N"},
|
parents: []string{"N"},
|
||||||
id: "O",
|
id: "O",
|
||||||
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "H", "C", "D"},
|
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "C", "D", "H"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dagconfig.DevnetParams.Name: {
|
dagconfig.DevnetParams.Name: {
|
||||||
@ -204,37 +205,37 @@ func TestBlockWindow(t *testing.T) {
|
|||||||
{
|
{
|
||||||
parents: []string{"H", "F"},
|
parents: []string{"H", "F"},
|
||||||
id: "I",
|
id: "I",
|
||||||
expectedWindow: []string{"F", "D", "C", "H", "B", "G"},
|
expectedWindow: []string{"F", "D", "H", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"I"},
|
parents: []string{"I"},
|
||||||
id: "J",
|
id: "J",
|
||||||
expectedWindow: []string{"I", "F", "D", "C", "H", "B", "G"},
|
expectedWindow: []string{"I", "F", "D", "H", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"J"},
|
parents: []string{"J"},
|
||||||
id: "K",
|
id: "K",
|
||||||
expectedWindow: []string{"J", "I", "F", "D", "C", "H", "B", "G"},
|
expectedWindow: []string{"J", "I", "F", "D", "H", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"K"},
|
parents: []string{"K"},
|
||||||
id: "L",
|
id: "L",
|
||||||
expectedWindow: []string{"K", "J", "I", "F", "D", "C", "H", "B", "G"},
|
expectedWindow: []string{"K", "J", "I", "F", "D", "H", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"L"},
|
parents: []string{"L"},
|
||||||
id: "M",
|
id: "M",
|
||||||
expectedWindow: []string{"L", "K", "J", "I", "F", "D", "C", "H", "B", "G"},
|
expectedWindow: []string{"L", "K", "J", "I", "F", "D", "H", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"M"},
|
parents: []string{"M"},
|
||||||
id: "N",
|
id: "N",
|
||||||
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "D", "C", "H", "B"},
|
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "B"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"N"},
|
parents: []string{"N"},
|
||||||
id: "O",
|
id: "O",
|
||||||
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "D", "C", "H"},
|
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dagconfig.SimnetParams.Name: {
|
dagconfig.SimnetParams.Name: {
|
||||||
@ -276,37 +277,37 @@ func TestBlockWindow(t *testing.T) {
|
|||||||
{
|
{
|
||||||
parents: []string{"H", "F"},
|
parents: []string{"H", "F"},
|
||||||
id: "I",
|
id: "I",
|
||||||
expectedWindow: []string{"F", "D", "H", "C", "G", "B"},
|
expectedWindow: []string{"F", "H", "D", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"I"},
|
parents: []string{"I"},
|
||||||
id: "J",
|
id: "J",
|
||||||
expectedWindow: []string{"I", "F", "D", "H", "C", "G", "B"},
|
expectedWindow: []string{"I", "F", "H", "D", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"J"},
|
parents: []string{"J"},
|
||||||
id: "K",
|
id: "K",
|
||||||
expectedWindow: []string{"J", "I", "F", "D", "H", "C", "G", "B"},
|
expectedWindow: []string{"J", "I", "F", "H", "D", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"K"},
|
parents: []string{"K"},
|
||||||
id: "L",
|
id: "L",
|
||||||
expectedWindow: []string{"K", "J", "I", "F", "D", "H", "C", "G", "B"},
|
expectedWindow: []string{"K", "J", "I", "F", "H", "D", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"L"},
|
parents: []string{"L"},
|
||||||
id: "M",
|
id: "M",
|
||||||
expectedWindow: []string{"L", "K", "J", "I", "F", "D", "H", "C", "G", "B"},
|
expectedWindow: []string{"L", "K", "J", "I", "F", "H", "D", "C", "B", "G"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"M"},
|
parents: []string{"M"},
|
||||||
id: "N",
|
id: "N",
|
||||||
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "D", "H", "C", "G"},
|
expectedWindow: []string{"M", "L", "K", "J", "I", "F", "H", "D", "C", "B"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
parents: []string{"N"},
|
parents: []string{"N"},
|
||||||
id: "O",
|
id: "O",
|
||||||
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "D", "H", "C"},
|
expectedWindow: []string{"N", "M", "L", "K", "J", "I", "F", "H", "D", "C"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -105,10 +105,14 @@ func (dm *difficultyManager) requiredDifficultyFromTargetsWindow(targetsWindow b
|
|||||||
return dm.genesisBits, nil
|
return dm.genesisBits, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in the past this was < 2 as the comment explains, we changed it to under the window size to
|
||||||
|
// make the hashrate(which is ~1.5GH/s) constant in the first 2641 blocks so that we won't have a lot of tips
|
||||||
|
|
||||||
// We need at least 2 blocks to get a timestamp interval
|
// We need at least 2 blocks to get a timestamp interval
|
||||||
// We could instead clamp the timestamp difference to `targetTimePerBlock`,
|
// We could instead clamp the timestamp difference to `targetTimePerBlock`,
|
||||||
// but then everything will cancel out and we'll get the target from the last block, which will be the same as genesis.
|
// but then everything will cancel out and we'll get the target from the last block, which will be the same as genesis.
|
||||||
if len(targetsWindow) < 2 {
|
// We add 64 as a safety margin
|
||||||
|
if len(targetsWindow) < 2 || len(targetsWindow) < dm.difficultyAdjustmentWindowSize + 64 {
|
||||||
return dm.genesisBits, nil
|
return dm.genesisBits, nil
|
||||||
}
|
}
|
||||||
windowMinTimestamp, windowMaxTimeStamp, windowsMinIndex, _ := targetsWindow.minMaxTimestamps()
|
windowMinTimestamp, windowMaxTimeStamp, windowsMinIndex, _ := targetsWindow.minMaxTimestamps()
|
||||||
@ -157,7 +161,11 @@ func (dm *difficultyManager) calculateDaaScoreAndAddedBlocks(stagingArea *model.
|
|||||||
isBlockWithTrustedData bool) (uint64, []*externalapi.DomainHash, error) {
|
isBlockWithTrustedData bool) (uint64, []*externalapi.DomainHash, error) {
|
||||||
|
|
||||||
if blockHash.Equal(dm.genesisHash) {
|
if blockHash.Equal(dm.genesisHash) {
|
||||||
return 0, nil, nil
|
genesisHeader, err := dm.headerStore.BlockHeader(dm.databaseContext, stagingArea, dm.genesisHash)
|
||||||
|
if err != nil {
|
||||||
|
return 0, nil, err
|
||||||
|
}
|
||||||
|
return genesisHeader.DAAScore(), nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ghostdagData, err := dm.ghostdagStore.Get(dm.databaseContext, stagingArea, blockHash, false)
|
ghostdagData, err := dm.ghostdagStore.Get(dm.databaseContext, stagingArea, blockHash, false)
|
||||||
|
@ -19,12 +19,6 @@ import (
|
|||||||
|
|
||||||
func TestDifficulty(t *testing.T) {
|
func TestDifficulty(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
// Mainnet's genesis is too new, so if we'll build on it we'll get to the future very quickly.
|
|
||||||
// TODO: Once it gets older, we should unskip this test.
|
|
||||||
if consensusConfig.Name == "kaspa-mainnet" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if consensusConfig.DisableDifficultyAdjustment {
|
if consensusConfig.DisableDifficultyAdjustment {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -37,7 +31,7 @@ func TestDifficulty(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
consensusConfig.K = 1
|
consensusConfig.K = 1
|
||||||
consensusConfig.DifficultyAdjustmentWindowSize = 265
|
consensusConfig.DifficultyAdjustmentWindowSize = 140
|
||||||
|
|
||||||
factory := consensus.NewFactory()
|
factory := consensus.NewFactory()
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestDifficulty")
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestDifficulty")
|
||||||
@ -114,7 +108,7 @@ func TestDifficulty(t *testing.T) {
|
|||||||
"window size, the difficulty should be the same as genesis'")
|
"window size, the difficulty should be the same as genesis'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < consensusConfig.DifficultyAdjustmentWindowSize+100; i++ {
|
for i := 0; i < consensusConfig.DifficultyAdjustmentWindowSize+10; i++ {
|
||||||
tip, tipHash = addBlock(0, tipHash)
|
tip, tipHash = addBlock(0, tipHash)
|
||||||
if tip.Header.Bits() != consensusConfig.GenesisBlock.Header.Bits() {
|
if tip.Header.Bits() != consensusConfig.GenesisBlock.Header.Bits() {
|
||||||
t.Fatalf("As long as the block rate remains the same, the difficulty shouldn't change")
|
t.Fatalf("As long as the block rate remains the same, the difficulty shouldn't change")
|
||||||
@ -136,9 +130,9 @@ func TestDifficulty(t *testing.T) {
|
|||||||
var expectedBits uint32
|
var expectedBits uint32
|
||||||
switch consensusConfig.Name {
|
switch consensusConfig.Name {
|
||||||
case dagconfig.TestnetParams.Name, dagconfig.DevnetParams.Name:
|
case dagconfig.TestnetParams.Name, dagconfig.DevnetParams.Name:
|
||||||
expectedBits = uint32(0x1e7f83df)
|
expectedBits = uint32(0x1e7f1441)
|
||||||
case dagconfig.MainnetParams.Name:
|
case dagconfig.MainnetParams.Name:
|
||||||
expectedBits = uint32(0x1e7f83df)
|
expectedBits = uint32(0x1d02c50f)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tip.Header.Bits() != expectedBits {
|
if tip.Header.Bits() != expectedBits {
|
||||||
@ -237,7 +231,7 @@ func TestDifficulty(t *testing.T) {
|
|||||||
|
|
||||||
func TestDAAScore(t *testing.T) {
|
func TestDAAScore(t *testing.T) {
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
consensusConfig.DifficultyAdjustmentWindowSize = 265
|
consensusConfig.DifficultyAdjustmentWindowSize = 86
|
||||||
|
|
||||||
stagingArea := model.NewStagingArea()
|
stagingArea := model.NewStagingArea()
|
||||||
|
|
||||||
@ -269,9 +263,9 @@ func TestDAAScore(t *testing.T) {
|
|||||||
t.Fatalf("DAAScore: %+v", err)
|
t.Fatalf("DAAScore: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
blockBlueScore3ExpectedDAAScore := uint64(2)
|
blockBlueScore3ExpectedDAAScore := uint64(2) + consensusConfig.GenesisBlock.Header.DAAScore()
|
||||||
if blockBlueScore3DAAScore != blockBlueScore3ExpectedDAAScore {
|
if blockBlueScore3DAAScore != blockBlueScore3ExpectedDAAScore {
|
||||||
t.Fatalf("DAA score is expected to be %d but got %d", blockBlueScore3ExpectedDAAScore, blockBlueScore3ExpectedDAAScore)
|
t.Fatalf("DAA score is expected to be %d but got %d", blockBlueScore3ExpectedDAAScore, blockBlueScore3DAAScore)
|
||||||
}
|
}
|
||||||
tipDAAScore := blockBlueScore3ExpectedDAAScore
|
tipDAAScore := blockBlueScore3ExpectedDAAScore
|
||||||
|
|
||||||
|
@ -7,15 +7,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type parentsManager struct {
|
type parentsManager struct {
|
||||||
hardForkOmitGenesisFromParentsDAAScore uint64
|
genesisHash *externalapi.DomainHash
|
||||||
genesisHash *externalapi.DomainHash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New instantiates a new ParentsManager
|
// New instantiates a new ParentsManager
|
||||||
func New(genesisHash *externalapi.DomainHash, hardForkOmitGenesisFromParentsDAAScore uint64) model.ParentsManager {
|
func New(genesisHash *externalapi.DomainHash) model.ParentsManager {
|
||||||
return &parentsManager{
|
return &parentsManager{
|
||||||
genesisHash: genesisHash,
|
genesisHash: genesisHash,
|
||||||
hardForkOmitGenesisFromParentsDAAScore: hardForkOmitGenesisFromParentsDAAScore,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +23,7 @@ func (pm *parentsManager) ParentsAtLevel(blockHeader externalapi.BlockHeader, le
|
|||||||
parentsAtLevel = blockHeader.Parents()[level]
|
parentsAtLevel = blockHeader.Parents()[level]
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(parentsAtLevel) == 0 && len(blockHeader.DirectParents()) > 0 && blockHeader.DAAScore() >= pm.hardForkOmitGenesisFromParentsDAAScore {
|
if len(parentsAtLevel) == 0 && len(blockHeader.DirectParents()) > 0 {
|
||||||
return externalapi.BlockLevelParents{pm.genesisHash}
|
return externalapi.BlockLevelParents{pm.genesisHash}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,11 +31,7 @@ func (pm *parentsManager) ParentsAtLevel(blockHeader externalapi.BlockHeader, le
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pm *parentsManager) Parents(blockHeader externalapi.BlockHeader) []externalapi.BlockLevelParents {
|
func (pm *parentsManager) Parents(blockHeader externalapi.BlockHeader) []externalapi.BlockLevelParents {
|
||||||
numParents := len(blockHeader.Parents())
|
numParents := constants.MaxBlockLevel + 1
|
||||||
if blockHeader.DAAScore() >= pm.hardForkOmitGenesisFromParentsDAAScore {
|
|
||||||
numParents = constants.MaxBlockLevel + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
parents := make([]externalapi.BlockLevelParents, numParents)
|
parents := make([]externalapi.BlockLevelParents, numParents)
|
||||||
for i := 0; i < numParents; i++ {
|
for i := 0; i < numParents; i++ {
|
||||||
parents[i] = pm.ParentsAtLevel(blockHeader, i)
|
parents[i] = pm.ParentsAtLevel(blockHeader, i)
|
||||||
|
@ -36,14 +36,16 @@ func TestPruning(t *testing.T) {
|
|||||||
dagconfig.SimnetParams.Name: "1582",
|
dagconfig.SimnetParams.Name: "1582",
|
||||||
},
|
},
|
||||||
"dag-for-test-pruning.json": {
|
"dag-for-test-pruning.json": {
|
||||||
dagconfig.MainnetParams.Name: "502",
|
dagconfig.MainnetParams.Name: "503",
|
||||||
dagconfig.TestnetParams.Name: "502",
|
dagconfig.TestnetParams.Name: "502",
|
||||||
dagconfig.DevnetParams.Name: "502",
|
dagconfig.DevnetParams.Name: "502",
|
||||||
dagconfig.SimnetParams.Name: "503",
|
dagconfig.SimnetParams.Name: "502",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
testutils.ForAllNets(t, true, func(t *testing.T, consensusConfig *consensus.Config) {
|
||||||
|
// Improve the performance of the test a little
|
||||||
|
consensusConfig.DisableDifficultyAdjustment = true
|
||||||
err := filepath.Walk("./testdata", func(path string, info os.FileInfo, err error) error {
|
err := filepath.Walk("./testdata", func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -71,6 +73,7 @@ func TestPruning(t *testing.T) {
|
|||||||
consensusConfig.DifficultyAdjustmentWindowSize = 400
|
consensusConfig.DifficultyAdjustmentWindowSize = 400
|
||||||
|
|
||||||
factory := consensus.NewFactory()
|
factory := consensus.NewFactory()
|
||||||
|
factory.SetTestLevelDBCacheSize(128)
|
||||||
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestPruning")
|
tc, teardown, err := factory.NewTestConsensus(consensusConfig, "TestPruning")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error setting up consensus: %+v", err)
|
t.Fatalf("Error setting up consensus: %+v", err)
|
||||||
|
@ -675,7 +675,19 @@ func (pm *pruningManager) calculateDiffBetweenPreviousAndCurrentPruningPoints(st
|
|||||||
onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.calculateDiffBetweenPreviousAndCurrentPruningPoints")
|
onEnd := logger.LogAndMeasureExecutionTime(log, "pruningManager.calculateDiffBetweenPreviousAndCurrentPruningPoints")
|
||||||
defer onEnd()
|
defer onEnd()
|
||||||
if currentPruningHash.Equal(pm.genesisHash) {
|
if currentPruningHash.Equal(pm.genesisHash) {
|
||||||
return utxo.NewUTXODiff(), nil
|
iter, err := pm.consensusStateManager.RestorePastUTXOSetIterator(stagingArea, currentPruningHash)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
set := make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry)
|
||||||
|
for ok := iter.First(); ok; ok = iter.Next() {
|
||||||
|
outpoint, entry, err := iter.Get()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
set[*outpoint] = entry
|
||||||
|
}
|
||||||
|
return utxo.NewUTXODiffFromCollections(utxo.NewUTXOCollection(set), utxo.NewUTXOCollection(make(map[externalapi.DomainOutpoint]externalapi.UTXOEntry)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pruningPointIndex, err := pm.pruningStore.CurrentPruningPointIndex(pm.databaseContext, stagingArea)
|
pruningPointIndex, err := pm.pruningStore.CurrentPruningPointIndex(pm.databaseContext, stagingArea)
|
||||||
|
@ -49,7 +49,7 @@ func TestCheckLockTimeVerifyConditionedByDAAScore(t *testing.T) {
|
|||||||
}
|
}
|
||||||
fees := uint64(1)
|
fees := uint64(1)
|
||||||
//Create a CLTV script:
|
//Create a CLTV script:
|
||||||
targetDAAScore := uint64(30)
|
targetDAAScore := consensusConfig.GenesisBlock.Header.DAAScore() + uint64(30)
|
||||||
redeemScriptCLTV, err := createScriptCLTV(targetDAAScore)
|
redeemScriptCLTV, err := createScriptCLTV(targetDAAScore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create a script using createScriptCLTV: %v", err)
|
t.Fatalf("Failed to create a script using createScriptCLTV: %v", err)
|
||||||
@ -156,7 +156,7 @@ func TestCheckLockTimeVerifyConditionedByDAAScoreWithWrongLockTime(t *testing.T)
|
|||||||
}
|
}
|
||||||
fees := uint64(1)
|
fees := uint64(1)
|
||||||
//Create a CLTV script:
|
//Create a CLTV script:
|
||||||
targetDAAScore := uint64(30)
|
targetDAAScore := consensusConfig.GenesisBlock.Header.DAAScore() + uint64(30)
|
||||||
redeemScriptCLTV, err := createScriptCLTV(targetDAAScore)
|
redeemScriptCLTV, err := createScriptCLTV(targetDAAScore)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create a script using createScriptCLTV: %v", err)
|
t.Fatalf("Failed to create a script using createScriptCLTV: %v", err)
|
||||||
|
@ -37,5 +37,7 @@ const (
|
|||||||
LockTimeThreshold = 5e11 // Tue Nov 5 00:53:20 1985 UTC
|
LockTimeThreshold = 5e11 // Tue Nov 5 00:53:20 1985 UTC
|
||||||
|
|
||||||
// MaxBlockLevel is the maximum possible block level.
|
// MaxBlockLevel is the maximum possible block level.
|
||||||
MaxBlockLevel = 255
|
// This is technically 255, but we clamped it at 256 - block level of mainnet genesis
|
||||||
|
// This means that any block that has a level lower or equal to genesis will be level 0.
|
||||||
|
MaxBlockLevel = 225
|
||||||
)
|
)
|
||||||
|
@ -104,9 +104,10 @@ func BlockLevel(header externalapi.BlockHeader) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proofOfWorkValue := NewState(header.ToMutable()).CalculateProofOfWorkValue()
|
proofOfWorkValue := NewState(header.ToMutable()).CalculateProofOfWorkValue()
|
||||||
for blockLevel := 0; ; blockLevel++ {
|
level := constants.MaxBlockLevel - proofOfWorkValue.BitLen()
|
||||||
if blockLevel == constants.MaxBlockLevel || proofOfWorkValue.Bit(blockLevel+1) != 0 {
|
// If the block has a level lower than genesis make it zero.
|
||||||
return blockLevel
|
if level < 0 {
|
||||||
}
|
level = 0
|
||||||
}
|
}
|
||||||
|
return level
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ import (
|
|||||||
//
|
//
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultMaxCoinbasePayloadLength = 172
|
defaultMaxCoinbasePayloadLength = 204
|
||||||
// defaultMaxBlockMass is a bound on the mass of a block, larger values increase the bound d
|
// defaultMaxBlockMass is a bound on the mass of a block, larger values increase the bound d
|
||||||
// on the round trip time of a block, which affects the other parameters as described below
|
// on the round trip time of a block, which affects the other parameters as described below
|
||||||
defaultMaxBlockMass = 500_000
|
defaultMaxBlockMass = 500_000
|
||||||
@ -49,7 +49,7 @@ const (
|
|||||||
defaultMergeSetSizeLimit = defaultGHOSTDAGK * 10
|
defaultMergeSetSizeLimit = defaultGHOSTDAGK * 10
|
||||||
defaultSubsidyGenesisReward = 1 * constants.SompiPerKaspa
|
defaultSubsidyGenesisReward = 1 * constants.SompiPerKaspa
|
||||||
defaultMinSubsidy = 1 * constants.SompiPerKaspa
|
defaultMinSubsidy = 1 * constants.SompiPerKaspa
|
||||||
defaultMaxSubsidy = 1000 * constants.SompiPerKaspa
|
defaultMaxSubsidy = 500 * constants.SompiPerKaspa
|
||||||
defaultBaseSubsidy = 50 * constants.SompiPerKaspa
|
defaultBaseSubsidy = 50 * constants.SompiPerKaspa
|
||||||
defaultFixedSubsidySwitchPruningPointInterval uint64 = 7
|
defaultFixedSubsidySwitchPruningPointInterval uint64 = 7
|
||||||
defaultCoinbasePayloadScriptPublicKeyMaxLength = 150
|
defaultCoinbasePayloadScriptPublicKeyMaxLength = 150
|
||||||
|
@ -36,10 +36,14 @@ var genesisTxPayload = []byte{
|
|||||||
0x20, 0xd7, 0x90, 0xd7, 0x9c, 0xd7, 0x94, 0xd7,
|
0x20, 0xd7, 0x90, 0xd7, 0x9c, 0xd7, 0x94, 0xd7,
|
||||||
0x9b, 0xd7, 0x9d, 0x20, 0xd7, 0xaa, 0xd7, 0xa2,
|
0x9b, 0xd7, 0x9d, 0x20, 0xd7, 0xaa, 0xd7, 0xa2,
|
||||||
0xd7, 0x91, 0xd7, 0x93, 0xd7, 0x95, 0xd7, 0x9f,
|
0xd7, 0x91, 0xd7, 0x93, 0xd7, 0x95, 0xd7, 0x9f,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Bitcoin block hash 00000000000000000001733c62adb19f1b77fa0735d0e11f25af36fc9ca908a5
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Bitcoin block hash 0000000000000000000b1f8e1c17b0133d439174e52efbb0c41c3583a8aa66b0
|
||||||
0x00, 0x01, 0x73, 0x3c, 0x62, 0xad, 0xb1, 0x9f,
|
0x00, 0x0b, 0x1f, 0x8e, 0x1c, 0x17, 0xb0, 0x13,
|
||||||
0x1b, 0x77, 0xfa, 0x07, 0x35, 0xd0, 0xe1, 0x1f,
|
0x3d, 0x43, 0x91, 0x74 ,0xe5, 0x2e, 0xfb, 0xb0,
|
||||||
0x25, 0xaf, 0x36, 0xfc, 0x9c, 0xa9, 0x08, 0xa5,
|
0xc4, 0x1c, 0x35, 0x83, 0xa8, 0xaa, 0x66, 0xb0,
|
||||||
|
0x0f, 0xca, 0x37, 0xca, 0x66, 0x7c, 0x2d, 0x55, // Checkpoint block hash 0fca37ca667c2d550a6c4416dad9717e50927128c424fa4edbebc436ab13aeef
|
||||||
|
0x0a, 0x6c, 0x44, 0x16, 0xda, 0xd9, 0x71, 0x7e,
|
||||||
|
0x50, 0x92, 0x71, 0x28, 0xc4, 0x24, 0xfa, 0x4e,
|
||||||
|
0xdb, 0xeb, 0xc4, 0x36, 0xab, 0x13, 0xae, 0xef,
|
||||||
}
|
}
|
||||||
|
|
||||||
// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for
|
// genesisCoinbaseTx is the coinbase transaction for the genesis blocks for
|
||||||
@ -50,19 +54,13 @@ var genesisCoinbaseTx = transactionhelper.NewSubnetworkTransaction(0, []*externa
|
|||||||
// genesisHash is the hash of the first block in the block DAG for the main
|
// genesisHash is the hash of the first block in the block DAG for the main
|
||||||
// network (genesis block).
|
// network (genesis block).
|
||||||
var genesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
|
var genesisHash = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||||
0xca, 0xeb, 0x97, 0x96, 0x0a, 0x16, 0x0c, 0x21,
|
0x58, 0xc2, 0xd4, 0x19, 0x9e, 0x21, 0xf9, 0x10, 0xd1, 0x57, 0x1d, 0x11, 0x49, 0x69, 0xce, 0xce, 0xf4, 0x8f, 0x9, 0xf9, 0x34, 0xd4, 0x2c, 0xcb, 0x6a, 0x28, 0x1a, 0x15, 0x86, 0x8f, 0x29, 0x99,
|
||||||
0x1a, 0x6b, 0x21, 0x96, 0xbd, 0x78, 0x39, 0x9f,
|
|
||||||
0xd4, 0xc4, 0xcc, 0x5b, 0x50, 0x9f, 0x55, 0xc1,
|
|
||||||
0x2c, 0x8a, 0x7d, 0x81, 0x5f, 0x75, 0x36, 0xea,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// genesisMerkleRoot is the hash of the first transaction in the genesis block
|
// genesisMerkleRoot is the hash of the first transaction in the genesis block
|
||||||
// for the main network.
|
// for the main network.
|
||||||
var genesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
|
var genesisMerkleRoot = externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||||
0xca, 0xed, 0xaf, 0x7d, 0x4a, 0x08, 0xbb, 0xe8,
|
0x8e, 0xc8, 0x98, 0x56, 0x8c, 0x68, 0x1, 0xd1, 0x3d, 0xf4, 0xee, 0x6e, 0x2a, 0x1b, 0x54, 0xb7, 0xe6, 0x23, 0x6f, 0x67, 0x1f, 0x20, 0x95, 0x4f, 0x5, 0x30, 0x64, 0x10, 0x51, 0x8e, 0xeb, 0x32,
|
||||||
0x90, 0x11, 0x64, 0x0c, 0x48, 0x41, 0xb6, 0x6d,
|
|
||||||
0x5b, 0xba, 0x67, 0xd7, 0x28, 0x8c, 0xe6, 0xd6,
|
|
||||||
0x72, 0x28, 0xdb, 0x00, 0x09, 0x66, 0xe9, 0x74,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// genesisBlock defines the genesis block of the block DAG which serves as the
|
// genesisBlock defines the genesis block of the block DAG which serves as the
|
||||||
@ -73,11 +71,13 @@ var genesisBlock = externalapi.DomainBlock{
|
|||||||
[]externalapi.BlockLevelParents{},
|
[]externalapi.BlockLevelParents{},
|
||||||
genesisMerkleRoot,
|
genesisMerkleRoot,
|
||||||
&externalapi.DomainHash{},
|
&externalapi.DomainHash{},
|
||||||
externalapi.NewDomainHashFromByteArray(muhash.EmptyMuHashHash.AsArray()),
|
externalapi.NewDomainHashFromByteArray(&[externalapi.DomainHashSize]byte{
|
||||||
0x17cfb020c02,
|
0x71, 0x0f, 0x27, 0xdf, 0x42, 0x3e, 0x63, 0xaa, 0x6c, 0xdb, 0x72, 0xb8, 0x9e, 0xa5, 0xa0, 0x6c, 0xff, 0xa3, 0x99, 0xd6, 0x6f, 0x16, 0x77, 0x04, 0x45, 0x5b, 0x5a, 0xf5, 0x9d, 0xef, 0x8e, 0x20,
|
||||||
0x1e7fffff,
|
}),
|
||||||
|
1637609671037,
|
||||||
|
486722099,
|
||||||
0x3392c,
|
0x3392c,
|
||||||
0,
|
1312860, // Checkpoint DAA score
|
||||||
0,
|
0,
|
||||||
big.NewInt(0),
|
big.NewInt(0),
|
||||||
&externalapi.DomainHash{},
|
&externalapi.DomainHash{},
|
||||||
|
@ -186,8 +186,6 @@ type Params struct {
|
|||||||
FixedSubsidySwitchPruningPointInterval uint64
|
FixedSubsidySwitchPruningPointInterval uint64
|
||||||
|
|
||||||
FixedSubsidySwitchHashRateThreshold *big.Int
|
FixedSubsidySwitchHashRateThreshold *big.Int
|
||||||
|
|
||||||
HardForkOmitGenesisFromParentsDAAScore uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NormalizeRPCServerAddress returns addr with the current network default
|
// NormalizeRPCServerAddress returns addr with the current network default
|
||||||
@ -213,7 +211,15 @@ var MainnetParams = Params{
|
|||||||
Net: appmessage.Mainnet,
|
Net: appmessage.Mainnet,
|
||||||
RPCPort: "16110",
|
RPCPort: "16110",
|
||||||
DefaultPort: "16111",
|
DefaultPort: "16111",
|
||||||
DNSSeeds: []string{"mainnet-dnsseed.daglabs-dev.com"},
|
DNSSeeds: []string{
|
||||||
|
"mainnet-dnsseed.daglabs-dev.com",
|
||||||
|
// This DNS seeder is run by Denis Mashkevich
|
||||||
|
"mainnet-dnsseed-1.kaspanet.org",
|
||||||
|
// This DNS seeder is run by Denis Mashkevich
|
||||||
|
"mainnet-dnsseed-2.kaspanet.org",
|
||||||
|
// This DNS seeder is run by Elichai Turkel
|
||||||
|
"kaspa.turkel.in",
|
||||||
|
},
|
||||||
|
|
||||||
// DAG parameters
|
// DAG parameters
|
||||||
GenesisBlock: &genesisBlock,
|
GenesisBlock: &genesisBlock,
|
||||||
@ -266,7 +272,6 @@ var MainnetParams = Params{
|
|||||||
PruningProofM: defaultPruningProofM,
|
PruningProofM: defaultPruningProofM,
|
||||||
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
|
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
|
||||||
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
|
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
|
||||||
HardForkOmitGenesisFromParentsDAAScore: 1320000,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestnetParams defines the network parameters for the test Kaspa network.
|
// TestnetParams defines the network parameters for the test Kaspa network.
|
||||||
@ -329,7 +334,6 @@ var TestnetParams = Params{
|
|||||||
PruningProofM: defaultPruningProofM,
|
PruningProofM: defaultPruningProofM,
|
||||||
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
|
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
|
||||||
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
|
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
|
||||||
HardForkOmitGenesisFromParentsDAAScore: 2e6,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimnetParams defines the network parameters for the simulation test Kaspa
|
// SimnetParams defines the network parameters for the simulation test Kaspa
|
||||||
@ -396,7 +400,6 @@ var SimnetParams = Params{
|
|||||||
PruningProofM: defaultPruningProofM,
|
PruningProofM: defaultPruningProofM,
|
||||||
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
|
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
|
||||||
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
|
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
|
||||||
HardForkOmitGenesisFromParentsDAAScore: 5,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DevnetParams defines the network parameters for the development Kaspa network.
|
// DevnetParams defines the network parameters for the development Kaspa network.
|
||||||
@ -459,7 +462,6 @@ var DevnetParams = Params{
|
|||||||
PruningProofM: defaultPruningProofM,
|
PruningProofM: defaultPruningProofM,
|
||||||
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
|
FixedSubsidySwitchPruningPointInterval: defaultFixedSubsidySwitchPruningPointInterval,
|
||||||
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
|
FixedSubsidySwitchHashRateThreshold: big.NewInt(150_000_000_000),
|
||||||
HardForkOmitGenesisFromParentsDAAScore: 3000,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -40,7 +40,7 @@ func TestValidateAndInsertTransaction(t *testing.T) {
|
|||||||
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||||
transactionsToInsert := make([]*externalapi.DomainTransaction, 10)
|
transactionsToInsert := make([]*externalapi.DomainTransaction, 10)
|
||||||
for i := range transactionsToInsert {
|
for i := range transactionsToInsert {
|
||||||
transactionsToInsert[i] = createTransactionWithUTXOEntry(t, i)
|
transactionsToInsert[i] = createTransactionWithUTXOEntry(t, i, 0)
|
||||||
_, err = miningManager.ValidateAndInsertTransaction(transactionsToInsert[i], false, true)
|
_, err = miningManager.ValidateAndInsertTransaction(transactionsToInsert[i], false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||||
@ -89,7 +89,7 @@ func TestImmatureSpend(t *testing.T) {
|
|||||||
tcAsConsensusPointer := &tcAsConsensus
|
tcAsConsensusPointer := &tcAsConsensus
|
||||||
consensusReference := consensusreference.NewConsensusReference(&tcAsConsensusPointer)
|
consensusReference := consensusreference.NewConsensusReference(&tcAsConsensusPointer)
|
||||||
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||||
tx := createTransactionWithUTXOEntry(t, 0)
|
tx := createTransactionWithUTXOEntry(t, 0, consensusConfig.GenesisBlock.Header.DAAScore())
|
||||||
_, err = miningManager.ValidateAndInsertTransaction(tx, false, false)
|
_, err = miningManager.ValidateAndInsertTransaction(tx, false, false)
|
||||||
txRuleError := &mempool.TxRuleError{}
|
txRuleError := &mempool.TxRuleError{}
|
||||||
if !errors.As(err, txRuleError) || txRuleError.RejectCode != mempool.RejectImmatureSpend {
|
if !errors.As(err, txRuleError) || txRuleError.RejectCode != mempool.RejectImmatureSpend {
|
||||||
@ -119,7 +119,7 @@ func TestInsertDoubleTransactionsToMempool(t *testing.T) {
|
|||||||
tcAsConsensusPointer := &tcAsConsensus
|
tcAsConsensusPointer := &tcAsConsensus
|
||||||
consensusReference := consensusreference.NewConsensusReference(&tcAsConsensusPointer)
|
consensusReference := consensusreference.NewConsensusReference(&tcAsConsensusPointer)
|
||||||
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||||
transaction := createTransactionWithUTXOEntry(t, 0)
|
transaction := createTransactionWithUTXOEntry(t, 0, 0)
|
||||||
_, err = miningManager.ValidateAndInsertTransaction(transaction, false, true)
|
_, err = miningManager.ValidateAndInsertTransaction(transaction, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||||
@ -186,7 +186,7 @@ func TestHandleNewBlockTransactions(t *testing.T) {
|
|||||||
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||||
transactionsToInsert := make([]*externalapi.DomainTransaction, 10)
|
transactionsToInsert := make([]*externalapi.DomainTransaction, 10)
|
||||||
for i := range transactionsToInsert {
|
for i := range transactionsToInsert {
|
||||||
transaction := createTransactionWithUTXOEntry(t, i)
|
transaction := createTransactionWithUTXOEntry(t, i, 0)
|
||||||
transactionsToInsert[i] = transaction
|
transactionsToInsert[i] = transaction
|
||||||
_, err = miningManager.ValidateAndInsertTransaction(transaction, false, true)
|
_, err = miningManager.ValidateAndInsertTransaction(transaction, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -253,12 +253,12 @@ func TestDoubleSpendWithBlock(t *testing.T) {
|
|||||||
tcAsConsensusPointer := &tcAsConsensus
|
tcAsConsensusPointer := &tcAsConsensus
|
||||||
consensusReference := consensusreference.NewConsensusReference(&tcAsConsensusPointer)
|
consensusReference := consensusreference.NewConsensusReference(&tcAsConsensusPointer)
|
||||||
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
miningManager := miningFactory.NewMiningManager(consensusReference, &consensusConfig.Params, mempool.DefaultConfig(&consensusConfig.Params))
|
||||||
transactionInTheMempool := createTransactionWithUTXOEntry(t, 0)
|
transactionInTheMempool := createTransactionWithUTXOEntry(t, 0, 0)
|
||||||
_, err = miningManager.ValidateAndInsertTransaction(transactionInTheMempool, false, true)
|
_, err = miningManager.ValidateAndInsertTransaction(transactionInTheMempool, false, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
t.Fatalf("ValidateAndInsertTransaction: %v", err)
|
||||||
}
|
}
|
||||||
doubleSpendTransactionInTheBlock := createTransactionWithUTXOEntry(t, 0)
|
doubleSpendTransactionInTheBlock := createTransactionWithUTXOEntry(t, 0, 0)
|
||||||
doubleSpendTransactionInTheBlock.Inputs[0].PreviousOutpoint = transactionInTheMempool.Inputs[0].PreviousOutpoint
|
doubleSpendTransactionInTheBlock.Inputs[0].PreviousOutpoint = transactionInTheMempool.Inputs[0].PreviousOutpoint
|
||||||
blockTransactions := []*externalapi.DomainTransaction{nil, doubleSpendTransactionInTheBlock}
|
blockTransactions := []*externalapi.DomainTransaction{nil, doubleSpendTransactionInTheBlock}
|
||||||
_, err = miningManager.HandleNewBlockTransactions(blockTransactions)
|
_, err = miningManager.HandleNewBlockTransactions(blockTransactions)
|
||||||
@ -571,7 +571,7 @@ func TestRevalidateHighPriorityTransactions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func createTransactionWithUTXOEntry(t *testing.T, i int) *externalapi.DomainTransaction {
|
func createTransactionWithUTXOEntry(t *testing.T, i int, daaScore uint64) *externalapi.DomainTransaction {
|
||||||
prevOutTxID := externalapi.DomainTransactionID{}
|
prevOutTxID := externalapi.DomainTransactionID{}
|
||||||
prevOutPoint := externalapi.DomainOutpoint{TransactionID: prevOutTxID, Index: uint32(i)}
|
prevOutPoint := externalapi.DomainOutpoint{TransactionID: prevOutTxID, Index: uint32(i)}
|
||||||
scriptPublicKey, redeemScript := testutils.OpTrueScript()
|
scriptPublicKey, redeemScript := testutils.OpTrueScript()
|
||||||
@ -587,7 +587,7 @@ func createTransactionWithUTXOEntry(t *testing.T, i int) *externalapi.DomainTran
|
|||||||
100000000, // 1 KAS
|
100000000, // 1 KAS
|
||||||
scriptPublicKey,
|
scriptPublicKey,
|
||||||
true,
|
true,
|
||||||
uint64(0)),
|
daaScore),
|
||||||
}
|
}
|
||||||
txOut := externalapi.DomainTransactionOutput{
|
txOut := externalapi.DomainTransactionOutput{
|
||||||
Value: 10000,
|
Value: 10000,
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
defaultConfigFilename = "kaspad.conf"
|
defaultConfigFilename = "kaspad.conf"
|
||||||
defaultDataDirname = "data"
|
|
||||||
defaultLogLevel = "info"
|
defaultLogLevel = "info"
|
||||||
defaultLogDirname = "logs"
|
defaultLogDirname = "logs"
|
||||||
defaultLogFilename = "kaspad.log"
|
defaultLogFilename = "kaspad.log"
|
||||||
@ -86,7 +85,7 @@ type Flags struct {
|
|||||||
Listeners []string `long:"listen" description:"Add an interface/port to listen for connections (default all interfaces port: 16111, testnet: 16211)"`
|
Listeners []string `long:"listen" description:"Add an interface/port to listen for connections (default all interfaces port: 16111, testnet: 16211)"`
|
||||||
TargetOutboundPeers int `long:"outpeers" description:"Target number of outbound peers"`
|
TargetOutboundPeers int `long:"outpeers" description:"Target number of outbound peers"`
|
||||||
MaxInboundPeers int `long:"maxinpeers" description:"Max number of inbound peers"`
|
MaxInboundPeers int `long:"maxinpeers" description:"Max number of inbound peers"`
|
||||||
DisableBanning bool `long:"nobanning" description:"Disable banning of misbehaving peers"`
|
EnableBanning bool `long:"enablebanning" description:"Enable banning of misbehaving peers"`
|
||||||
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
|
BanDuration time.Duration `long:"banduration" description:"How long to ban misbehaving peers. Valid time units are {s, m, h}. Minimum 1 second"`
|
||||||
BanThreshold uint32 `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."`
|
BanThreshold uint32 `long:"banthreshold" description:"Maximum allowed ban score before disconnecting and banning misbehaving peers."`
|
||||||
Whitelists []string `long:"whitelist" description:"Add an IP network or IP that will not be banned. (eg. 192.168.1.0/24 or ::1)"`
|
Whitelists []string `long:"whitelist" description:"Add an IP network or IP that will not be banned. (eg. 192.168.1.0/24 or ::1)"`
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
|
|
||||||
func TestGetHashrateString(t *testing.T) {
|
func TestGetHashrateString(t *testing.T) {
|
||||||
var results = map[string]string{
|
var results = map[string]string{
|
||||||
dagconfig.MainnetParams.Name: "131.07 KH/s",
|
dagconfig.MainnetParams.Name: "1.53 GH/s",
|
||||||
dagconfig.TestnetParams.Name: "131.07 KH/s",
|
dagconfig.TestnetParams.Name: "131.07 KH/s",
|
||||||
dagconfig.DevnetParams.Name: "131.07 KH/s",
|
dagconfig.DevnetParams.Name: "131.07 KH/s",
|
||||||
dagconfig.SimnetParams.Name: "2.00 KH/s",
|
dagconfig.SimnetParams.Name: "2.00 KH/s",
|
||||||
|
@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
|
|||||||
const (
|
const (
|
||||||
appMajor uint = 0
|
appMajor uint = 0
|
||||||
appMinor uint = 11
|
appMinor uint = 11
|
||||||
appPatch uint = 4
|
appPatch uint = 5
|
||||||
)
|
)
|
||||||
|
|
||||||
// appBuild is defined as a variable so it can be overridden during the build
|
// appBuild is defined as a variable so it can be overridden during the build
|
||||||
|
Loading…
x
Reference in New Issue
Block a user